프로젝트를 배포하기 위해서 Https를 도입했다.
개인프로젝트 이기는 했지만, 실제로 서비스되어야 했기 때문에 이왕 배포하는 거 더 보안을 신경쓰고 싶어서였다.
가볍게 Https에 대한 개념은 알고 있었지만 오늘 더 확실하게 정리해 보고자 한다.
Https를 이해하기 전에 SSL과 TSL, 그리고 대칭키와 비대칭키에 대해서 먼저 알아야 한다.
SSL(Secure Scokets Layer)은 Netscape에서 자신들이 만든 Netscape Navigator 브라우저를 위해 최초 설계한 암호화 기반의 인터넷 보안 프로토콜이다.
Secure Sockets Layer 라는 단어를 보니까 OSI 7Layer처럼 통신 구조의 한 계층에 속하는 것처럼 보인다.
예상과 비슷하게 SSL은 인터넷과 같은 TCP/IP Layer기반의 통신에서 응용계층과 전송계층과 사이에 독립적인 보안 계층이라는 걸 만들어 동작한다. ( 특정 계층에 속하는 개념은 아니다. )
Https는 Http에 SSL을 적용한 프로토콜이다.
왜 필요할까??
기존에 Http는 데이터를 일반 텍스트 평문으로 주고 받았다. 그래서 제 3자가 정보를 조회할 경우 그대로 노출되는 위험이 있었다.
이러한 문제를 해결하고자 데이터를 암호화하는 SSL이 만들어진 것이다.
SSL은 1996년 SSL 3.0 에서 업데이트가 멈췄는데, 보안 취약성이 해당 버전에서 보안 취약성이 많이 남아 있었다.
그래서 이후 Tim Dierks와 Christopher Allen이 1999년에 SSL 3.0의 후속으로 TLS 1.0을 만들게 되는데, 이때 소유권 변경을 위해서 이름을 TSL(Transport Layer Security)로 바꾸었다고 한다.
사실상 TLS는 SSL의 업데이트 버전이며 명칭만 다르다고 볼 수 있다.
결론은 SSL = TLS 이다. ( 예시로 애완동물과 반려동물이 있다. 현재 올바른 표현은 반려동물이지만 애완동물이 아직도 많이 사용된다. )
Https 동작 방식을 이해하기 위해서 대칭키와 비대칭키에 대해 알아야 한다.
대칭키와 비대칭키 모두 "키"라는 단어가 들어가는데, 이 "키"라는 것을 통해서 데이터를 암호화하고 복호화하기 때문이다.
대칭키는 말 그대로 두 당사자가 사용하는 키가 대칭된다는 뜻에서 대칭키이다. 즉, 사용하는 키가 같다는 것이다.
A라는 키가 있다면 데이터를 암호화 할 때에도 A를 통해서 암호화하고 그렇게 암호화된 데이터를 복호화할 때에도 A를 사용한다.
A를 갖고 있는 누구라도 데이터를 A로 암호화된 데이터를 복호화할 수 있기 때문에 키 탈취 시에 보안 위험이 존재하는 방식이다. 하지만 속도가 상대적으로 빠르다는 장점도 있다.
비대칭키는 공개키와 개인키 두 가지 키를 사용하는 방식이다.
공개키를 이용해서 암호화 했다면 개인키를 통해서만 복호화가 가능하고 개인키를 이용해서 암호화 했다면 공개키를 이용해서만 복호화가 가능하다.
보통 공캐를 외부에 공개하고 개인키는 자신만 갖도록 한다. 그러면 공개키를 가진 사람이 공개키로 데이터를 암호화하면 개인키를 가진사람만이 그 데이터를 읽을 수 있기 때문에 개인키만 노출되지 않는다면 거의 안전한 방식이다. 다만 속도가 조금 느리다는 단점이 있다.
이러한 특징 때문에 비대칭키를 통한 암호화의 의미는 대칭키와는 조금 다르다. 공개키를 마음만 먹으면 비교적 쉽게 탈취할 수 있기 때문이다. 보통 공개키를 가진 쪽이 암호화한 데이터를 자신만 알 수 있기 위한 수단으로써 쓰인다.
그래서 실제로 Https 통신에서는 위의 두 가지 방법을 모두 이용한다.
비교적 속도가 느리지만 안전한 비대칭키 방식을 통해 이후 통신에서 사용할 세션키라는 대칭키를 주고 받고, 그 후로는 세션키를 이용해 데이터를 암호화하여 통신한다.
그 정확한 방법은 밑에서 설명하도록 하겠다.
이러한 인증서는 인증된 기관(CA)에서 발급해 주는 것으로 서버는 그러한 기관에게 발급 요청을 하고 인증서를 받아야 한다.
서버가 공개키와 개인키를 만든다.
서버가 자신이 만든 공개키와 서버의 각종 정보를 CA에 전달하고, 인증서 발급을 요청한다.
CA는 서버로부터 받은 정보들을 토대로 해당 서버를 위한 SSL인증서를 만든다.
CA는 해당 인증서를 암호화하기 위해, 공개키와 개인키를 생성한다. 그리고 생성한 비밀키를 이용해 SSL인증서를 암호화한다.
암호화된 SSL인증서를 요청한 서버에 전달한다.
이 과정을 거쳐서 SSL인증서는 최종적으로 서버로 전달된다.
서버는 SSL인증서를 발급 받았기 때문에 Https를 사용할 준비가 되었다. 클라이언트와 서버는 이 인증서를 활용해서 SSL(TLS) HandShake과정을 거쳐 Https 통신을 하게 된다.
클라이언트가 서버로 "헬로" 메시지를 전송하면서 핸드셰이크를 개시한다. 이 메시지에는 클라이언트가 지원하는 TLS 버전, 지원되는 암호화 방식, Session ID, SNI(서버명), 무작위 바이트 문자열을 포함한다.
이 때, HandShake 과정을 매 요청마다 반복할 경우 비효율적이기 때문에, Session ID 라는 것을 사용한다.
다음 요청에서는 Session ID를 보냈을 때 유효하다면 TLS HandShake 과정이 생략된다.
( 네트워크를 많이 타는 것은 시간이 오래 걸릴 수 있기 때문에 생략이 가능하다면 상당히 효율적이다. )
클라이언트 헬로 메시지에 대한 응답으로 서버가 SSL 인증서, 서버에서 선택한 암호화 방식, 그리고 서버에서 생성한 또 다른 무작위 바이트 문자열을 포함하는 메시지를 전송한다.
Server Key Exchange라는 것이 있는데, 이는 SSL인증서에 서버의 공개키가 없는 경우 서버가 직접 보냄을 의미한다고 한다.
( 어쩌다 공개키가 누락되는 지는 잘 모르겠다.. CA에 공개키를 보내고 인증서를 발급받는 과정에서 문제가 있는 건지.. )
클라이언트는 서버로부터 받은 SSL 인증서(CA의 개인키로 암호화된)를 CA의 공개키를 통해 복호화하여 검증한다. CA의 공개키는 브라우저에서 자체적으로 CA에 대한 리스트와 공개키를 갖고 있다.
이를 통해 서버가 인증서에 명시된 서버인지, 그리고 클라이언트가 상호작용 중인 서버가 실제 해당 도메인의 소유자인지를 확인하고 서버의 공개키도 얻을 수 있다.
클라이언트는 SSL 인증서에서 얻은 서버의 공개키로 암호화한 "pre-master secret"라는 무작위 바이트 문자열을 하나 더 전송한다. 이는 서버의 개인 키로만 해독할 수 있다.
모든 SSL 핸드셰이크는 비대칭 암호화(공개 키와 개인 키)를 사용하지만, 세션 키를 생성하는 과정(4~6과정)에서 모두가 개인 키를 사용하는 것은 아니라고 한다. 예를 들어, 임시 Diffie-Hellman 핸드셰이크 같은 게 있다고 한다. ( pre-master secret 대신 DH 매개변수를 사용한다고 한다. 너무 어려워서 원리는 모름 ㅋ )
서버가 pre-master secret을 복호화 한다.
클라이언트와 서버는 클라이언트 무작위 바이트 문자열, 서버의 무작위 바이트 문자열, pre-master secret를 이용해 세션 키를 생성한다. 도중에 문제가 없었다면 서버와 클라이언트는 동일한 세션 키가 생성될 것이다.
클라이언트가 세션 키로 암호화된 "완료" 메시지를 전송한다.
서버가 세션 키로 암호화된 "완료" 메시지를 전송한다.
핸드셰이크가 완료되고, 세션 키를 이용해 통신을 진행한다.
이렇게 Https에 대해 알아 보았다.
Http의 평문으로 데이터를 전달한다는 보안 문제를 해결하기 위해 SSL이라는 것이 만들어졌고, 어떻게 동작하는 지 알 수 있었다.
그런데 데이터를 암호화 할 거면 인증서가 굳이 필요한가? 대칭키 비대칭키만 써도 암호화는 충분해 보이는데..
실제로 Server Key Exchange라는 개념이 위에 잠깐 있었는데, 서버가 직접 공개키를 클라이언트에게 넘기는 경우였다.
이런 걸 보면 정말 데이터를 암호화한다는 목적만 있다면 인증서는 사실 필요 없어도 될 것이다. 그냥 대칭키 비대칭키만 사용해도 된다.
하지만 인증서라는 것을 사용하면, 단순히 암호화 뿐만 아니라 제 3자로부터 검증받을 수 있다는 장점이 추가적으로 생긴다.
신뢰할 수 있는 제 3자가 안전한 사이트인지 중간에서 매개체 역할을 해 주기 때문에 보안적으로 더 우수하다.
보안에 충분이란 없다. 아무리 보안에 신경 써도 뚫리기 마련이기 때문에 철저하게 보안은 신경을 써야 하는 것이다.