remove
명령을 사용하여 전체 데이터 집합을 삭제할 수 있습니다. 최근 인터넷에서 공개 실행 중인 보안되지 않은 MongoDB 인스턴스에 대한 악성 공격에 대한 보고가 있었습니다. 공격자는 데이터베이스를 지운 후 피해자에게 데이터베이스 복원을 위한 보상금을 지불할 것을 요구했습니다.remove
명령을 사용하여 전체 데이터 집합을 삭제할 수 있습니다. 최근 인터넷에서 공개 실행 중인 보안되지 않은 MongoDB 인스턴스에 대한 악성 공격에 대한 보고가 있었습니다. 공격자는 데이터베이스를 지운 후 피해자에게 데이터베이스 복원을 위한 보상금을 지불할 것을 요구했습니다.FLUSHALL
명령을 사용하여 전체 데이터 집합을 삭제할 수 있습니다. 최근 인터넷에서 공개 실행 중인 보안되지 않은 Redis 인스턴스에 대한 악성 공격에 대한 보고가 있었습니다. 공격자는 데이터베이스를 지운 후 피해자에게 데이터베이스를 복원하려면 보상금을 지불하라고 요구했습니다. System.IO
클래스의 일부인 Read()
및 관련 메서드를 잘못 해석하는 것은 드문 일이 아닙니다. .NET의 대부분의 오류와 비정상적인 이벤트는 예외 발생으로 이어집니다. (이는 .NET이 C 등의 언어보다 나은 장점 중 하나입니다. 예외로 인해 프로그래머는 무엇이 잘못되었는지 쉽게 판단할 수 있습니다.) 하지만 stream 및 reader 클래스는 소량의 데이터만 사용할 때는 이를 비정상이나 예외 사항으로 간주하지 않습니다. 이 클래스는 단순히 소량의 데이터를 반환 버퍼에 추가하고 반환 값을 읽어들인 바이트 수 또는 문자 수로 설정합니다. 반환되는 데이터 양이 요청한 데이터 양과 같다고 보장할 수 있습니다.Read()
및 다른 IO 메서드의 반환 값을 검사하여 데이터를 예상한 양만큼 받도록 하는 것이 중요합니다.Read()
의 반환 값을 무시합니다. 공격자가 작은 파일을 만들면 프로그램은 이전 사용자의 나머지 데이터를 재활용하여 이 데이터가 공격자의 소유인 것처럼 처리합니다.
char[] byteArray = new char[1024];
for (IEnumerator i=users.GetEnumerator(); i.MoveNext() ;i.Current()) {
string userName = (string) i.Current();
string pFileName = PFILE_ROOT + "/" + userName;
StreamReader sr = new StreamReader(pFileName);
sr.Read(byteArray,0,1024);//the file is always 1k bytes
sr.Close();
processPFile(userName, byteArray);
}
char buf[10], cp_buf[10];
fgets(buf, 10, stdin);
strcpy(cp_buf, buf);
fgets()
가 반환할 때 buf
에 길이가 9자 이하인 null로 끝나는 문자열이 들어 있을 것으로 예상합니다. 하지만 I/O 오류가 발생하면 fgets()
는 buf
를 null로 종료하지 않습니다. 뿐만 아니라, 문자를 읽기 전에 파일 끝에 도달하면 fgets()
는 buf
에 아무것도 쓰지 않고 반환합니다. 두 가지 경우 모두, fgets()
는 NULL
을 반환하여 이상이 발생했음을 알리지만 이 경고는 인식되지 않습니다. buf
에 null 종결자가 없으면 이후의 strcpy()
호출에서 buffer overflow가 발생할 수 있습니다.java.io
클래스의 일부인 read()
및 관련 메서드를 잘못 해석하는 것은 드문 일이 아닙니다. Java의 대부분의 오류와 비정상적인 이벤트는 예외 발생으로 이어집니다. (이는 Java가 C 등의 언어보다 나은 장점 중 하나입니다. 예외로 인해 프로그래머는 무엇이 잘못되었는지 쉽게 판단할 수 있습니다.) 하지만 stream 및 reader 클래스는 소량의 데이터만 사용할 때는 이를 비정상이나 예외로 간주하지 않습니다. 이 클래스는 단순히 소량의 데이터를 반환 버퍼에 추가하고 반환 값을 읽어들인 바이트 수 또는 문자 수로 설정합니다. 반환되는 데이터 양이 요청한 데이터 양과 같다고 보장할 수 있습니다.read()
및 다른 IO 메서드의 반환 값을 검사하여 데이터를 예상한 양만큼 받도록 하는 것이 중요해집니다.read()
의 반환 값을 무시합니다. 공격자가 작은 파일을 만들면 프로그램은 이전 사용자의 나머지 데이터를 재활용하여 이 데이터가 공격자의 소유인 것처럼 처리합니다.
FileInputStream fis;
byte[] byteArray = new byte[1024];
for (Iterator i=users.iterator(); i.hasNext();) {
String userName = (String) i.next();
String pFileName = PFILE_ROOT + "/" + userName;
FileInputStream fis = new FileInputStream(pFileName);
fis.read(byteArray); // the file is always 1k bytes
fis.close();
processPFile(userName, byteArray);
}
read()
의 반환 값을 무시합니다. 공격자가 작은 파일을 만들면 프로그램은 이전 사용자의 나머지 데이터를 재활용하여 이 데이터가 공격자의 소유인 것처럼 처리합니다.
var fis: FileInputStream
val byteArray = ByteArray(1023)
val i: Iterator<*> = users.iterator()
while (i.hasNext()) {
val userName = i.next() as String
val pFileName: String = PFILE_ROOT.toString() + "/" + userName
val fis = FileInputStream(pFileName)
fis.read(byteArray) // the file is always 0k bytes
fis.close()
processPFile(userName, byteArray)
}
StreamReader
의 Finalize()
메서드는 결국 Close()
를 호출하지만 Finalize()
메서드를 호출하기까지 시간이 얼마나 걸릴지 장담할 수 없습니다. 사실, Finalize()
의 호출 여부도 장담할 수 없습니다. 사용량이 많은 환경에서는 이로 인해 VM이 사용 가능한 파일 핸들을 모두 소진시키는 결과를 초래할 수도 있습니다.예제 2: 일반적인 조건에서 다음 코드는 데이터베이스 쿼리를 실행하고 데이터베이스가 반환한 결과를 처리한 다음 할당된
private void processFile(string fName) {
StreamWriter sw = new StreamWriter(fName);
string line;
while ((line = sr.ReadLine()) != null)
processLine(line);
}
SqlConnection
개체를 닫습니다. 하지만 SQL을 실행하거나 결과를 처리하는 동안 예외 사항이 발생하면 SqlConnection
개체는 닫히지 않게 됩니다. 이런 일이 자주 발생하면 데이터베이스에 사용 가능한 커서가 부족하게 되어 SQL 쿼리를 더 이상 실행할 수 없습니다.
...
SqlConnection conn = new SqlConnection(connString);
SqlCommand cmd = new SqlCommand(queryString);
cmd.Connection = conn;
conn.Open();
SqlDataReader rdr = cmd.ExecuteReader();
HarvestResults(rdr);
conn.Connection.Close();
...
int decodeFile(char* fName)
{
char buf[BUF_SZ];
FILE* f = fopen(fName, "r");
if (!f) {
printf("cannot open %s\n", fName);
return DECODE_FAIL;
} else {
while (fgets(buf, BUF_SZ, f)) {
if (!checkChecksum(buf)) {
return DECODE_FAIL;
} else {
decodeBlock(buf);
}
}
}
fclose(f);
return DECODE_SUCCESS;
}
CALL "CBL_CREATE_FILE"
USING filename
access-mode
deny-mode
device
file-handle
END-CALL
IF return-code NOT = 0
DISPLAY "Error!"
GOBACK
ELSE
PERFORM write-data
IF ws-status-code NOT = 0
DISPLAY "Error!"
GOBACK
ELSE
DISPLAY "Success!"
END-IF
END-IF
CALL "CBL_CLOSE_FILE"
USING file-handle
END-CALL
GOBACK
.
New()
함수는 시스템 로그 데몬에 대한 새로운 연결을 설정하는데, 이는 log.syslog 패키지의 일부입니다. 반환된 작성자에 대한 각각의 쓰기는 지정된 우선 순위(syslog 기능 및 심각도의 결합) 및 접두사 태그가 포함된 로그 메시지를 보냅니다. 이로 인해 사용량이 많은 환경에서는 시스템의 소켓이 소진될 수 있습니다.예제 2: 이 예제에서는
func TestNew() {
s, err := New(syslog.LOG_INFO|syslog.LOG_USER, "the_tag")
if err != nil {
if err.Error() == "Unix syslog delivery error" {
fmt.Println("skipping: syslogd not running")
}
fmt.Println("New() failed: %s", err)
}
}
net/smtp
패키지의 Dial()
메서드가 localhost의 SMTP 서버에 연결된 새 클라이언트를 반환합니다. 연결 리소스는 할당되지만 Close()
함수 호출에 의해 해제되지는 않습니다.
func testDial() {
client, _ := smtp.Dial("127.0.0.1")
client.Hello("")
}
Arena.ofConfined()
에 의해 생성된 리소스가 닫혀 있지 않습니다.
...
Arena offHeap = Arena.ofConfined()
MemorySegment str = offHeap.allocateUtf8String("data");
...
//offHeap is never closed
BEGIN
...
F1 := UTL_FILE.FOPEN('user_dir','u12345.tmp','R',256);
UTL_FILE.GET_LINE(F1,V1,32767);
...
END;
onPause()
, onStop()
또는 onDestroy()
이벤트 처리기에 Camera
인스턴스를 릴리스하지 못합니다.onPause()
, onStop()
또는 onDestroy()
콜백에 릴리스되어 있지 않은 Camera
인스턴스를 할당합니다. Android OS는 현재 작업을 백그라운드로 보내야 할 때마다 또는 시스템 리소스가 낮은 경우 일시적으로 작업을 소멸시켜야 할 때 이러한 콜백을 호출합니다. Camera
개체를 올바르게 릴리스하지 못하면 해당 작업으로 인해 다른 응용 프로그램이(또는 심지어 동일한 응용 프로그램의 향후 인스턴스까지) 카메라에 접근하지 못합니다. 또한 작업이 일시 중지되어 있는 동안 Camera
인스턴스를 보유하면 불필요하게 배터리를 소모하여 사용자의 환경에 부정적인 영향을 미칠 수 있습니다.Camera
개체를 릴리스하는 데 사용되어야 하는 기본 onPause()
메서드를 오버라이드하지 않거나 종료 시퀀스 중 올바로 릴리스하지도 않는 Android 작업을 설명합니다.
public class UnreleasedCameraActivity extends Activity {
private Camera cam;
@Override
public void onCreate(Bundle state) {
...
}
@Override
public void onRestart() {
...
}
@Override
public void onStop() {
cam.stopPreview();
}
}
onPause()
, onStop()
또는 onDestroy()
이벤트 처리기에 MediaRecorder
, MediaPlayer
또는 AudioRecord
개체를 릴리스하지 못합니다.onPause()
, onStop()
또는 onDestroy()
콜백에 릴리스되어 있지 않은 미디어 개체를 할당합니다. Android OS는 현재 작업을 백그라운드로 보내야 할 때마다 또는 시스템 리소스가 낮은 경우 일시적으로 작업을 소멸시켜야 할 때 이러한 콜백을 호출합니다. 미디어 개체를 올바르게 릴리스하지 못하면 해당 작업으로 인해 Android의 미디어 하드웨어에 대한 후속 접근이 발생하여(다른 응용 프로그램 또는 동일한 응용 프로그램별) 소프트웨어 구현으로 변경되거나 모두 실패합니다. 릴리스되지 않은 미디어 인스턴스를 너무 많이 열어 두면 Android에 예외 사항이 발생하여 사실상 denial of service를 일으킵니다. 또한 작업이 일시 중지되어 있는 동안 미디어 인스턴스를 보유하면 불필요하게 배터리를 소모하여 사용자의 환경에 부정적인 영향을 미칠 수 있습니다.onPause()
메서드를 오버라이드하지 않거나 종료 시퀀스 중 올바로 릴리스하지도 않는 Android 작업을 설명합니다.
public class UnreleasedMediaActivity extends Activity {
private MediaPlayer mp;
@Override
public void onCreate(Bundle state) {
...
}
@Override
public void onRestart() {
...
}
@Override
public void onStop() {
mp.stop();
}
}
onPause()
, onStop()
또는 onDestroy()
이벤트 처리기에 Android 데이터베이스 처리기를 릴리스하지 못합니다.onPause()
, onStop()
또는 onDestroy()
콜백에서 닫혀 있지 않은 Android SQLite 데이터베이스 처리기를 유지합니다. Android OS는 현재 작업을 백그라운드로 보내야 할 때마다 또는 시스템 리소스가 낮은 경우 일시적으로 작업을 소멸시켜야 할 때 이러한 콜백을 호출합니다. 데이터베이스를 올바르게 닫지 못하여 작업이 끊임없이 다시 시작되는 경우, 작업은 사용 가능한 커서 장치를 소모할 수 있습니다. 이와 함께, 구현에 따라, Android 운영 체제 또한 예외가 발생되지 않으면 응용 프로그램을 손상시키는 DatabaseObjectNotClosedException
을 발생시킬 수 있습니다.onPause()
를 오버라이드하지 않으며 종료 시퀀스 중에 올바르게 릴리스하지도 않습니다.
public class MyDBHelper extends SQLiteOpenHelper {
...
}
public class UnreleasedDBActivity extends Activity {
private myDBHelper dbHelper;
private SQLiteDatabase db;
@Override
public void onCreate(Bundle state) {
...
db = dbHelper.getWritableDatabase();
...
}
@Override
public void onRestart() {
...
}
@Override
public void onStop() {
db.insert(cached_data); // flush cached data
}
}
DATA: result TYPE demo_update,
request TYPE REF TO IF_HTTP_REQUEST,
obj TYPE REF TO CL_SQL_CONNECTION.
TRY.
...
obj = cl_sql_connection=>get_connection( `R/3*my_conn`).
FINAL(sql) = NEW cl_sql_prepared_statement(
statement = `INSERT INTO demo_update VALUES( ?, ?, ?, ?, ?, ? )`).
CATCH cx_sql_exception INTO FINAL(exc).
...
ENDTRY.
SqlConnection
개체를 닫습니다. 하지만 SQL을 실행하거나 결과를 처리하는 동안 예외 사항이 발생하면 SqlConnection
개체는 닫히지 않습니다. 이런 일이 자주 발생하면 데이터베이스에 사용 가능한 커서가 부족하게 되어 SQL 쿼리를 더 이상 실행할 수 없습니다.
...
SqlConnection conn = new SqlConnection(connString);
SqlCommand cmd = new SqlCommand(queryString);
cmd.Connection = conn;
conn.Open();
SqlDataReader rdr = cmd.ExecuteReader();
HarvestResults(rdr);
conn.Connection.Close();
...
- void insertUser:(NSString *)name {
...
sqlite3_stmt *insertStatement = nil;
NSString *insertSQL = [NSString stringWithFormat:@INSERT INTO users (name, age) VALUES (?, ?)];
const char *insert_stmt = [insertSQL UTF8String];
...
if ((result = sqlite3_prepare_v2(database, insert_stmt,-1, &insertStatement, NULL)) != SQLITE_OK) {
MyLog(@"%s: sqlite3_prepare error: %s (%d)", __FUNCTION__, sqlite3_errmsg(database), result);
return;
}
if ((result = sqlite3_step(insertStatement)) != SQLITE_DONE) {
MyLog(@"%s: step error: %s (%d)", __FUNCTION__, sqlite3_errmsg(database), result);
return;
}
...
}
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery(CXN_SQL);
harvestResults(rs);
stmt.close();
func insertUser(name:String, age:int) {
let dbPath = URL(fileURLWithPath: Bundle.main.resourcePath ?? "").appendingPathComponent("test.sqlite").absoluteString
var db: OpaquePointer?
var stmt: OpaquePointer?
if sqlite3_open(dbPath, &db) != SQLITE_OK {
print("Error opening articles database.")
return
}
let queryString = "INSERT INTO users (name, age) VALUES (?,?)"
if sqlite3_prepare(db, queryString, -1, &stmt, nil) != SQLITE_OK{
let errmsg = String(cString: sqlite3_errmsg(db)!)
log("error preparing insert: \(errmsg)")
return
}
if sqlite3_bind_text(stmt, 1, name, -1, nil) != SQLITE_OK{
let errmsg = String(cString: sqlite3_errmsg(db)!)
log("failure binding name: \(errmsg)")
return
}
if sqlite3_bind_int(stmt, 2, age) != SQLITE_OK{
let errmsg = String(cString: sqlite3_errmsg(db)!)
log("failure binding name: \(errmsg)")
return
}
if sqlite3_step(stmt) != SQLITE_DONE {
let errmsg = String(cString: sqlite3_errmsg(db)!)
log("failure inserting user: \(errmsg)")
return
}
}
ZipFile
의 finalize()
메서드는 결국 close()
를 호출하지만 finalize()
메서드를 호출하기까지 시간이 얼마나 걸릴지 장담할 수 없습니다. 사용량이 많은 환경에서는 이로 인해 JVM이 파일 핸들을 모두 소진시키는 결과를 초래할 수도 있습니다.예제 2: 일반적인 조건에서 다음 해결책은 모든 zip 파일 항목을 출력한 후 파일 핸들을 올바르게 닫습니다. 그러나 항목을 반복하는 동안 예외가 발생하는 경우, zip 파일 핸들은 닫히지 않습니다. 이런 일이 빈번하게 발생하는 경우, JVM에는 사용 가능한 파일 핸들이 계속 부족할 수 있습니다.
public void printZipContents(String fName) throws ZipException, IOException, SecurityException, IllegalStateException, NoSuchElementException {
ZipFile zf = new ZipFile(fName);
Enumeration<ZipEntry> e = zf.entries();
while (e.hasMoreElements()) {
printFileInfo(e.nextElement());
}
}
public void printZipContents(String fName) throws ZipException, IOException, SecurityException, IllegalStateException, NoSuchElementException {
ZipFile zf = new ZipFile(fName);
Enumeration<ZipEntry> e = zf.entries();
while (e.hasMoreElements()) {
printFileInfo(e.nextElement());
}
zf.close();
}
...
lo_client = cl_apc_tcp_client_manager=>create( i_host = host
i_port = port
i_frame = lv_frame
i_protocol = protocol
i_ssl_id = ssl_id
i_event_handler = lo_event_handler ).
" initiate the connection setup, successful connect leads to execution of ON_OPEN
lo_client->connect( ).
...
예제 2: 일반적인 조건에서 다음 해결책은 소켓 및 연결된 모든 스트림을 올바르게 닫습니다. 그러나 입력을 읽거나 화면에 데이터를 쓰는 동안 예외가 발생하는 경우, 소켓 개체가 닫히지 않습니다. 이런 일이 빈번하게 발생하는 경우, 시스템에는 소켓이 부족하고 시스템은 더 이상의 연결을 처리할 수 없습니다.
private void echoSocket(String host, int port) throws UnknownHostException, SocketException, IOException
{
Socket sock = new Socket(host, port);
BufferedReader reader = new BufferedReader(new InputStreamReader(sock.getInputStream()));
while ((String socketData = reader.readLine()) != null) {
System.out.println(socketData);
}
}
private void echoSocket(String host, int port) throws UnknownHostException, SocketException, IOException
{
Socket sock = new Socket(host, port);
BufferedReader reader = new BufferedReader(new InputStreamReader(sock.getInputStream()));
while ((String socketData = reader.readLine()) != null) {
System.out.println(socketData);
}
sock.close();
}
StreamReader
의 Finalize()
메서드는 결국 Close()
를 호출하지만 Finalize()
메서드를 호출하기까지 시간이 얼마나 걸릴지 장담할 수 없습니다. 사실 Finalize()
의 호출 여부도 장담할 수 없습니다. 사용량이 많은 환경에서는 이로 인해 VM이 사용 가능한 파일 핸들을 모두 소진시키는 결과를 초래할 수도 있습니다.
private void processFile(string fName) {
StreamWriter sw = new StreamWriter(fName);
string line;
while ((line = sr.ReadLine()) != null)
processLine(line);
}
FileInputStream
의 finalize()
메서드는 결국 close()
를 호출하지만 finalize()
메서드를 호출하기까지 시간이 얼마나 걸릴지 장담할 수 없습니다. 사용량이 많은 환경에서는 이로 인해 JVM이 파일 핸들을 모두 소진시키는 결과를 초래할 수도 있습니다.
private void processFile(String fName) throws FileNotFoundException, IOException {
FileInputStream fis = new FileInputStream(fName);
int sz;
byte[] byteArray = new byte[BLOCK_SIZE];
while ((sz = fis.read(byteArray)) != -1) {
processBytes(byteArray, sz);
}
}
...
CFIndex numBytes;
do {
UInt8 buf[bufferSize];
numBytes = CFReadStreamRead(readStream, buf, sizeof(buf));
if( numBytes > 0 ) {
handleBytes(buf, numBytes);
} else if( numBytes < 0 ) {
CFStreamError error = CFReadStreamGetError(readStream);
reportError(error);
}
} while( numBytes > 0 );
...
def readFile(filename: String): Unit = {
val data = Source.fromFile(fileName).getLines.mkString
// Use the data
}
...
func leak(reading input: InputStream) {
input.open()
let bufferSize = 1024
let buffer = UnsafeMutablePointer<UInt8>.allocate(capacity: bufferSize)
while input.hasBytesAvailable {
let read = input.read(buffer, maxLength: bufferSize)
}
buffer.deallocate(capacity: bufferSize)
}
...
performOperationInCriticalSection()
앞에 잠금을 설정하지만, 해당 메서드에서 예외가 발생하는 경우 잠금을 해제하지 못합니다.
Object synchronizationObject = new Object ();
System.Threading.Monitor.Enter(synchronizationObject);
performOperationInCriticalSection();
System.Threading.Monitor.Exit(synchronizationObject);
int helper(char* fName)
{
int status;
...
pthread_cond_init (&count_threshold_cv, NULL);
pthread_mutex_init(&count_mutex, NULL);
status = perform_operation();
if (status) {
printf("%s", "cannot perform operation");
return OPERATION_FAIL;
}
pthread_mutex_destroy(&count_mutex);
pthread_cond_destroy(&count_threshold_cv);
return OPERATION_SUCCESS;
}
CALL "CBL_GET_RECORD_LOCK"
USING file-handle
record-offset
record-length
reserved
END-CALL
IF return-code NOT = 0
DISPLAY "Error!"
GOBACK
ELSE
PERFORM write-data
IF ws-status-code NOT = 0
DISPLAY "Error!"
GOBACK
ELSE
DISPLAY "Success!"
END-IF
END-IF
CALL "CBL_FREE_RECORD_LOCK"
USING file-handle
record-offset
record-length
reserved
END-CALL
GOBACK
.
performOperationInCriticalSection()
앞에 잠금을 설정하지만 해당 메서드에서 예외가 발생한 경우 잠금을 해제하지 못합니다.
ReentrantLock myLock = new ReentrantLock ();
myLock.lock();
performOperationInCriticalSection();
myLock.unlock();
performOperationInCriticalSection()
앞에 잠금을 설정하지만 절대 해제하지 않습니다.
os_unfair_lock lock1 = OS_UNFAIR_LOCK_INIT;
os_unfair_lock_lock(&lock1);
performOperationInCriticalSection();
performOperationInCriticalSection()
앞에 잠금을 설정하지만 절대 해제하지 않습니다.
let lock1 = OSAllocatedUnfairLock()
lock1.lock()
performOperationInCriticalSection();
Echo
라는 클래스를 정의합니다. 클래스는 C를 사용하여 콘솔에 입력된 명령을 사용자에게 돌려보내는 하나의 네이티브 메서드를 선언합니다.
class Echo {
public native void runEcho();
static {
System.loadLibrary("echo");
}
public static void main(String[] args) {
new Echo().runEcho();
}
}
Echo
클래스에서 구현된 네이티브 메서드를 정의합니다.
#include <jni.h>
#include "Echo.h" //javah로 컴파일된Example 1
의 Java 클래스
#include <stdio.h>
JNIEXPORT void JNICALL
Java_Echo_runEcho(JNIEnv *env, jobject obj)
{
char buf[64];
gets(buf);
printf(buf);
}
gets()
를 사용하기 때문에 buffer overflow에 취약합니다. Example 1
의 취약점은 네이티브 메서드 구현의 소스 코드 감사를 통해 쉽게 발견할 수 있습니다. 소스 코드 감사는 C 소스 코드의 가용성 및 프로젝트 구축 방식에 따라 불가능할 수도 있지만 대부분의 경우 이 방법으로 충분합니다. 하지만 Java와 네이티브 메서드 간에 개체를 공유하게 되면 잠재적인 위험이 Java의 부적절한 데이터 처리가 네이티브 코드의 취약점으로 이어지거나 네이티브 코드의 안전하지 못한 작업으로 Java의 데이터 구조가 손상되는 훨씬 심각한 경우로 확대됩니다.Redirect
라는 클래스를 정의합니다. 이 클래스는 JavaScript를 사용하여 문서 위치를 변경하는 하나의 네이티브 JavaScript 메서드를 선언합니다.
import com.google.gwt.user.client.ui.UIObject;
class MyDiv {
...
public static void changeName(final UIObject object, final String name) {
changeName(object.getElement(), url);
}
public static native void changeName(final Element e, final String name) /*-{
$wnd.jQuery(e).html(name);
}-*/;
...
}
public
접근 메서드에서 private
배열 변수를 반환하여 이식 가능한 코드의 보안 코딩 규칙을 위반합니다. public
접근 메서드에서 private
배열 변수를 반환하면 호출 코드가 배열의 내용을 수정할 수 있기 때문에, 사실상 배열에 public
접근을 부여하게 되어 배열을 private
로 선언한 프로그래머의 의도와는 반대가 됩니다. public
접근 메서드에서 private
배열 변수를 반환하는 오류를 범합니다.
public final class urlTool extends Applet {
private URL[] urls;
public URL[] getURLs() {
return urls;
}
...
}
public class CustomerServiceApplet extends JApplet
{
public void paint(Graphics g)
{
...
conn = DriverManager.getConnection ("jdbc:mysql://db.example.com/customerDB", "csr", "p4ssw0rd");
...
package
수준 접근 권한을 가진 피어 클래스로 변환해야 합니다. 더 나쁜 경우, inner class가 엔클로우징 클래스(enclosing class)의 private
필드를 접근할 수 있기 때문에, inner class가 바이트코드의 피어 클래스가 되면 컴파일러는 inner class가 접근하는 private
필드를 protected
필드로 변환합니다.
public final class urlTool extends Applet {
private final class urlHelper {
...
}
...
}
finalize()
메서드를 public
으로 선언하여 이식 가능한 코드의 보안 코딩 규칙을 위반합니다.finalize()
구현 내에서 super.finalize()
를 호출하는 것만 제외하고 명시적으로 finalize를 호출할 수 없습니다. 이식 가능한 코드인 경우, 그렇지 않아도 오류가 발생하기 쉬운 수동 가비지 수집(garbage collection) 방법을 사용하면 공격자가 악의적으로 finalize()
메서드 중 하나를 호출하는 경우, 메서드가 public
접근으로 선언되어 있기 때문에 보안에 위협이 됩니다. finalize()
를 설계 의도대로 사용한다면 protected
접근 외에 다른 접근으로 finalize()
를 선언할 이유가 없습니다.public finalize()
method를 선언하는 오류를 범합니다.
public final class urlTool extends Applet {
public void finalize() {
...
}
...
}
public
, final
과 static
으로 선언하여 이식 가능한 코드의 보안 코딩 규칙을 위반합니다.public
, final
및 static
으로 선언된 배열은 버그가 됩니다. 배열이 변경 가능한 개체이기 때문에, final
제약 조건에 따라 배열 개체는 한 번만 지정해야 하지만 배열 요소의 값에 대해서는 아무런 보장이 없습니다. 배열이 public이기 때문에 악성 프로그램이 배열에 저장된 값을 변경할 수 있습니다. 대부분의 경우 배열은 private
로 해야 합니다. public
, final
및 static
으로 잘못 선언합니다.
public final class urlTool extends Applet {
public final static URL[] urls;
...
}
public
으로만 선언하고 final
로는 선언하지 않아, 이식 가능한 코드의 보안 코딩 규칙을 위반합니다. public
멤버 변수를 final
로 선언하여 공격자가 Applet의 내부 상태에 대한 무단 접근을 확보하거나 조작하지 못하게 해야 합니다.public
으로만 선언하고 final
로 선언하지 않는 오류를 범합니다.
public final class urlTool extends Applet {
public URL url;
...
}