TLS(Transport Layer Security)는 두 엔드포인트 간에 통신을 암호화하는 데에 사용되는 기본적인 프로토콜이다.
암호화되지 않은 일반 데이터(IP패킷)를 그냥 전송하면 위험하기 때문에 암호화가 필요하다.
그런데 통신을 하는 사람들마다 암호화하는 방법이 모두 다르면 혼란이 오기 때문에 암호화 표준이 필요했고 이걸 위해 TLS가 생겨났다.
인터넷 통신에서 HTTPS 기반으로 굉장히 많은 통신이 이루어지고, 이때 사용되는 암호화방식이 TLS이므로 공부할 필요가 있을 것 같다.
HTTP
HTTP통신은 기본적으로 아래와 같이 이루어진다.
1. HTTP연결을 위해서 TCP연결을 수립한다.(HandShake)
2. 연결 후에 [GET / **] 형태의 데이터를 보내게 될텐데, MTU에 따라서 하나 이상의 TCP세그먼트로 전송될 것이다.
HTTPS
만약 여기에 암호화가 추가 된다면 어떻게 될까?
1. 먼저 암호화를 위한 HandShake과정을 거치게 되는데, 이때 대칭키를 공유하게 된다.(클라이언트 - 서버 둘 다 같은 키를 가지고 있음)
-> 대칭키 암호화 알고리즘이기 때문에 같은키로 암호화하고 같은 키로 복호화할 수 있다.
2. 클라이언트가 암호화해서 전송한 데이터를 서버는 복호화해서 처리하고, 결과를 암호화하여 클라이언트에게 전송한다.
알고리즘 방식에는 아래와 같이 2가지 방식이 존재한다.
[대칭키 알고리즘]
1. XOR연산을 사용하고, 키를 사용하여 내용을 암호화하기 때문에 매우 빠르다.
[비대칭키 알고리즘]
1. 암호화키와 복호화키가 따로 있다.
2. 보안성 때문에 인기있지만, 지수 함수에 의존(CPU연산을 더 많이 함) 하기 때문에 느리다는 단점이 있다.
이러한 상황에서 서버와 클라이언트가 같은 대칭키를 가져야 하고,
대칭키 알고리즘의 키를 교환할 때 어떻게 키를 유출시키지 않고 교환할지가 핵심이다.
또한 TLS는 서버가 목적지 서버가 맞는지(인증된 서버가 맞는지 확인) 확인해야 하고, 서버는 인증서를 보내는 과정도 포함된다. 공유키를 통해서 이러한 인증서에 있는 정보가 누구에 의해 서명되었는지 확인하여 신뢰성을 보장받을 수 있다.
TSL 1.2 Handshake
TSL 1.2는 어떤 키 교환 방법을 사용할지 서로 협상하는 과정이 필요하다.
연결을 수립하기 위해 "TLS버전(여기서는 1.2)", "어떠한 키교환 알고리즘을 사용할 것인가", "임의의 문자열"을 서버에 전송한다.
여기서는 비대칭키 키교환 알고리즘 중 하나인 RSA를 사용한다고 가정한다.
RSA는 공개키와 개인키를 가지고 있다. 공개키에는 서버의 인증서가 포함되고 개인키는 자신만 가지고 있는다.
1. 클라이언트가 서버에게 "RSA의 대칭키 알고리즘을 통해서 암호화할 거야"라고 전송한다.
2. 서버는 공개키와 개인키를 생성하고, 공개키와 함께 인증서를 클라이언트에게 보낸다.
3. 클라리언트는 인증서 발행기관을 통해 서버로부터 받은 인증서를 검증한다.
4. 인증을 통해 신뢰할 수 있다고 판단이 끝났다면, 클라이언트는 임의의 키를 생성한다. 그리고 서버가 보내준 공개키를 통해서 임의의 키를 암호화하여 서버에 전송한다.
-> (이 임의의 키를 탈취해도 서버가 가지고 있는 개인키가 없으면 복호화할 수 없다.)
4. 이제 서버는 클라이언트로부터 받은 암호화된 임의의 키를 개인키로 복호화하여 클라이언트와 동일한 대칭키를 가지고, 클라이언트에게 통신 준비가 됐음을 알린다.
이렇게 비대칭키 방식으로 서로 키를 교환하면서, 결과적으로 데이터 통신을 할 때는 대칭키 방식으로 빠르게 암/복호화하여 통신할 수 있다.
RSA의 경우 추후에 개인키가 유출되었을 때, 과거 통신 이력을 보고(IPS와 같은 곳에서 통신내역이 유출될 경우) 세션(핸드셰이크 연결)마다 임의의 키를 알아내어 데이터를 복호화할 수 있다는 문제가 있다. 그래서 RSA는 잘 사용하지 않거나 개인키를 몇 달 혹은 몇 주만에 바꿔주는 방식을 사용하기도 한다.
이러한 RSA방식보다 더 좋은 키 교환 알고리즘인 Diffie Hellman 알고리즘이 있다.
Diffie Hellman
RSA와 마찬가지로 대칭키를 생성하기 위한 키 교환 알고리즘이다.
수학적인 방식을 사용하는데, 개인키 2개와 공개키 1개가 존재한다.
개인키는 각각 클라이언트가 1개, 서버가 1개 가지고 있고 이 3개의 키를 조합하면 임의의 키(대칭키)를 하나 만들 수 있다.
개인키 A, 공개키 B, 개인키 C라고 할 때,
A는 (B^A) % n라는 값을 생성하고, B는 (B^C) % n 라는 값을 생성한다.
A가 C에게 (B^A) % n을 보냈을 때 C가 받은 값에 {(B^A) % n}^C를 수행해 버리면 B^(AC) % n라는 대칭키를 얻게 된다.
반대로 C가 A에게 (B^C) % n을 전송하면 A는 {(B^C) % n}^A를 수행하여 똑같은 대칭키인 B^(AC) % n를 생성할 수 있는 것이다.
이렇게 지수연산과 모듈러 연산을 통해서 해석할 수 없는 키를 클라이언트-서버 간에 서로 전달할 수 있고, 이 값을 통해 클라이언트-서버간에 대칭키를 생성할 수 있다.
단점으로는 지수연산을 사용하기 때문에 대규모 시스템에서는 느릴 수 있다는 점이다.
TLS 1.3 Improvements
TLS 1.3 버전은 TLS 1.2 버전에 조금 더 발전된 키 교환 알고리즘들을 적용하였다.
또한 이미 특정한 키 교환 알고리즘을 사용한다고 가정하고 핸드셰이크를 수립하기 때문에 어떠한 키 교환 알고리즘을 사용할 것인지에 대한 협상과정이 필요하지 않다.
Diffie Hellman알고리즘을 적용한다고 가정한다.
1. 클라이언트가 공개키와 자신이 가진 개인키를 지수와 모듈러 연산으로 합친 후 서버에게 전송한다.
2. 서버는 클라이언트로 받은 값과 자신의 개인키를 결합하여 대칭키를 생성한다.
3. 서버 또한 공개키와 자신이 가진 개인키를 합쳐 클라이언트에게 전송하여(인증서도 포함) 대칭키를 가질 수 있도록 한다.
이렇게 클라이언트와 서버 간에 곧바로 연결을 수립하고 동일한 대칭키를 통해 암호화된 통신을 할 수 있다.
TLS1.2와 TLS1.3의 차이점 중 하나는 TLS1.3 은 어떠한 키교환 알고리즘을 사용할지 협상하는 과정(통신)이 필요 없기 때문에 TLS1.2버전보다 빠르다는 특징이 있다.
이 외에도 버전별로 패킷을 분석해서 더 깊게 공부하면 구체적인 차이점 또한 알아볼 수 있을 것 같다.