분산 컴퓨팅에서 중요한 것은 시간과 상태입니다. 즉, 둘 이상의 구성 요소가 통신하려면 상태를 공유해야 하며 시간이 걸립니다.
대부분의 프로그래머들은 자신들의 작업을 의인화합니다. 하나의 컨트롤 스레드로 마치 자신이 직접 작업한 것처럼 전체 프로그램을 수행할 수 있을 것으로 생각합니다. 하지만 최신 컴퓨터는 작업 간에 매우 빠르게 전환되므로 멀티코어, 멀티 CPU 또는 분산 시스템에서 두 이벤트가 정확히 동시에 발생할 수 있습니다. 프로그래머가 만든 프로그램 실행 모델과 실제 현실 간에 빠르게 결함이 생기기 마련입니다. 이러한 결함은 스레드, 프로세스, 시간 및 정보 간의 예기치 않은 상호작용과 관련이 있습니다. 이러한 상호 작용은 공유 상태를 통해 발생합니다. 세마포, 변수, 파일 시스템 그리고 정보를 저장할 수 있는 모든 것이 여기에 포함됩니다.
HttpSession
속성으로 저장하면 응용 프로그램 안정성을 해칠 수 있습니다.HttpSession
개체를 복제하여 한 JVM을 사용할 수 없게 되면 다른 JVM이 개입하여 역할을 대신하기 때문에 응용 프로그램의 흐름이 중단되지 않습니다.Serializable
인터페이스를 구현해야 합니다.
public class DataGlob {
String globName;
String globValue;
public void addToSession(HttpSession session) {
session.setAttribute("glob", this);
}
}
block.timestamp
또는 block.number
를 사용합니다.block.timestamp
또는 block.number
에 연결된 값을 사용해 시간 종속 이벤트를 트리거합니다. 그런데 이러한 값은 대개 사용하기에 안전하지 않은 시간 정보를 제공하는 경우가 많습니다.block.timestamp
를 사용하는 코드는 신뢰하기가 어려울 수 있으며 최악의 경우에는 악의적인 채굴자가 블록의 타임스탬프를 채굴에 유리하게 변경할 수도 있습니다.block.number
사용 시에는 블록 간 시간(약 14초) 예측은 가능하지만 블록 시간이 일정하게 유지되지 않으며 네트워크 활동에 따라 달라질 수도 있습니다. 그러므로 block.number
는 시간 관련 계산에서 안전하게 사용할 수 없습니다.block.number
를 사용하여 일정 기간이 지난 후 자금을 잠금 해제합니다.
function withdraw() public {
require(users[msg.sender].amount > 0, 'no amount locked');
require(block.number >= users[msg.sender].unlockBlock, 'lock period not over');
uint amount = users[msg.sender].amount;
users[msg.sender].amount = 0;
(bool success, ) = msg.sender.call.value(amount)("");
require(success, 'transfer failed');
}
...
var authenticated = true;
...
database_connect.query('SELECT * FROM users WHERE name == ? AND password = ? LIMIT 1', userNameFromUser, passwordFromUser, function(err, results){
if (!err && results.length > 0){
authenticated = true;
}else{
authenticated = false;
}
});
if (authenticated){
//do something privileged stuff
authenticatedActions();
}else{
sendUnathenticatedMessage();
}
true
로 설정하고 확인되지 않으면 false
로 설정합니다. 하지만 콜백은 IO에 의해 차단되므로 비동기로 실행되며 if (authenticated)
확인 후에 실행될 수 있습니다. 기본값은 true이기 때문에 사용자가 실제로 인증되었는지 여부와 관계없이 if 문이 실행됩니다.
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(Uri.fromFile(new File(Environment.getExternalStorageDirectory() + "/download/" + "app.apk")), "application/vnd.android.package-archive");
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
setuid root
에서 가져온 것입니다. 이 프로그램은 권한 없는 사용자를 대신하여 특정 파일 작업을 수행하고 액세스 검사를 사용하여 현재 사용자가 사용해서는 안 되는 작업을 수행하는 데 루트 권한을 사용하지 못하도록 합니다. 이 프로그램은 파일을 열고 필요한 작업을 수행하기 전에 access()
시스템 호출을 사용하여 프로그램을 실행하는 사람이 지정된 파일에 액세스할 수 있는 권한을 가지고 있는지 확인합니다.
if (!access(file,W_OK)) {
f = fopen(file,"w+");
operate(f);
...
}
else {
fprintf(stderr,"Unable to open file %s.\n",file);
}
access()
호출은 예상대로 동작하고 프로그램을 실행하는 사용자가 파일 쓰기 권한을 가지고 있으면 0
을, 그렇지 않으면 -1을 반환합니다. 하지만 access()
및 fopen()
모두 파일 핸들이 아닌 파일 이름에 대해 동작하기 때문에 file
변수가 fopen()
에 전달될 때 access()
에 전달되었을 때와 같은 디스크상의 파일을 참조한다고 보장할 수 없습니다. 공격자가 access()
호출 후 file
을 다른 파일에 대한 심볼 링크로 교체하면 프로그램은 파일이 공격자가 수정할 수 없는 파일인 경우에도 해당 파일에 루트 권한을 사용하여 작업합니다. 공격자는 프로그램을 속여 수행할 권한이 없는 작업을 수행하게 함으로써 높은 권한을 얻는 것입니다.root
권한이 있는 프로그램에만 국한되는 것은 아닙니다. 공격자가 수행할 수 없는 작업을 수행할 수 있는 응용 프로그램이라면 모두 공격의 대상이 될 수 있습니다.
fd = creat(FILE, 0644); /* Create file */
if (fd == -1)
return;
if (chown(FILE, UID, -1) < 0) { /* Change file owner */
...
}
chown()
호출 시 작동되는 파일이 creat()
호출 시 생성되는 파일과 같다고 가정하지만 반드시 그런 것은 아닙니다. chown()
은 파일 핸들이 아닌 파일 이름에 대해 작동하므로 공격자가 자신이 소유하지 않은 파일의 링크로 파일을 대체할 수 있습니다. 그러면 공격자가 chown()
호출 시 연결된 파일의 소유권을 얻게 됩니다.CBL_CHECK_FILE_EXIST
루틴을 호출하여 파일이 존재하는지 확인합니다.
CALL "CBL_CHECK_FILE_EXIST" USING
filename
file-details
RETURNING status-code
END-CALL
IF status-code NOT = 0
MOVE 3 to access-mode
MOVE 0 to deny-mode
MOVE 0 to device
CALL "CBL_CREATE_FILE" USING
filename
access-mode
deny-mode
device
file-handle
RETURNING status-code
END-CALL
END-IF
CBL_CHECK_FILE_EXIST
호출이 예상대로 작동하고 0이 아닌 값을 반환합니다. 이는 파일이 없음을 나타냅니다. 하지만 CBL_CHECK_FILE_EXIST
및 CBL_CREATE_FILE
은 모두 파일 핸들 대신 파일 이름을 사용하여 작업하기 때문에 filename
변수가 CBL_CHECK_FILE_EXIST
에 전달되었을 때 참조하던 파일과 CBL_CREATE_FILE
에 전달될 때 참조하는 파일이 여전히 동일한 것이라는 보장이 없습니다. 공격자가 CBL_CHECK_FILE_EXIST
호출 이후에 filename
을 만들 경우, CBL_CREATE_FILE
호출은 실패하며 프로그램은 파일이 비어 있다고 믿게 됩니다. 실제로는 공격자가 제어하는 데이터가 파일 안에 들어 있습니다.root
권한이 있는 프로그램에 적용될 수 있습니다. 허용되지 않는 작업을 수행하도록 프로그램을 속이면 공격자가 승격된 권한을 얻을 수 있습니다.java.text.Format
의 parse()
및 format()
메서드에는 설계 결함이 있어서 한 사용자가 다른 사용자의 데이터를 볼 수 있습니다.java.text.Format
의 parse()
및 format()
메서드에는 race condition이 있어서 한 사용자가 다른 사용자의 데이터를 볼 수 있습니다.
public class Common {
private static SimpleDateFormat dateFormat;
...
public String format(Date date) {
return dateFormat.format(date);
}
...
final OtherClass dateFormatAccess=new OtherClass();
...
public void function_running_in_thread1(){
System.out.println("Time in thread 1 should be 12/31/69 4:00 PM, found: "+ dateFormatAccess.format(new Date(0)));
}
public void function_running_in_thread2(){
System.out.println("Time in thread 2 should be around 12/29/09 6:26 AM, found: "+ dateFormatAccess.format(new Date(System.currentTimeMillis())));
}
}
format()
구현의 race condition으로 인해 첫 번째 스레드의 데이터가 두 번째 스레드의 출력에 표시됩니다.