데이터를 주고 받을 때, 암호화 하는 일반적인 방법에 대해. 과거에는 SSL(Secure Sockets Layer)라는 이름으로 불렸음.

7 minute read

데이터를 주고 받을 때, 암호화 하는 일반적인 방법에 대해. 과거에는 SSL(Secure Sockets Layer)라는 이름으로 불렸음.

데이터 전송의 암호화는 아래와 같은 순서로 발전한다.

  1. 평문으로 데이터 주고 받기
  2. 암호화 해서 주고 받기
    • 동일한 암호키(encryption key)를 사용하기
    • Q. 암호화 키를 어떻게 전달할 것인가?
  3. 비대칭키(공개키/개인키)를 통해 주고 받기
    • 개인키(private key)가 있는 서버만 평문 내용을 알 수 있다.
    • Q. 통신 하는 대상인 서버는 믿을만 한가?
  4. 인증서(certificate)를 함께 전송하기
    • CA(Certificate Authority, 인증 기관)를 통해 신용을 확보한다.

평문으로 데이터 주고 받기

유저와 서버가 데이터를 평문으로 주고 받는다면, 통신이 감청 되었을 때 주고 받는 정보가 그대로 보인다. 😵

암호화 해서 주고 받기

유저와 서버는 미리 정해둔 암호키(encryption key)를 사용해서 정보를 암호화 한다. 암호화된 데이터는 통신이 감청되어도 정보를 알 수 없다.

유저와 서버가 오프라인에서 미리 아는 사이라면, 암호키를 미리 정해둘 수 있을 것이다. 그러나 99.9%의 유저-서버 쌍은 서로 처음 본다. 즉, 둘 사이에 미리 정해둔 암호키가 존재할 수 없다!

만약 통신 초기에 암호키를 인터넷을 통해 주고 받는다면, 통신 감청을 통해 암호키가 노출될 수 있다. 🥷 이러면 헛수고다!

비대칭키를 통해 주고 받기

서버는 개인키(private key)공개키(public key)를 만든다. 통신을 준비할 때, 서버는 유저에게 서버 공개키를 보낸다. 유저는 서버의 공개키로 암호키를 암호화 해서 보낸다.

비대칭키로 암호화 되었으므로 유저가 서버 공개키로 암호화한 값은 서버 개인키가 있는 서버 자신만 해독할 수 있다.

이제 해독한 암호키로 데이터를 암호화하여 서로 통신 한다.

그런데, 해커가 트래픽을 조정해서 서버 자체를 사칭 한다면? 🥷 그러면 유저가 사칭한 서버를 믿고, 사칭 서버의 공개키로 암호키를 암호화해서 전달하게 된다. 그러면 사칭한 서버가 사칭 서버의 개인키로 암호키를 해독할 수 있게 된다!

SSL 인증서로 자신을 증명하기

통신을 시작할 때, 서버는 “SSL Certificate”를 유저에게 보내어 자신이 진짜 서버임을 증명한다.

유저는 서버 인증서를 보고, 통신하는 서버가 사칭 서버가 아닌 실제 서버인지 확인한다. 실제 서버인지 확인 했다면, 비대칭키 방식으로 보안 연결을 수립하고 통신한다.

유저는 서버 인증서를 어떻게 검증하는가? feat. PKI

서버가 SSL 인증서를 유저에게 보냅니다. 그러면 유저는 인증서의 내용에서 아래의 3단계를 확인하여 실제 서버가 보낸 인증서인지 확인 합니다.

순서는 체크하기 쉬운 것부터 제가 재배열 했습니다. 실제 검증 순서는 다를 수 있습니다.

  1. 유효 기간 확인
    1. 전달 받은 인증서가 현재 날짜 기준으로 만료되지 않은 것인지 체크합니다.
  2. 도메인 이름 일치 확인
    1. 인증서에 있는 도메인 이름(CN 또는 SAN 필드)이 실제 접속한 URL과 일치하는지 체크합니다.
  3. CA(인증기관)의 서명 확인
    1. 유저는 인증서의 디지털 서명(signature)을 확인하여 인증서가 신뢰할 수 있는 CA에서 발급한 것인지 확인합니다. “서버 인증서의 검증” 문단에서 자세히 다룹니다.
    2. 유저는 신뢰하는 CA의 공개키 목록을 내장하고 있어서 이를 이용해 서명을 검증 합니다.

서버 인증서와 CA

CA(Certificate Authority)는 신뢰할 만한 인증 기관으로, 서버 인증서를 발급해준다. 서버 인증서에는 아래의 내용이 들어있다.

  • 인증서 소유자 이름
    • Common Name(CN)
  • 인증서 소유자의 공개키
    • 당연히 소유자의 개인키는 노출되지 않는다!
  • 인증서의 유효기간
  • CA의 디지털 서명(signature)
    • 소유자의 공개키를 CA의 비밀키로 암호화
    • 해커가 절대 위조할 수 없음!
    • 이후 검증 과정에서 브라우저에 내장된 CA의 공개키로 해독하여 사용합니다.
  • CA 서명의 해싱 알고리즘
    • ex. SHA-256

깃헙 블로그에서 사용하고 있는 SSL 인증서

이 내용은 CA의 개인키로 암호화 되어 서버에서 파일로 보관했다가 유저와 통신할 때 사용한다.

서버 인증서의 검증

깃헙 블로그에서 사용하고 있는 SSL 인증서 (Detail)
signature 값은 HEX 값으로 인코딩 되어 있습니다.

유저는 서버의 인증서를 받았다. 유저는 서버 인증서에 담긴 CA의 서명(signature)을 CA의 공개키로 복호화 한다. CA의 공개키는 브라우저에 내장되어 있다.

ssl_cert = GetSSLCert()

CA_signature = ssl_cert.GetCASignature()  # HEX encoded
CA_public_key = GetCAPublicKeyFromBrowser()
hash_from_CA = do_decrypt(CA_signature, CA_public_key)

server_public_key = ssl_cert.GetServerPublicKey()
CA_hash_algorithm = ssl_cert.GetCAHashAlgo() # SHA-256
hashed_server_pk = do_hashing(server_public_key, CA_hash_algorithm)

if hash_from_CA == hashed_server_pk:
  print("Truth Certificate!")
else:
  print("Hacker!!")

사칭된 서버 공개키를 썼다면?

해커가 인증서에 흠집을 냈다고 생각해보자.

해싱의 원리에 의해 해싱키가 다르면, 해싱 값이 다르게 나온다. 즉, 올바른 서버 공개키가 적혀있지 않으면, 서명을 복호화한 hash_from_CA의 값과 맞지 않게 된다.

정말로 사칭하고 싶다면, do_hashing()의 값이 hashed_server_pk가 되는, 실제 서버 공개키와는 다른, 공개키-비밀키 쌍을 찾아야 한다. 그러나 이것은 불가능하다.

사칭된 서명을 썼다면?

CA 공개키는 누구나 다 알고 있으니, 사칭된 서명도 복호화할 수는 있다. 그러나 복호화된 값이 실제 공개키의 해싱 값 hashed_server_pk와 맞지 않는다.

정말로 사칭하고 싶다면, do_decrypt()의 값이 hash_from_CA이 되는 실제 CA 서명과 다른 서명값을 찾아야 한다. 그러나 이것은 불가능하다.

서버 인증서를 그대로 쓴다면?

“에라 모르겠다!”하고 서버 공개키도 CA 서명도 위조 할 수 없음을 깨달은 해커는 올바른 서버 인증서를 그대로 사칭 서버에서 그대로 쓰기로 마음 먹었다.

그러나 이 방식으로 유저의 CA 검증은 통과해도, 실제 서버 공개키에 대응되는 실제 서버 비밀키를 모르기 때문에 유저가 보낸 암호키를 제대로 복호화 할 수가 없다.

결론: 사칭은 불가능하다

결국 (1) 해싱 알고리즘의 단방향 암호화, 그리고 (2) CA 비밀키를 알 수 없다는 점 때문에 해커는 공개키와 CA 서명 어떤 것도 흠집을 낼 수 없다.

맺음말

SSL/TLS 암호화는 개발하면서 정말 기본적으로 사용하는 것임에도 불구하고, 시간이 지나면 원리를 까먹고 다시 공부하게 되는 것 같습니다 ㅋㅋ

예전에 CKA 시험을 준비할 때, 이 부분 때문에 머리가 엄청 아팠던 기억이 있는데, 이번에 CCDAK 시험을 준비와 회사에서 Kafka 클러스터의 인증서를 구축하면서 다시 이 부분을 복습하고 있습니다… ㅋㅋ

잘 모르는게 있을 때, 다시 초심으로 돌아가서 보면 되니까요!! ㅎㅎ 오늘도 아좌잣!!


후속 글로 openssl 도구를 사용해서 SSL/TLS를 세팅하는 방법에 대해 정리해보았습니다 ㅎㅎ

➡️ Hello, OpenSSL!

Categories:

Updated: