HTTP의 보안상 취약한 부분을 강화한 프로토콜이 바로 HTTPS(HyperText Transfer Protocol over Secure Socket Layer)입니다.
HTTP는 리소스를 암호화하지 않은 상태로 전송하기 때문에 제 3자에 의해 감청당하거나 데이터 변조와 같은 보안문제가 일어날 가능성이 있습니다. HTTPS는 SSL(Secure Socket Layer)라 불리는 프로토콜 위에서 동작하여 HTTP의 보안상 취약점을 보완해 리소스를 전송합니다.
참고로 HTTP는 well-known 포트로 80번을 사용하지만, HTTPS는 443번을 사용합니다.
SSL 동작과정을 이해하기 위해서는 알아야 할 몇 가지 개념들이 있습니다. 이들을 먼저 살펴보고, SSL이 어떻게 동작하는지 자세히 살펴보겠습니다.
대칭키 암호화(비밀키 암호화)는 평문을 암호화할 때, 반대로 암호문을 복호화할 때 사용하는 키(Key)가 동일한 암호화 방식을 말합니다.
대칭키 암호화 방식은 데이터를 변환하는 방식(알고리즘)에 따라 블록암호와 스트림암호로 구분됩니다.
출처: https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation
평문 데이터를 특정 길이(N)의 비트들로 쪼개서 블록 단위로 만들고, 이렇게 쪼개진 블록들을 암호화하는 방식입니다. 블록암호에는 운용 방식(mode)이라는 것이 있습니다. 운용 방식은 쪼개진 블록들을 어떻게 암호화할 것인지 결정하는 요소입니다. ECB, CBC, CFB 등 여러 방식이 있지만, 여기서 설명하는 것은 주제에서 벗어나므로 자세한 설명은 생략하겠습니다.
대표적인 블록 암호화 방식으로는
출처: https://thisismyclassnotes.blogspot.com/2017/05/cryptography-stream-ciphers-and-its.html
의사난수(Pseudorandom) 스트림을 만들어서, 평문 데이터와 결합(보통은 xor 연산을 사용)하여 암호화하는 방식입니다. 의사난수 스트림은 keystream이라 불리며, 이를 어떻게 생성하느냐에 따라 동기식과 비동기식으로 나뉘지만, 주제에서 벗어나므로 자세한 설명은 생략하겠습니다.
대표적인 스트림 암호화 방식으로는
대칭키 암호화 방식과 달리, 공개키 암호화(비대칭키 암호화) 방식은 평문을 암호화할 때와 암호문을 복호화할 때 사용하는 키가 서로 다른 암호화 방식입니다. 즉, 두 가지의 키를 사용하는 방식입니다.
하나는 타인에게 제공되는 공개키(Public Key)이고, 다른 하나는 자신만이 가지는 개인키(Private Key, 비밀키, 비공개키)입니다. 공개키로 암호화한 것은 개인키로 복호화할 수 있고, 개인키로 암호화한 것은 공개키로 복호화할 수 있습니다. 공개키로 암호화된 내용은 개인키가 유출되지 않는 한 복호화할 수 없기 때문에, 공개키는 아무리 노출되더라도 안전합니다.
해시함수란, 임의의 길이를 가진 메시지를 일정 길이(n 비트)의 메시지롤 변환하는 함수를 말합니다. 해시함수의 출력결과로 나오는 n 비트의 메시지를 해시값(Hash value 혹은 다이제스트, Digest)라 부릅니다.
(암호학에서의) 해시함수는 단방향성이며, 단방향성이란 해시값으로부터 원본 메시지를 역산할 수 없다는 특징을 가집니다.
대표적인 해시함수는
하나의 원본 메시지는 단 하나의 해시값을 갖지만, 반대로 하나의 해시값은 여러 개의 원본 메시지를 가질 수 있습니다. 서로 다른 메시지가 동일한 해시값을 가지면 이를 충돌(Collision)이라 부릅니다. 보통 해시함수는 메시지의 무결성을 검증하는데 많이 사용하기 때문에, 충돌 가능성 최소화하는 것은 해시함수에게 매우 중요한 요소입니다.
말 그대로 메시지를 인증할 때 사용하는 코드를 의미합니다. MAC은 해시함수를 활용하여 전달받은 메시지의 송신자가 정상적인 사용자인지 인증합니다.
출처: https://en.wikipedia.org/wiki/Message_authentication_code
송신자와 수신자가 같은 키, 같은 MAC 알고리즘을 공유하고 있다고 가정합니다.
위 방식은 MAC 알고리즘을 해시함수를 사용하는 HMAC 방식입니다.
실세계의 서명과 동일하다고 생각하면 됩니다. 다만, 서명의 대상이 서류가 아닌 전자적인 데이터이고 서명을 펜으로 하지 않는다는 점이 다르겠네요. 서명을 통해 서명자의 신원을 확인하고, 서명한 서류의 내용을 서명자가 승인하였음을 나타낼 수 있습니다.
전자서명은 크게 두 가지 과정이 있습니다. 데이터를 서명하는 과정(1 ~ 2)과 서명을 검증하는 과정(3 ~ 4)입니다.
참고로 위 과정은 디지털 서명로 구현된 전자서명입니다.
송신자는 서명 알고리즘(Signing algorithm)을 통해 보낼 메시지에 서명을 합니다. 보통 서명 알고리즘은 위 그림과 같이 원본 메시지를 해시함수에 입력하여 해시값을 만듭니다. 그 후, 송신사의 개인키를 이용해 암호화합니다.
이렇게 암호화된 해시값(서명)을 원본 메시지 끝에 첨부하여 전자서명된 데이터를 만듭니다. 그리고 이를 수신자에게 전송합니다.
수신자는 전자서명된 데이터를 메시지와 서명으로 분리합니다. 메시지는 (서로 공유하고 있는) 해시함수에 입력하여 해시값(A)를 만듭니다. 그리고 서명은 송신자의 공개키를 통해 복호화(B)합니다.
A와 B를 비교하여 서명이 정상적인지 판단합니다. 같다면, 서명이 정상적인 것입니다.
일단 SSL과 TLS은 같은 말이다. SSL이 넷스케이프에 의해 만들어지고 관리되다가 표준화 기구인 IETF(Internet Engineering Task Force, 국제 인터넷 표준화 기구)에게 넘어가면서 TLS(Transport Layer Security)라는 이름으로 변경되어 관리되고 있다.
출처: https://blog.cloudflare.com/keyless-ssl-the-nitty-gritty-technical-details/
클라이언트가 서버에 접속한다. Client Hello단계라 불리며, 이 때 클라이언트는 서버에게 다음과 같은 정보를 보낸다.
SSL버전
클라이언트에서 생성한 랜덤 데이터(난수)
클라이언트가 지원하는 암호화 방식 (Cipher suites)
이 정보를 보내는 이유는 상호 간 어떠한 암호화 방식을 사용할 것인지 협상하기 위해서입니다. 왜냐하면 서버와 클라이언트가 지원하는 암호화 방식의 차이가 있을 수 있기 때문입니다.
협상해야할 암호화 알고리즘은 4가지입니다.
대칭키 교환에 사용할 암호화 알고리즘
인증서 서명 알고리즘
대칭키 알고리즘
MAC 알고리즘
세션 아이디 (optional)
서버는 Client Hello단계에 대한 응답으로 Server Hello 절차를 수행합니다. 이 때 서버가 클라이언트에게 건네는 정보는 다음과 같습니다.
클라이언트는 서버로부터 받은 인증서를 검증한다.
인증서가 정상적으로 검증되었으면, 클라이언트는 pre master secret라 불리는 랜덤 데이터를 하나 생성합니다. 인증서에 담겨있는 서버의 공개키를 이용해 pre master secret을 암호화하고 서버에게 전송합니다.
클라이언트로부터 받은 pre master secret을 서버 자신의 개인키로 복호화합니다. 이로써 pre master secret을 서버와 클라이언트가 모두 공유합니다. 서버와 클라이언트는 PRF(PseudoRandom Function) 알고리즘으로 pre master secret을 master secret 값(48bytes)으로 만듭니다.
master_secret = PRF(pre_master_secret, "master secret",
ClientHello.random + ServerHello.random)[0..47];
이렇게 만든 master secret를 통해 session key를 생성하고, 서버와 클라이언트는 Session key를 사용하여 대칭키 암호화 방식으로 데이터를 암호화하여 통신합니다.
key_block = PRF(SecurityParameters.master_secret,
"key expansion",
SecurityParameters.server_random +
SecurityParameters.client_random);
client_write_MAC_key[SecurityParameters.mac_key_length]
server_write_MAC_key[SecurityParameters.mac_key_length]
client_write_key[SecurityParameters.enc_key_length]
server_write_key[SecurityParameters.enc_key_length]
client_write_IV[SecurityParameters.fixed_iv_length]
server_write_IV[SecurityParameters.fixed_iv_length]
서버와 클라이언트 handshake 단계의 종료를 서로에게 알립니다.
세션 단계는 실제 서버와 클라이언트가 데이터를 주고 받는 단계입니다. 위에서 언급한 것처럼 Session key를 사용하여 대칭키 암호화 방식으로 데이터를 암호화하여 통신합니다
데이터 전송이 끝나면 SSL 통신이 끝났음을 서로에게 알려주고, 이 때 통신에서 사용한 대칭키인 session key를 폐기합니다.