[Security-12] TLS 1.2 Pt.2

유영석·2023년 1월 25일
0

Security

목록 보기
12/12
post-thumbnail

자, 그렇다면 서버에서 온 공개키는 어떻게 인증할 수 있을까요? 조금 더 일상에서의 예로 내가 취업하고 싶은 회사에 졸업장을 낼 때 그 졸업장이 진짜인지를 회사는 어떻게 판단할 수 있을까요? 졸업장 밑에 총장의 서명을 보고 판단합니다. 서버의 공개키 안에는 내가 신뢰하는 주체의 메세지가 서명이 되어있는 겁니다. 이와 같은 구조를 Public Key Infrastructure(PKI) 라고 합니다.

Public Key Infrastructure(PKI)

아래 간단한 예시를 봅시다.

클라이언트는 서버 1 과 secure connection 을 맺고 싶습니다. 그 때 서버 2 가 나타나 connection request 를 가로채고 서버 1 과 따로 TLS connection 을 맺고 클라이언트에게는 자신의 certificate(인증서) 를 주는 겁니다. man in the middle 과 같이 행동하는 것이지요.

그래서 Server Authentication 과정이 필요한 것입니다.

즉, 클라이언트에서 자신이 원하는 정확한 서버와 연결됬는 지를 알 수 있는 방법이 있어야 합니다. 기본적으로 클라이언트는 서버의 인증서를 보고 인증을 합니다. 어떻게 하냐고요? 인증서에는 Common Name[CN] 이라는 영역이 있습니다. 이 값이 서버 1의 도메인 이름 과 매치하는지를 확인하는 것입니다. 아니 그러면 서버 2 가 자신의 인증서의 Common Name 을 바꾸면 되지 않겠냐고요? 그것을 방지해주는 것이 바로 이번에 배울 PKI 인 것입니다.

Chain of Trust

PKI 를 위해 먼저 알아야 할 개념이 바로 Chain of Trust 입니다. 간단한 예를 들어보죠.

Alice 와 Charlie 가 있습니다. 이 둘은 서로 만나본 적이 없기에 서로의 공개키를 신뢰하지 않고 있는 상태입니다. 하지만 둘은 모두 믿음직스러운 친구 Bob 이 있습니다. Charlie 는 Bob 에게 그의 공개키를 Bob 자신의 개인키로 서명해달라고 부탁합니다. 이를 가지고 Charlie 는 Alice 에게 Bob 의 서명이 첨부된 자신의 공개키를 보내는 겁니다. 그러면 Alice 는 Charlie 의 공개키에 있는 Bob 의 서명을 보고 Charlie 를 신뢰할 수 있게 되는 것입니다. Alice 가 Bob 을 신뢰하고, 그 Bob 이 Charlie 를 신뢰하는 연결성에 의해 Alice 는 Charlie 를 신뢰할 수 있게 됩니다. 신뢰의 관계가 체인처럼 연결되어 있다 하여 이를 Chain of Trust 라고 합니다.

이를 인터넷에 적용해 봅시다. 브라우저가 믿는 TTP(trusted third party)Certificate Authority(CA) 라고 합니다. CA 는 사이트들을 확인하고 신뢰할 수 있다고 판단되면 해당 사이트의 공개키에 대한 서명을 만들어줍니다. 그러면 사이트는 공개키와 서명으로 인증서를 만드는 것이죠. 브라우저가 자신이 믿는 CA 의 공개키를 로컬 파일에 저장해 둡니다.

조금 더 자세히 들여다 볼까요? CA 중에서도 직접 사이트의 인증서를 만들기 위한 서명을 해주는 곳은 중간 단계인 Intermediate CA 입니다. 그러면 이 Intermediate CA 는 어떻게 인증하고 신뢰할 수 있을까요? 이 Intermediate CA 의 인증서는 또 Root CA 라는 최상단의 CA 에서 인증 및 서명을 해줍니다. 그리고 브라우저에는 바로 이 Root CA 의 인증서가 브라우저에 저장되어 있는 것이지요.

이와 같이 공개키에 대한 신뢰의 계층적인 구조를 Public Key Infrastructure 이라고 하는 겁니다. Root CA 의 공개키는 왼쪽 아래와 같이 브라우저와 OS에서 로컬 하드 코딩으로 박혀 있습니다.

어떤 사이트에 Certificate 에 서명이 로컬에 저장되어 있는 Root CA 의 것이 아닐 수 있습니다. 그러면 인증이 될 수가 없죠. OS 가 윈도우라면 Windows 에서 안깔아 준 겁니다. 그렇기 때문에 어떤 사이트에 접속시키기 위해 새로운 Root CA 의 public key 를 강제로 박는 경우도 있는데 그것이 바로 한 번 쯤은 설치해보셨을 만한 대한민국의 ActiveX 입니다. 별로 이상적인 방법은 아니겠죠....? 😅 그리고 오른쪽을 보면 Certificate 의 내용을 확인해볼 수 있습니다. www.amazon.com 에서 클라이언트에게 제공하는 인증서가 되겠네요. 보시면 공개키와 서명 뿐 아니라 발행한 Root CA 는 Verisign 사인 것을 확인할 수 있습니다. 서명 알고리즘은 SHA-1 을 RSA 와 함께 사용했다는 내용도 있구요.

또 다른 얘기를 해봅시다.

예전에는 이와 같이 하나의 서버, 즉 하나의 IP 주소로 서로 다른 포트 번호를 사용해서 각기 다른 사이트를 돌렸습니다. 여러 웹사이트(호스트) 들이 포트 번호로 구별되었던 것이지요. 그런데 당연히 대부분의 웹사이트가 HTTP 를 의미하는 80 번 포트 번호를 쓰고 싶지 않을까요?

이것은 Virtual Hosting 기술이 도입된 이후 해결이 되었습니다. 같은 포트 번호 80을 가상화하여 여러 웹사이트가 쓸 수 있도록 한 것입니다. HTTP request 헤더에 어떤 호스트에 연결한 것인지를 명시하여 연결이 되었습니다. 그런데 여기서 우리의 TLS 가 도입되기 시작합니다. TLS 에서 HTTP request 는 모든 Handshake 과정이 끝난 뒤에 보내는 것임을 압니다. 서버가 인증서를 주어야 하는데 어떤 사이트에 접속하는 지를 뒤에 알 수 있는 모순이 생긴 겁니다.

그래서 만들어진 해결책 중 하나가 왼쪽의 Wildcard Certificate 입니다. 기존의 도메인 네임으로 사용하였던 CN(Common Name) 을 무르고, 와일드카드 도메인 네임을 사용한 것입니다. 그래서 *.domain.com 에 대한 인증서로 www.domain.com 뿐만 아니라 mail.domain.com 과 같은 subdomain 레벨까지 보호할 수 있게 된 것입니다. 그리고 여기서 subdomain 뿐만 아니라 다른 여러 도메인 네임도 포함하기 위해 만들어진 것이 Subject Alternative Name 입니다. 오른쪽과 같이 하나의 인증서에 IP 주소, 도메인 네임(common name)들이 명시되어 있도록 한 것입니다. 그런데 이렇게 되면 어떤 사이트가 들어오거나 빠지게 되면 일일히 인증서를 업데이트 해야하는 문제에 직면하게 됩니다. 또한, 다른 사이트들과 인증서로 엮이기 싫은 경우들도 많을 것이구요.

그래서 결국 돌고 돌아 2003 년도 TLS 를 확장하여 Handshake 의 첫 번째 패킷인 client_hello 에 브라우저가 도메인 네임을 명시해주는 필드인 Server Name Indication(SNI) 가 도입되었습니다. 그런데 이 패킷은 평문으로 날라가기 때문에 누구든 감시가 가능하게 됩니다. 그래서 어떤 사이트에 접속하는 지를 감시하여 차단하는 것이 인터넷을 사용하면서 한 번쯤은 봤을 만한 아래와 같은 화면이 되는 것입니다.

그런데 이것은 악용되면 공격자가 호스트의 웹 기록을 볼 수 있다는 뜻이 되기도 하겠지요? 그래서 TLS 1.2 의 다음 버전인 1.3 에서는 Encrypted SNI(ESNI) 가 도입되게 됩니다. 도메인 네임을 가지고 사이트에 접속하기 위해서는 가장 먼저 도메인 서버를 방문하여 IP 주소를 가져와야 합니다. 이 때 도메인 서버가 준 공개키를 주고 이를 이용해 개인키를 만들어 암호화하는 것입니다. 그런데 굳이 SNI 를 보지 않더라도 도메인 서버에 날라가는 쿼리를 보고 접속하고 싶은 사이트를 확인할 수도 있겠지요? 그래서 그냥 아예 client_hello 를 암호화한 Encrypted Client Hello(ECH) 를 사용합니다. 이 도메인 자체가 보안에 많이 쥐약이기 때문에 최근에 도메인 네임 자체를 TLS 로 암호화한 DoH(Domain over HTTPS)/DoT(Domain over TLS) 사용이 가능합니다. 이렇게 하면 거의 모든 곳이 다 뚫리죠.

이렇게 서버가 CA 로부터 서명을 받는 것을 CSR(Certificate Signing Request) 이라고 합니다. 서버(위의 그림, CA 입장에서는 서버가 클라이언트) 는 자신의 개인키와 공유키 쌍을 생성합니다. 이 공유키를 CA (root/intermediate) 에게 제출하여 certificate 를 받는 과정이 CSR 인 것입니다. 물론 개인키는 웹사이트에서 안전하게 보관을 해두겠죠? 이런 CSR 과정은 사실 OpenSSL 의 명령어들 중 하나입니다. 그래서 누구나 손쉽게 할 수 있는 것이죠. 그렇기에 CA 가 아닌 자기 자신이 공개키에 대해 서명을 할 수도 있게 되는 겁니다. 물론 그러면 오른쪽과 같이 인증서가 유효하지 않다는 화면을 마주치게 되겠지만요.

profile
백엔드 개발자

0개의 댓글