분산 컴퓨팅에서 중요한 것은 시간과 상태입니다. 즉, 둘 이상의 구성 요소가 통신하려면 상태를 공유해야 하며 시간이 걸립니다.
대부분의 프로그래머들은 자신들의 작업을 의인화합니다. 하나의 컨트롤 스레드로 마치 자신이 직접 작업한 것처럼 전체 프로그램을 수행할 수 있을 것으로 생각합니다. 하지만 최신 컴퓨터는 작업 간에 매우 빠르게 전환되므로 멀티코어, 멀티 CPU 또는 분산 시스템에서 두 이벤트가 정확히 동시에 발생할 수 있습니다. 프로그래머가 만든 프로그램 실행 모델과 실제 현실 간에 빠르게 결함이 생기기 마련입니다. 이러한 결함은 스레드, 프로세스, 시간 및 정보 간의 예기치 않은 상호작용과 관련이 있습니다. 이러한 상호 작용은 공유 상태를 통해 발생합니다. 세마포, 변수, 파일 시스템 그리고 정보를 저장할 수 있는 모든 것이 여기에 포함됩니다.
HttpSessionState
속성으로 저장하면 응용 프로그램 안정성을 해칠 수 있습니다.HttpSessionState
개체, 해당 속성 및 메모리에서 참조하는 모든 개체를 저장합니다. 이 모델은 단일 시스템의 시스템 메모리가 수용할 수 있는 상태로 활성 세션 상태를 제한합니다. 이 제약의 범위를 넘어 용량을 확장하려면 전체적인 성능을 개선하기 위해 용량을 확장하고 여러 시스템 간의 복제를 허용하는 세션 상태 정보를 지속하도록 서버를 자주 구성해야 합니다. 해당 세션 상태를 유지하려면 저장된 모든 개체가 serializable 상태인 HttpSessionState
를 서버가 직렬화해야 합니다.[Serializable]
속성을 선언해야 합니다. 또한, 개체가 사용자 지정 serialization 메서드를 사용해야 하는 경우 ISerializable
인터페이스도 구현해야 합니다.
public class DataGlob {
String GlobName;
String GlobValue;
public void AddToSession(HttpSessionState session) {
session["glob"] = this;
}
}
sleep()
을 호출하면 성능이 떨어질 수 있고 교착 상태(deadlock)가 발생할 수도 있습니다.sleep()
을 호출하면 다른 모든 스레드는 리소스가 해제되기를 기다리게 될 수 있어 성능이 저하되거나 교착 상태(deadlock)가 될 수 있습니다. sleep()
을 호출합니다.
ReentrantLock rl = new ReentrantLock();
...
rl.lock();
Thread.sleep(500);
...
rl.unlock();
if (fitz == null) {
synchronized (this) {
if (fitz == null) {
fitz = new Fitzer();
}
}
}
return fitz;
Fitzer()
개체만 할당되는 것을 보장하려 하지만 이 코드를 호출할 때마다 동기화 비용을 지불하지는 않으려는 경우가 있습니다. 이런 경우를 double-checked locking이라고 합니다.Fitzer()
개체를 할당합니다. 자세한 내용은 "Double-Checked Locking is Broken" Declaration을 참조하십시오[1].pthread_mutex_unlock()
을 호출하여 뮤텍스를 잠금 해제해야 합니다. 스레드의 신호 처리가 뮤텍스의 잠금 해제를 실패하는 경우, 두 번째 스레드의 pthread_cond_wait()
호출은 반환되지 않고 이 스레드는 실행되지 않습니다. pthread_cond_signal()
를 호출하여 뮤텍스에 대기 중인 또 다른 스레드를 신호 처리하지만, 대기 중인 나머지 스레드를 뮤텍스의 잠금 해제하는 것은 실패합니다.
...
pthread_mutex_lock(&count_mutex);
// Signal waiting thread
pthread_cond_signal(&count_threshold_cv);
...
...
if (tmpnam_r(filename)){
FILE* tmp = fopen(filename,"wb+");
while((recv(sock,recvbuf,DATA_SIZE, 0) > 0)&&(amt!=0))
amt = fwrite(recvbuf,1,DATA_SIZE,tmp);
}
...
GetTempFileName()
함수뿐 아니라 tmpnam()
, tempnam()
, mktemp()
및 이에 상응하는, 앞에 _
(밑줄)이 붙은 C++ 함수 등의 C 라이브러리가 있습니다 이 그룹의 함수는 속성 상 선택한 파일 이름에 대한 경쟁 조건(race condition)이 발생합니다. 함수가 파일 이름 선택 시점에 이름이 고유하다는 것은 보장하지만 이름을 선택한 후 응용 프로그램이 파일을 열기 전에 다른 프로세서나 공격자가 같은 이름의 파일을 생성하는 것을 방지하는 메커니즘이 없습니다. 같은 함수의 다른 호출로 인해 발생하는 자연스러운 충돌의 위험 외에도 이들 함수가 생성한 파일 이름이 추측하기 어려울 만큼 무작위성이 보장되지 않기 때문에 공격자가 악의적으로 충돌을 일으킬 수 있습니다.O_CREAT
및 O_EXCL
플래그를 사용한 open()
호출 또는 CREATE_NEW
속성을 사용한 CreateFile()
호출로 파일을 여는 것입니다. 이 방법은 파일이 이미 있을 때는 파일을 열지 않기 때문에 앞서 설명한 종류의 공격을 예방할 수 있습니다. 하지만 공격자가 임시 파일 이름의 순서를 정확하게 예측할 수 있는 경우 응용 프로그램이 필요한 임시 저장소를 여는 것을 막아 Denial Of Service(DoS) 공격을 일으킬 수 있습니다. 이런 종류의 공격은 이들 함수가 생성하는 파일의 이름 선택에 사용된 무작위성의 수준이 낮은 것을 감안하면 어렵지 않게 실행할 수 있습니다.tmpfile()
및 이에 상응하는, 앞에 _
(밑줄)이 붙은 C++ 함수뿐 아니라 동작 기능이 좀 더 우수한 C 라이브러리 함수 mkstemp()
등의 C 라이브러리 함수가 있습니다.tmpfile()
형식의 함수는 "wb+"
플래그가 전달되면(즉, 읽기/쓰기 모드의 이진 파일로 전달되면) 고유한 파일 이름을 생성하고 fopen()
과 같은 방식으로 파일을 엽니다. 파일이 이미 있으면, 앞에서 언급한 고유한 파일 이름 선택과 이후의 선택한 파일 열기 사이에 존재하는 경쟁 조건(race condition) 관련 보안 문제를 해결하기 위해 tmpfile()
은 크기 0으로 파일을 자릅니다. 하지만 이 동작으로 함수의 보안 문제를 해결하지는 못합니다. 첫째, 공격자는 대체로 tmpfile()
이 연 파일이 보유하고 있을 완화된 접근 권한으로 파일을 미리 만들 수 있습니다. 뿐만 아니라, Unix 기반 시스템에서 공격자가 파일을 다른 중요한 파일의 링크로 미리 만드는 경우, 응용 프로그램은 높은 권한을 사용하여 해당 파일을 잘라 공격자 대신 시스템을 손상시킬 수 있습니다. 마지막으로 tmpfile()
이 새 파일을 만들게 되면 해당 파일에 적용되는 접근 권한이 운영 체제 별로 다르기 때문에 공격자가 사용할 파일 이름을 미리 예측할 수 없는 경우에도 응용 프로그램 데이터가 취약해질 수 있습니다.mkstemp()
입니다. 이 함수는 사용자가 제공한 파일 이름 템플릿과 무작위로 생성된 일련의 문자를 기반으로 고유한 파일을 만들고 엽니다. 그런 파일을 만들 수 없는 경우 작업은 실패하고 -1
을 반환합니다. 요즘의 시스템에서는 0600
모드를 사용하여 파일을 엽니다. 즉, 파일은 사용자가 접근 권한을 명시적으로 변경하는 경우를 제외하고 외부에서 조작할 수 없습니다. 하지만 mkstemp()
도 예측 가능한 파일 이름 사용에서 자유롭지 못하며 공격자가 사용할 파일 이름을 예측하고 미리 만들어 mkstemp()
가 실패하게 만들면 응용 프로그램이 denial of service 공격에 취약해질 수 있습니다.
...
try:
tmp_filename = os.tempnam()
tmp_file = open(tmp_filename, 'w')
data = s.recv(4096)
while True:
more = s.recv(4096)
tmp_file.write(more)
if not more:
break
except socket.timeout:
errMsg = "Connection timed-out while connecting"
self.logger.exception(errMsg)
raise Exception
...
os.O_CREAT
및 os.O_EXCL
플래그를 사용한 open()
호출을 사용하여 파일을 여는 것입니다. 이 방법은 파일이 이미 있을 때는 파일을 열지 않기 때문에 앞서 설명한 종류의 공격을 예방할 수 있습니다. 하지만 공격자가 임시 파일 이름의 순서를 정확하게 예측할 수 있는 경우 응용 프로그램이 필요한 임시 저장소를 여는 것을 막아 Denial Of Service(DoS) 공격을 일으킬 수 있습니다. 이런 종류의 공격은 이들 함수가 생성하는 파일의 이름 선택에 사용된 무작위성의 수준이 낮은 것을 감안하면 어렵지 않게 실행할 수 있습니다.tmpfile()
과 같은 함수가 포함됩니다.tmpfile()
형식의 함수는 "wb+"
플래그가 전달되면(즉, 읽기/쓰기 모드의 이진 파일로 전달되면) 고유한 파일 이름을 생성하고 open()
과 같은 방식으로 파일을 엽니다. 파일이 이미 있으면, 앞에서 언급한 고유한 파일 이름 선택과 이후의 선택한 파일 열기 사이에 존재하는 경쟁 조건(race condition) 관련 보안 문제를 해결하기 위해 tmpfile()
은 크기 0으로 파일을 자릅니다. 하지만 이 동작으로 함수의 보안 문제를 해결하지는 못합니다. 첫째, 공격자는 대체로 tmpfile()
이 연 파일이 보유하고 있을 완화된 접근 권한으로 파일을 미리 만들 수 있습니다. 뿐만 아니라, Unix 기반 시스템에서 공격자가 파일을 다른 중요한 파일의 링크로 미리 만드는 경우, 응용 프로그램은 높은 권한을 사용하여 해당 파일을 잘라 공격자 대신 시스템을 손상시킬 수 있습니다. 마지막으로 tmpfile()
이 새 파일을 만들게 되면 해당 파일에 적용되는 접근 권한이 운영 체제 별로 다르기 때문에 공격자가 사용할 파일 이름을 미리 예측할 수 없는 경우에도 응용 프로그램 데이터가 취약해질 수 있습니다.
...
HttpSession sesssion = request.getSession(true);
sesssion.setMaxInactiveInterval(-1);
...