병렬처리에 관해 이야기할 때 항상 등장하는 단어인 Context Switching에 대해 공부 해보았다. 해당 단어를 꺼내기 위해서는 기본적으로 알아둬야 할 사전지식이 필요하다. 해당 사전지식도 가볍게 다루며 콘텍스트 스위칭에 대하여 작성해보자.
프로세스
프로세스는 컴퓨터에서 프로그램이 실행될 때 사용되는 실행 단위로, 실행 중인 프로그램의 인스턴스다. 메모리와 CPU 자원을 할당받아 동작하는 상태를 의미하며, 우리가 코드를 통해 만든 하나의 애플리케이션이 실행될 때 생성된다.
멀티 프로세스, 멀티 스레드
멀티 프로세스는 여러 개의 독립된 프로세스를 생성하여 각각의 메모리 공간을 가지고 병렬로 동작
멀티 스레드는 하나의 프로세스 내에서 여러 스레드가 메모리 자원을 공유하며 동작
CPU의 동작
CPU는 하나의 프로세스만을 담당하는 것이 아니라, 컴퓨터에서 실행된 모든 프로그램의 동작을 담당해야 한다.
CPU는 여러 프로그램을 동시에 처리하는 것처럼 보이지만, 사실은 매우 짧은 시간 간격으로 각 프로세스의 작업을 번갈아가며 처리하고 있다. 이 때 각 프로세스는 자신이 중단된 지점의 상태, 즉 레지스터, 스택 포인터, 프로그램 카운터 등의 정보를 저장하고, 다른 프로세스의 상태를 불러와 실행을 이어간다. 이 정보를 Context(문맥) 라고 한다.
Context Switching(문맥 교환)
문맥 교환(Context Switching)은 여러 프로세스나 스레드가 CPU를 사용할 수 있도록 문맥을 저장하고 불러오는 작업을 의미한다. 이 과정에서 실행 중인 프로세스의 상태를 저장하고 다른 프로세스의 상태를 복원하는 작업이 필요하므로 일정한 오버헤드(비용) 가 발생한다. 따라서 병렬 처리를 통해 성능을 개선하려면, 문맥 교환의 빈도와 그로 인한 오버헤드가 전체 성능에 미치는 영향을 신중하게 고려해야 한다.
우리가 hello 를 회원가입 할 때 입력받아 암호화 하여 데이터베이스에 저장한다고 가정해보자.
회원가입 할 때 받은 비밀번호를 단순 해시화 하여 값을 저장했을 때
SHA256(hello) → 2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824 의 값으로 단방향 해시되어 데이터베이스에는 암호화 된 값을 저장할 것이다. 그래야 데이터베이스를 탈취당해도 유저의 실제 암호는 알 수 없기 때문인데
사실은 값을 찾아낼 수 있다.
레인보우 테이블
복호화를 하지 못하는데 값을 어떻게 찾을 수 있는지 의문이 들지만 해시된 값이 그저 단순 문자열로 이루어진 고정 값이라면 레인보우테이블 기법을 통해 해시된 값을 알아낼 수 있다.
레인보우 테이블이란 기존 문자들을 미리 암호화 처리하여 사전처럼 해시값 기준으로 원래의 문자열을 알아낼 수 있는 형태의 테이블이다.
레인보우 테이블이란 암호화된 해시값을 키로 두고, 키에 대한 원조 값을 찾아낼 수 있는 값을 value로 두는 사전이라고 볼 수 있는데 예시 테이블을 참고해서 보자면
만약 이러한 테이블을 저장한 레인보우 테이블이 있을 때 해커는 hello의 값을 2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824 해시 검색을 통해 알아낼 수 있을 것이다.
코드 예시
import java.util.*;
public class main
{
public static void main(String[] args)
{
// 2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824의 값이 저장됨
String passwordSave = sha256("hello");
//만들어져 있는 레인보우 테이블이라고 가정
Map<String, String> rainbowTable = new HashMap<>();
rainbowTable.put(sha256("hello"), "hello");
//얻은 해시값
System.out.println(rainbowTable.get("2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824"));
}
public static String sha256(String needEncodingString){
//해싱처리
//hello -> sha256 -> 2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824
return "2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824";
}
}
---------
출력 값 : hello
솔트 치기
솔트를 치는 이유는 보안 강화이며, 단순한 해시화는 앞에서 보았던 것 처럼 쉽게 예측이 가능한 것을 보았다. 해시작업을 할 때 기존의 문자열만으로 해시하는 것이 아니라 기존 문자열과 함께 서버에서만 알 수 있는 문자열을 부여해서 두 문자를 합친 해시값을 만드는 것이다. 예를 들면 sha256(hello + "qwerafaad" ) 와 같이 암호와 관련이 없는 문자열을 해시하기 전 추가해서 전혀 다른 해시값을 만드는 것이다. 이 때 암호와 관련이 없는 문자열을 솔트(소금)이라고 부른다.
또 솔트를 칠 때 주의해야 할 점이 있는데 이에 대해 알아보자
솔트값
소금 값은 짧지 않은 값으로 생성되어야 한다. 평범한 비밀번호로 구성되어있는 룩업 테이블(레인보우 테이블) 등의 경우 837G 만으로 전체 룩업 테이블을 구성할 수 있다. 이 837GB에서 “asd” 라는 문자가 추가되는 테이블을 만들었다고 했을 때 해커 입장에서는 부담스럽지 않은 값으로 해당 테이블의 조합을 만들어 낼 수 있을 것이다.
때문에 소금 값은 보통 해시 알고리즘을 사용해서 완성되는 해시길이로 생성한다. ex ) SHA256 알고리즘은 32바이트 이기에 소금 값도 랜덤한 32바이트
유저별로 랜덤한 문자열을 생성
랜덤한 문자열을 만들어놓고 그 값을 그대로 재사용 해서는 안된다. 소금 값의 의미가 없어지는데, 예를 들어 하나의 유저의 비밀번호가 뚫렸다고 생각해보자
“hello”(비밀번호) + “adad”(소금)
해커는 hello라는 비밀번호에 대해 adad의 소금 값을 알아냈다.
모든 유저의 비밀번호를 하나의 소금값으로 사용
비밀번호가 유출된 유저가 비밀번호 재설정을 했을 때
위의 두가지 상황에서 해커는 소금값을 알기 때문에 쉽게 찾아낼 수 있을 것이다. 위와 같은 이유로 소금을 칠 때는 반드시 두가지 규칙(짧지 않은 소금 값, 재사용 금지)을 따라야 한다.
정리하면 다음과 같다.
소금값(Salt) 생성
사용자 계정을 생성하거나 비밀번호를 변경할 때, 새로운 임의의 랜덤 소금값을 생성합니다. 이 소금값은 절대 재사용하지 않으며, 충분히 길고 다양한 값을 가지도록 해야 한다. 일반적으로 소금값의 길이는 해시 함수의 출력 길이와 동일하게 해야한다.
비밀번호 해싱
사용자가 입력한 비밀번호에 생성된 소금값을 추가(일반적으로 결합)한 후, 그 결합된 값을 해시 함수에 전달하여 해시된 비밀번호를 생성한다.
저장
생성된 소금값과 해시된 비밀번호를 사용자 계정 테이블에 저장합니다. 이때 소금값은 별도로 저장되며, 해시된 비밀번호와 함께 보관.
우리가 알고있는 HTTP통신은 OSI 7계층의 응용계층에 속한다. 이 통신을 하기 위해 어떤 동작이 이루어지는지 키워드를 갖고 간단하게 다뤄보자
TCP(Transmission Controll Protocol)
TCP는 클라이언트와 서버간의 데이터 통신을 위해 사용하는 4계층에 속하는 프로토콜이다. HTTP는 기본적으로 통신을 하기 위해 TCP를 활용해 3-way-handshake 과정을 거쳐 TCP 소켓 연결을 하고 데이터를 전송한다.이후 소켓 연결을 해제할 때는 4-way-handshake 과정을 거쳐 연결을 해제한다.
3-way-handshake
TCP통신은 기본적으로 3방향 핸드셰이크라는 방식으로 네트워크 소켓연결을 시도하는데 SYN → SYN-ACK → ACK 의 순서로 진행된다.
소켓연결 후 소켓을 끊을 때는 4-way-handshake 과정을 진행한다. 여기서 사용하는 주요 FLAG는 FIN, ACK이 있다.
해당 연결해제 절차는 클라이언트 측과 서버 측 모두 사용 가능하기에 A, B로 설명하자면,
A(FIN) → B
B(ACK) → A
B(FIN) → A
A(ACK) → B
위의 순서를 통해 A와 B의 소켓이 해제되는데 최초 (1)FIN요청을 받은 B는 A에게 (2)ACK신호를 줌과 동시에 연결을 끊는 작업을 시행하고 연결을 종료할 수 있는 준비작업이 완료되면 B가 A에게 최종종료되었다는 (3)FIN FLAG를 넘겨준다. 이를 받은 A는 최종확인 (4)ACK FLAG를 B에게 보냄으로써 소켓은 서로 닫히게 된다.
HTTP 통신
HTTP통신으로 호출하기 위한 흐름은 기본적으로 TCP 소켓 연결을 기본으로 소켓연결이 된 후 Request & Response작업이 진행된다.
때문에 순서를 다시한번 적자면 이렇게 된다
3-way-handshake → Request → Response → 4-way-handshake의 순서로 통신 흐름을 이해할 수 있다.
HTTPS 통신
우리가 평소에 사용하는 사이트들은 모두 HTTP가 아닌 HTTPS를 사용하고있다. HTTPS는 Http에 S(Secure)가 붙어서 보안을 강화시킨 통신방식인데, 이 통신을 시행하면 중간에 데이터를 가로채가도 데이터는 암호화되어있기에 어떤 데이터를 가로챈건지 알 수 없게 되는 보안프로토콜이다.
이 통신방식은 Secure Sockets Layer(SSL)/Transport Layer Security (TLS) 등으로 불리우는 암호화 프로토콜통신(SSL Handshake, TLS Negotiation)을 HTTP통신의 데이터 교환에 앞서서 시행한다.
SSL Handshake, TLS Negotiation
이 통신을 SSL Handshake/TLS Negotiation이라고도 불리며, 기존의 소켓연결인 3-way-handshake 직후에 시행하는 통신작업인데, 순서는 다음과 같다.