SSL/TLS 동작 원리 쉽게 이해하기

SSL/TLS 동작 원리 쉽게 이해하기

인터넷에서 로그인을 하거나 카드 번호를 입력할 때, 그 정보가 내 컴퓨터에서 서버까지 가는 동안 누군가 몰래 들여다보고 있으면 큰일입니다. 실제로 암호화가 없던 시절에는 같은 와이파이를 쓰는 사람이 옆에서 패킷을 가로채면 비밀번호가 그대로 보였습니다. 이런 문제를 해결하기 위해 만들어진 게 SSL이고, 그 후속 버전이 TLS입니다. 이전 글에서 Let’s Encrypt로 인증서를 적용하는 방법을 다뤘는데, 이번 글에서는 그 인증서가 실제로 어떤 원리로 통신을 보호하는지를 정리해보겠습니다.

SSL과 TLS는 같은 건가 다른 건가

SSL(Secure Sockets Layer)은 1990년대에 넷스케이프에서 만든 암호화 프로토콜입니다. SSL 3.0까지 나왔고, 이후에 표준화 과정을 거치면서 이름이 TLS(Transport Layer Security)로 바뀌었습니다. TLS 1.0이 SSL 3.0의 후속 버전이고, 현재는 TLS 1.3까지 나와 있습니다.

엄밀히 말하면 SSL과 TLS는 다른 프로토콜입니다. SSL은 보안 취약점이 발견되어서 지금은 사용하지 않습니다. 현재 HTTPS에서 실제로 사용되는 건 전부 TLS입니다. 그런데 SSL이라는 이름이 워낙 오래 쓰여서 아직도 SSL 인증서, SSL 적용이라는 표현을 관행적으로 사용합니다. Let’s Encrypt에서 발급받는 것도 실제로는 TLS 인증서이지만 다들 SSL 인증서라고 부릅니다. 이 글에서도 편의상 SSL/TLS를 혼용하겠습니다.

암호화의 기본 개념 — 대칭키와 비대칭키

TLS의 동작 원리를 이해하려면 먼저 두 가지 암호화 방식을 알아야 합니다.

대칭키 암호화는 하나의 키로 암호화하고 같은 키로 복호화하는 방식입니다. 자물쇠와 열쇠가 하나인 것과 같습니다. 내가 데이터를 암호화해서 보내면 상대방도 같은 키를 가지고 있어야 복호화할 수 있습니다. 속도가 빠르다는 장점이 있지만, 문제는 그 키를 상대방에게 어떻게 전달하느냐입니다. 키를 전달하는 과정에서 누군가 가로채면 암호화가 무의미해집니다.

비대칭키 암호화는 키가 두 개입니다. 공개키와 개인키라고 부릅니다. 공개키로 암호화한 데이터는 개인키로만 복호화할 수 있고, 개인키로 암호화한 데이터는 공개키로만 복호화할 수 있습니다. 공개키는 말 그대로 누구에게든 공개해도 됩니다. 누군가 내 공개키로 데이터를 암호화해서 보내면 내 개인키를 가진 나만 복호화할 수 있으니까요. 키 전달 문제가 해결되지만 대칭키에 비해 속도가 느리다는 단점이 있습니다.

TLS는 이 두 가지를 조합해서 사용합니다. 비대칭키로 안전하게 대칭키를 교환하고, 이후 실제 데이터 전송은 빠른 대칭키로 암호화합니다. 두 방식의 장점만 취하는 구조입니다.

인증서는 무엇이고 왜 필요한가

비대칭키 암호화에서 공개키를 받았다고 해봅시다. 그런데 이 공개키가 정말 내가 접속하려는 서버의 것인지 어떻게 확신할 수 있을까요. 중간에 공격자가 자기 공개키를 대신 보내놓고 통신을 가로챌 수도 있습니다. 이걸 중간자 공격(Man-in-the-Middle Attack)이라고 합니다.

이 문제를 해결하기 위해 인증서가 존재합니다. 인증서는 “이 공개키는 이 도메인의 것이 맞다”고 신뢰할 수 있는 제3자가 보증하는 문서입니다. 이 제3자를 인증 기관(CA, Certificate Authority)이라고 합니다. Let’s Encrypt가 바로 CA 중 하나입니다.

인증서 안에는 여러 정보가 들어 있습니다. 도메인 이름, 서버의 공개키, 인증서를 발급한 CA 정보, 유효 기간, 그리고 CA의 디지털 서명이 포함됩니다.

디지털 서명은 CA가 자신의 개인키로 인증서 내용을 암호화한 것입니다. 브라우저는 CA의 공개키로 이 서명을 복호화해서 인증서 내용이 변조되지 않았는지 확인합니다. 브라우저에는 신뢰할 수 있는 CA들의 공개키가 미리 내장되어 있기 때문에 별도의 과정 없이 검증이 가능합니다.

TLS 핸드셰이크 과정

브라우저에서 https로 시작하는 주소에 접속하면 실제 데이터를 주고받기 전에 TLS 핸드셰이크라는 과정을 거칩니다. 이 과정에서 서버의 신원을 확인하고 암호화에 사용할 대칭키를 교환합니다.

TLS 1.2 기준으로 핸드셰이크 과정을 순서대로 설명하겠습니다.

첫 번째 단계는 Client Hello입니다. 브라우저가 서버에 접속 요청을 보내면서 자신이 지원하는 TLS 버전, 사용 가능한 암호화 방식 목록, 그리고 랜덤한 데이터를 함께 보냅니다. 이 랜덤 데이터는 나중에 대칭키를 만드는 데 사용됩니다.

두 번째 단계는 Server Hello입니다. 서버가 클라이언트가 보낸 목록 중에서 사용할 TLS 버전과 암호화 방식을 선택하고, 서버 쪽 랜덤 데이터와 함께 응답합니다. 이때 서버의 인증서도 함께 보냅니다.

세 번째 단계는 인증서 검증입니다. 브라우저가 서버로부터 받은 인증서를 확인합니다. 인증서가 신뢰할 수 있는 CA에서 발급한 것인지, 유효 기간이 지나지 않았는지, 인증서에 적힌 도메인이 접속하려는 도메인과 일치하는지를 확인합니다. 검증에 실패하면 브라우저가 경고 화면을 보여줍니다. 주소창에 “이 연결은 안전하지 않습니다”라고 뜨는 게 이 단계에서 검증이 실패한 경우입니다.

네 번째 단계는 키 교환입니다. 브라우저가 Pre-Master Secret이라는 랜덤 데이터를 생성하고, 서버의 공개키로 암호화해서 보냅니다. 서버만 자신의 개인키로 이걸 복호화할 수 있기 때문에 중간에 누가 가로채도 내용을 알 수 없습니다.

다섯 번째 단계는 대칭키 생성입니다. 클라이언트와 서버 양쪽이 Client Hello에서 보낸 랜덤 데이터, Server Hello에서 보낸 랜덤 데이터, 그리고 Pre-Master Secret 세 가지를 조합해서 동일한 대칭키(Session Key)를 만듭니다. 이 대칭키는 네트워크를 통해 직접 전달된 적이 없기 때문에 안전합니다.

여섯 번째 단계부터 실제 데이터 전송이 시작됩니다. 양쪽이 동일한 대칭키를 갖게 되었으니 이후의 모든 통신은 이 대칭키로 암호화됩니다. 비대칭키 암호화는 핸드셰이크 과정에서만 사용되고, 실제 데이터 전송은 속도가 빠른 대칭키 암호화로 처리됩니다.

TLS 1.3에서 달라진 점

TLS 1.2의 핸드셰이크는 클라이언트와 서버 사이에 두 번의 왕복(2-RTT)이 필요합니다. TLS 1.3에서는 이걸 한 번의 왕복(1-RTT)으로 줄였습니다. 클라이언트가 처음 요청을 보낼 때 키 교환에 필요한 정보를 미리 포함시키기 때문입니다. 핸드셰이크가 빨라졌다는 건 사이트가 처음 로딩되는 속도도 빨라졌다는 뜻입니다.

보안도 강화되었습니다. TLS 1.2에서는 다양한 암호화 방식을 지원했는데 그중 일부에 취약점이 발견되었습니다. TLS 1.3에서는 안전하지 않은 암호화 방식을 전부 제거하고 검증된 방식만 남겼습니다. 선택지가 줄었지만 그만큼 잘못된 설정으로 보안이 약해질 가능성도 줄었습니다.

이전에 같은 서버에 접속한 적이 있다면 0-RTT 연결도 가능합니다. 이전 세션에서 저장해둔 정보를 사용해서 핸드셰이크 없이 바로 데이터를 보낼 수 있습니다. 다만 0-RTT는 재전송 공격(Replay Attack)에 취약할 수 있어서 모든 상황에서 권장되는 건 아닙니다.

인증서 체인이란

인증서 검증 과정에서 한 가지 더 알아둘 게 있습니다. 실제로 서버의 인증서를 직접 발급하는 건 루트 CA가 아니라 중간 CA인 경우가 대부분입니다.

구조를 보면 이렇습니다. 루트 CA가 중간 CA에게 인증서를 발급하고, 중간 CA가 서버에게 인증서를 발급합니다. 서버가 브라우저에 인증서를 보낼 때는 서버 인증서와 중간 CA 인증서를 함께 보냅니다. 브라우저는 서버 인증서를 중간 CA의 공개키로 검증하고, 중간 CA 인증서를 루트 CA의 공개키로 검증합니다. 루트 CA의 공개키는 브라우저에 내장되어 있으므로 최종적으로 신뢰가 확보됩니다.

이렇게 루트부터 서버까지 이어지는 구조를 인증서 체인(Certificate Chain)이라고 합니다. 가끔 서버 설정에서 중간 인증서를 빠뜨리면 일부 브라우저에서 인증서 오류가 나는 경우가 있습니다. Let’s Encrypt와 Certbot을 사용하면 이 체인 설정을 자동으로 처리해주기 때문에 직접 신경 쓸 일은 많지 않지만, 문제가 생겼을 때 원인을 파악하려면 이 구조를 알아두는 게 좋습니다.

HTTPS에서 실제로 일어나는 일

브라우저에서 https://todayfunplay.com에 접속하면 위에서 설명한 모든 과정이 순식간에 일어납니다. TLS 핸드셰이크는 보통 수십 밀리초 안에 끝납니다. 사용자 입장에서는 아무것도 느끼지 못하지만, 그 짧은 시간 안에 서버의 신원 확인, 키 교환, 대칭키 생성이 전부 처리됩니다.

핸드셰이크가 끝나면 이후의 모든 HTTP 요청과 응답이 대칭키로 암호화되어 오갑니다. URL 경로, 헤더, 본문 전부 암호화됩니다. 중간에서 패킷을 가로채더라도 암호화된 데이터만 보이기 때문에 내용을 알 수 없습니다.

다만 접속하려는 도메인 자체는 핸드셰이크 초기 단계에서 평문으로 노출됩니다. 이걸 SNI(Server Name Indication)라고 하는데, 하나의 서버에서 여러 도메인을 호스팅할 때 어떤 도메인의 인증서를 보내야 하는지 알려주는 역할을 합니다. 어떤 사이트에 접속하는지는 보이지만 그 안에서 어떤 페이지를 보는지나 어떤 데이터를 주고받는지는 보이지 않습니다. 이 부분도 암호화하는 ECH(Encrypted Client Hello)라는 기술이 개발 중입니다.

SSL/TLS 관련 서버 설정 확인

이전 글에서 Certbot으로 인증서를 적용한 뒤에 Nginx 설정 파일을 보면 Certbot이 추가한 SSL 관련 설정이 보입니다. ssl_certificate와 ssl_certificate_key가 인증서 파일과 개인키 파일의 경로입니다. ssl_protocols에는 허용할 TLS 버전이 적혀 있습니다.

보안을 위해 TLS 1.0과 1.1은 비활성화하고 TLS 1.2와 1.3만 허용하는 게 좋습니다. 최신 Certbot을 사용했다면 이미 이렇게 설정되어 있을 가능성이 높지만 한 번 확인해보는 걸 추천합니다.

서버의 SSL 설정 상태를 외부에서 확인하고 싶으면 SSL Labs의 SSL Server Test 사이트에서 도메인을 입력하면 됩니다. 인증서 상태, TLS 버전, 암호화 스위트, 알려진 취약점 여부를 분석해서 A부터 F까지 등급을 매겨줍니다. A 이상이 나오면 안심해도 됩니다.

마무리

SSL/TLS는 결국 두 가지 문제를 해결합니다. 첫째, 통신하는 상대방이 진짜 그 서버가 맞는지 확인하는 것이고, 둘째, 주고받는 데이터를 제3자가 볼 수 없도록 암호화하는 것입니다. 비대칭키로 안전하게 대칭키를 교환하고, 대칭키로 빠르게 데이터를 암호화하는 구조입니다. 인증서는 서버의 공개키가 진짜인지 CA가 보증하는 역할을 합니다. 개념이 복잡하게 느껴질 수 있지만 핵심은 이겁니다. 인증서로 신원을 확인하고, 키를 교환하고, 암호화된 통신을 시작한다. 다음 글에서는 네트워크 기초에서 중요한 서브넷과 CIDR 표기법에 대해 다뤄보겠습니다.

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *