저번 시간에는 HTTP 버전별 특징에 대해 공부했었죠. 이번 시간에는 그에 대한 후속작으로 SSL, TLS, HTTPS에 대해 다뤄보도록 하겠습니다. 아직까지 HTTPS에 대한 면접 질문은 받아본 적은 없지만 CS 측면에서도 꽤나 중요하고 비중이 있는 내용이기 때문에 면접 질문으로 나올 가능성은 충분히 있다고 생각합니다.
참고 : https://developer.mozilla.org/ko/docs/Glossary/HTTPS
HTTPS (HTTP Secure) 는 HTTP protocol의 암호화된 버전입니다. 이것은 대개 클라이언트와 서버 간의 모든 커뮤니케이션을 암호화 하기 위하여 SSL 이나 TLS을 사용합니다. 이 커넥션은 클라이언트가 민감한 정보를 서버와 안전하게 주고받도록 해줍니다.
HTTP 통신은 일반 텍스트를 이용해서 통신을 합니다. 예를 들어, 패스워드나 카드 번호 같은 중요한 정보가 있다면 어떻게 될까요? 누군가가 가로채기라도 한다면 큰일날 것입니다. 실제로 공용 Wi-Fi와 같이 안전하지 않은 매체를 통한 통신은 도청에 매우 취약합니다.
HTTPS를 사용하면 트래픽이 암호화되므로 패킷을 스니핑하거나 가로챈다고 해도 무의미한 문자로만 인식됩니다.
또한, HTTPS는 웹 서버를 인증해줍니다. 즉, 공격자들이 사용자를 속여 데이터를 훔치기 위한 가짜 웹사이트를 만드는 일이 있기 때문에, 이러한 인증이 중요합니다.
참고 : https://transparencyreport.google.com/https/overview?hl=ko
요즘에는 거의 대부분이 HTTPS를 제공합니다. 거의 95% 이상이라고 볼 수 있겠군요. 예전에는 그래도 HTTP로만 되어있는 사이트가 보였던거 같은데 어느 순간 사라진거 같더니... ㅎㅎ
사실 이는 브라우저의 역할이 컸습니다. 구글 크롬 브라우저가 HTTPS를 지원하지 않는 사이트를 엄중 단속했으며, 다른 브라우저도 그 뒤를 따랐습니다. 결국 이런 변화가 사용자까지 영향을 미쳤고, HTTPS 자물쇠 아이콘이 없는 웹 사이트를 경계하게 되었습니다.
참고 : https://developer.mozilla.org/ko/docs/Glossary/SSL
Secure Sockets Layer(SSL)는 클라이언트와 서버 간의 안전한 링크를 통해 송수신되는 모든 데이터를 안전하게 보장하는 과거의 보안 표준 기술입니다. SSL 버전 3.0은 Netscape가 1999년에 발표했으며 현재에는 Transport Layer Security (TLS) 로 대체되었습니다.
참고 : https://developer.mozilla.org/ko/docs/Glossary/TLS
참고2 : https://ko.wikipedia.org/wiki/전송_계층_보안
Transport Layer Security (TLS)는 어플리케이션들이 네트워크 상에서 안전하게 통신하기 위해 사용된 protocol이며, 이메일, 웹 브라우징, 메세징, 그리고 다른 프로토코들의 감청을 통한 정보의 변형을 방지합니다. 서버와 클라이언트가 TLS로 통신을 할때, 어떠한 제 3자도 메세지를 변형시키거나 감청할 수 없도록 합니다.
이 규약은 TCP/IP 네트워크를 사용하는 통신에 적용되며, 통신 과정에서 전송계층 종단간 보안과 데이터 무결성을 확보해줍니다.
대부분의 브라우저에서 TLS 1.0 와 1.1를 더 이상 지원하지 않으며 TLS 1.2 (2008) 나 TLS 1.3 (2018)을 사용해야 합니다.
참고 : https://www.cloudflare.com/ko-kr/learning/ssl/what-is-ssl/
사실 SSL의 최종 버전(3.0)과 TLS 첫 버전의 차이는 크지 않으며, 이름이 바뀐 것은 소유권 변경을 나타낸다고 하네요. SSL은 넷스케이프가 개발했으나 이후 넷스케이프가 떡락하면서... 더 이상 개발에 참여하지 못하게 되었으며 이 때문에 TLS로 바뀐 것이라네요.
이둘은 긴밀히 연계되어 있어 두 용어가 혼합되어 사용되는 경우가 많으며, TLS를 아직도 SSL이라고 부르기도 하고, SSL의 인지도가 높으므로, ‘SSL/TLS 암호화’라 부르는 경우도 있습니다. (하긴... SSL하면 바로 뭔가 떠오르는데 TLS라고만 하면 인지도가 떨어지긴 한듯)
먼저 암호화에 대해 알아보도록 하겠습니다.
암호화란 특별한 지식을 소유한 사람들을 제외하고는 누구든지 읽어볼 수 없도록 알고리즘을 이용하여 정보(평문을 가리킴)를 전달하는 과정입니다. 이에 역행하는 과정을 해독 또는 디크립션(decryption)이라고 하며 이로써 암호화된 정보를 다시 읽을 수 있습니다. - 위키피디아
고전 암호의 한계는 암호화 알고리즘을 알아내면 암호문을 해독이 가능하다는 점입니다. 이를 극복하는 현재 암호화 기술의 핵심은 임의의 문자열 값인 '암호화 키'입니다. 적절한 암호화 키를 사용한다면 암호화 알고리즘이 노출되더라도 키 없이는 해독할 수 없습니다.
암호화의 종류에는 크게 3가지가 있습니다. 단방향 암호화(해시), 비밀키 암호화(대칭 암호화), 공개키 암호화(비대칭 암호화)가 있죠. 여기서는 단방향 암호화를 제외한 나머지 2가지에 대해서 알아보겠습니다.
비밀키 암호화는 암호화와 암호 해독 모두에 동일한 (비밀) 키를 사용하기 때문에 대칭 암호화라고도 합니다. 따라서 비밀키 암호화를 위해서는 송신자와 수신자 모두 동일한 암호화 키를 알고 있어야 합니다.
장점으로는 비밀키의 크기는 공개키에 비해 상대적으로 작고 암호 알고리즘 내부 구조가 단순하여 암호화와 복호화 처리 속도가 공개키 암호화 방식에 비해 매우 빠릅니다. 반면 송신자와 수신자가 동일한 비밀키를 공유해야 하는데 비밀키를 분배하는 과정 중 누출이 되면 누구라도 암호문을 복호화할 수 있는 단점이 있죠. 관리 측면에서도 다수에게 공유해야 하는 경우 문제가 생길 확률이 더 높겠죠.
참고 : https://namu.wiki/w/공개키%20암호화%20방식 (나무위키가 은근 잘 되어있단 말이지...)
공개키 암호화는 공개키와 개인키라고 불리는 서로 다른 두 개의 키를 사용하기 때문에 비대칭 암호화라고도 합니다. 송, 수신자에게 공개된 공개키를 사용하여 암호화할 수 있지만, 복호화는 개인키를 가진 사람만 할 수 있습니다. (목적에 따라 그 반대도 가능한듯)
조금 더 복잡해 보이는 해당 방식은 비밀키 암호화 방식보다 처리가 느리기 때문에 실제 암호화 시스템은 비밀키 암호화 방식과 공개키 암호화 방식을 혼합하여 구축됩니다. SSL/TLS에서 두 당사자가 사용할 '대칭키(비밀키)'를 전달하는 용도로 사용됩니다.
기밀 내용의 전달 뿐만 아니라 "발행자의 증명 및 문서의 변조 방지"에서도 사용됩니다. 밑에 SSL 인증서에서 CA에 대해 나오는데 같이 살펴보면 좋을 거 같습니다.
참고 : https://www.cloudflare.com/ko-kr/learning/ssl/what-is-an-ssl-certificate/
HTTP에서 보다 안전한 HTTPS로 이동하려면 SSL 인증서가 필요합니다. SSL 인증서는 웹 사이트의 원본 서버에서 호스팅되는 데이터 파일입니다. SSL 인증서 덕분에 SSL/TLS 암호화가 가능하며, 인증서에는 웹 사이트의 공개 키와 웹 사이트의 신원 및 관련 정보가 포함됩니다. 원본 서버와 통신을 시도하는 장치는 이 파일을 참조하여 공개 키를 얻고 서버의 신원을 확인합니다. 개인 키는 안전하게 비밀로 보관됩니다. (중요한 핵심이 다 나왔네요)
웹사이트에서는 어떻게 SSL 인증서를 발급받을까요? SSL 인증서가 유효하려면 도메인이 인증 기관(CA)에서 인증서를 발급받아야 합니다. CA는 SSL 인증서를 생성하고 제공하는 신뢰할 수 있는 제3자 외부 조직입니다.
이미지 출처 : https://www.ssl.com/faqs/what-is-a-certificate-authority/
사용자(애플리케이션)은 CA에게 도메인 이름, 자신의 공개 키(개인 키는 비밀로 유지), 발급하는 사람(조직, 장치)에 대한 정보를 넘겨줍니다. 그러면 CA에는 발급한 인증 기관, 인증서 발급 날짜, 인증서 만료 날짜 등을 추가해서 자신의 개인 키로 암호화를 합니다.
예를 들어, 네이버 인증서를 보면 DigiCert Gobal Root CA라는 곳에서 발급받았나보네요.
공개키 암호화 알고리즘으로는 RSA를 사용했군요. 근데 SHA256은 단방향(해시) 알고리즘인데... 인증서 서명 알고리즘으로 사용됐군요. 근데 왜 사용하는거죠?? 🤔
참고 : https://epicarts.tistory.com/156
참고2 : https://eunhyee.tistory.com/209
이에 대해 별도로 찾아보니까 네이버가 인증서 정보를 CA에게 넘겨주기 전, Hash 알고리즘으로 암호화를 해서 서명(Signature)을 별도로 만드네요. 실제로 서명 값이라는게 있습니다.
그리고 나서 검증 단계에서는 인증서 안에 존재하는 데이터를 다시 Hash 함수를 통해 Hash 값을 구해서 둘의 Hash 값(서명 값)을 비교하여 검증을 하는군요. 오... 이를 통해 인증서의 무결성을 검증한다고 하네요. (음...굳이 안해도 될 거 공개키 암호화를 통해 무결성은 보장될 거 같지만... 2차 검증일까요? 근데 모든 사이트가 다 사용하는거 같네요. 필수인걸까요? 🤔)
아무튼 정리해보면 서명은 특정 메시지를 내가 작성했다는 것을 인증하는 역할을 합니다.
본격적으로 HTTPS 통신 과정을 살펴보겠습니다. TLS 핸드셰이크는 HTTPS 작동 원리의 근간을 이룹니다. TLS 핸드셰이크 중에, 통신하는 양측에서는 메시지를 교환하여 서로를 인식하고 서로를 검증하며 사용할 암호화 알고리즘을 구성하고 세션 키에 합의합니다.
TLS 핸드셰이크는 TCP 연결이 TCP 핸드셰이크를 통해 열린 후에 발생합니다.
클라이언트가 서버로 "헬로" 메시지를 전송하면서 핸드셰이크를 개시합니다. 이 메시지에는 클라이언트가 지원하는 TLS 버전, 지원되는 암호 제품군(암호화 알고리즘, Cipher suite), 그리고 "클라이언트 무작위(난수)"라고 하는 무작위 바이트 문자열이 포함됩니다.
클라이언트 헬로 메시지에 대한 응답으로 서버는 서버에서 SSL 인증서, 최적의 TLS 버전, 암호 제품군, 그리고 서버에서 생성한 또 다른 무작위 바이트 문자열인 "서버 무작위"를 포함하는 메시지를 전송합니다.
이 단계는 서로를 탐색하는 과정이라고 볼 수 있겠네요. 뭔가 소개팅에서 서로 인사하고 탐색하는 느낌이지 않을까요?
(엇... 왜 눈에서 눈물이..)
클라이언트가 서버의 SSL 인증서를 인증서 발행 기관(CA 공개키)을 통해 검증합니다. 이를 통해 서버가 인증서에 명시된 서버인지, 그리고 클라이언트가 상호작용 중인 서버가 실제 해당 도메인의 소유자인지를 확인할 수 있습니다.
인증서에는 서버의 공개키가 있기 때문에 'Server Key Exchange' 과정은 생략할 수 있습니다. 만약 서버의 공개키가 SSL 인증서 내부에 없다면, Server가 직접 전달해야 합니다. 아... 이게 키 교환 알고리즘이 Diffie-Hellman(DH, DHE 등)이라면 키 교환 재료를 서로 교환하게 되어 'Server Key Exchange'가 발생된다고 합니다. - 참고
이 단계에서는 몇가지 경우가 있는 거 같습니다. 이게 TLS 버전에 따라, 혹은 키 교환 알고리즘에 따라 다른거 같긴한데... 확실하진 않네요. (어렵...ㅠㅠ)
경우 1. RSA를 사용한 방법입니다. 클라이언트가 클라이언트 무작위 난수 + 서버 무작위 난수를 이용해 session key(암호화 키, 대칭 키)를 생성합니다. 그리고 나서 SSL 인증서에 있던 서버의 공개키를 통해 암호화해서 서버로 전송합니다. 서버 이외의 나머지는 개인키가 없으므로 복호화할 수 없습니다. 따라서 서버만이 개인키를 통해 복호화해서 세센 키를 받을 수 있습니다.
경우 2. RSA를 사용한 방법인거 같은데 조금 형식이 다릅니다. 클라이언트가 세션 키를 만들어서 서버에 전송하는 대신에, 클라이언트는 예비 마스터 암호(pre-master key)라고 하는 무작위 바이트 문자열을 하나 더 전송합니다. 마찬가지로 이를 암호화해서 서버에 전송합니다. 서버는 예비 마스터 암호를 해독합니다. 클라이언트와 서버가 모두 클라이언트 무작위, 서버 무작위, 예비 마스터 암호를 이용해 세션 키를 생성합니다. 모두 같은 결과가 나옵니다.
경우 3. Diffie-Hellman(DH, DHE 등)를 사용하는 방법입니다. Diffie-Hellman 알고리즘은 지수 계산을 이용해 동일한 예비 마스터 암호를 생성합니다. 서버와 클라이언트가 각자 계산을 위한 매개변수를 제공하고, 각자 서로 다른 계산 결과가 나오지만, 합치면 결과가 동일해집니다. (어휴... 이건 나중에 기회가 되면 별도로 다뤄야겠네요)
참고 : https://dokydoky.tistory.com/463 (여기 그림이 잘나와있네요)
클라이언트가 세션 키로 암호화된 "완료" 메시지를 전송합니다. 서버가 세션 키로 암호화된 "완료" 메시지를 전송합니다. 핸드셰이크가 완료되고, 세션 키를 이용해 통신이 계속 진행됩니다.
네트워크 왕복 횟수를 줄이기 위해 핸드셰이크를 최적화합니다. 위에서는 TLS 1.2에 대해 설명했는데 이는 TLS 1.2가 1.3 보다 설명하기 더 쉽기 때문입니다. TLS 1.2의 핵심 개념은 여전히 TLS 1.3에 적용됩니다.
그리고 RSA는 더이상 키 교환 방법으로 지원되지 않습니다. Diffie-Hellman(DH, DHE 등)이 요즘 세션 키를 교환하는 더 일반적인 방식입니다. 쉽게 말해 키를 전송하지 않고 키를 파생하기 위한 큰 소수와 일부 고급 수학을 사용합니다...
오랜만에 HTTPS에 대해 복습을 해서 좋았습니다. HTTPS를 보면 어떻게 암호화된 방식으로 통신을 할 수 있을까에 대한 많은 로직과 생각을 엿볼 수 있습니다. 그 덕분에 마음 놓고 쿠팡에서 물건을 사거나 할 수 있는거겠죠. ㅎㅎ
아.. 근데 이외로 TLS 핸드셰이크 과정이 경우, 알고리즘에 따라서 달라지다보니 조금 디테일하게 들어가다보면 어려운게 사실이네요. 나중에 기회가 된다면 후속편으로 작성해야 될 거 같습니다.
심화 : https://blog.naver.com/PostView.naver?blogId=aepkoreanet&logNo=221475942085
심화 2 : https://blog.naver.com/aepkoreanet/222114190722