개발

Https, 클라이언트와 서버간 TLS 핸드셰이크 과정

플리트우드 2024. 12. 10. 17:09

SSL, TLS 

통신계층 중에, 어플리케이션과 TCP/IP 레이어 사이에서 데이터를 암호화하는 기법이다. TLS는 SSL 3.0 이후의 표준 암호화 방식을 뜻한다. SSL은 구식~

 

 

서버를 올리면, https로 암호화된 통신을 하기 위해 ssl 인증서를 발급받아야 한다. 그리고 인증서를 nginx, apache 등의 웹서버에 적용시켜야 한다. 발급 시 공개키와 개인키가 생기게 되는데, 개인키는 나만 가지고 있어야 한다.

 

 

 

 

클라이언트가 서버와 통신을 시작하는 과정인 TLS 핸드셰이크 순서를 보기 전에, 암호화에 대해 대강 알아야 할 게 있다.

 

1. 공개키, 개인키를 이용한 비대칭 암호화 방식 

- 공개키를 이용하여 암호화한 데이터를 개인키로 복호화

- 개인키를 이용하여 암호화한 데이터를 공개키로 복호화

- 반대로 대칭키 암호화는? 같은 키로 잠그고, 같은 키로 여는 것.

 

2. 해시함수, 해싱

- 해시함수를 통해 암호화된 데이터는 복호화가 불가하다.

- 다만, 내가 수중에 다음 두가지 값을 가지고 있다고 하자.

      a. 해싱값 abc

      b. 쌩 데이터 123

      ➡️123를 가져다가 해시함수(함수 종류는 a.가 쓴 것과 같아야 한다.)를 통과시켜 암호화했을때, abc가 나온다면? abc의 원본이 123 이라는 거.

 

 

 

 

TLS 핸드셰이크의 과정 (축약)

1. 클라이언트 -> 서버 : 똑똑~ google.com 맞나요?

2. 서버 -> 클라이언트 : google.com 맞습니다 (인증서 투척)

3. 클라이언트 -> 서버 : 인증서 검증 완료, 우리가 앞으로 사용할 키입니다~ (세션키 투척)

4. 서버 -> 클라이언트 : 세션키 풀었음요 ㅋ 이거 맞죠? (세션키 투척)

5. 클라이언트 -> 서버 : 지금부터 세션키로 데이터 잠가서 통신하자~

 

 

 

 

디지털 인증서 만드는 과정 

1. 서버는 인증서 속 원본 데이터 (도메인이름, 공개키 등)을 해시함수를 이용하여 해싱값으로 변환한다.

2. 그렇게 나온 해싱값을, 서버만 가지고 있는 개인키를 이용하여 또! 비대칭 암호화한다  (“개인키로 서명한다”라고 함) 

 

 

 

TLS 핸드셰이크  ( 1 )  -  클라이언트의 디지털인증서 검증 방식 

- 브라우저는 내부에 인증정보목록을 가지고 있다.

- 클라이언트는 서버로부터 디지털 인증서를 받아, 공개키로 이를 복호화한다. 그렇게 해서 나온 결과물을 ABC라고 하자.

- 클라이언트는 인증서의 원본 데이터(도메인이름, 공개키 등)에 서버가 사용한 해싱함수를 적용한다. 이렇게 해서 나온 결과물이 ABC라면, 서버가 보낸 디지털 인증서는 개인키를 이용하여 잠갔다는 게 검증되는 셈이다. 

 

 

TLS 핸드셰이크  ( 2 )  -  클라이언트가 세션키를 생성하여 서버와 공유하는 과정

- 서버의 진위여부를 인증서로 인증했으니, 데이터 암호화 통신에 사용할 세션키를 서로 주고받아야한다.

- 세션키는 클라이언트가 생성하여 공개키로 암호화한 뒤 서버에 보낸다.

- 서버는 개인키를 사용해 암호화된 세션키를 해독한다.

- 서버가 세션키를 이제 안다는 걸 클라이언트에게 알리기 위해, 특정문자열(이때까지 핸드셰이크에 쓰인 데이터를 기반으로 정해진다.)을 세션키를 사용해 암호화한 후 클라이언트에게 보낸다.

- 클라이언트는 세션키를 사용하여 복호화한 메시지가 특정문자열인 걸 확인한다. 

- TLS 핸드셰이크가 성공하고, 앞으로의 데이터통신은 세션키를 사용한 대칭적 암호화 방식을 사용하게 된다.

 

 

 

 

 

 

잡!

- 크롬 개발자 도구에서 서버에 전송되는 json 데이터들은, TLS 세션키로 암호화되기 전이라 내가 확인할 수 있는 것이다. “개발자 도구”니까 개발자들이 디버깅할 수 있게 브라우저에서 보여주는 거

- 세션키를 통해 암호화된 데이터들이 넘어오면, 이걸 복호화하여 어플리케이션 레벨에서 쓸 수 있게 하는 주체는 웹서버(nginx, apache) 또는 어플리케이션의 내장서버(스프링의 내장서버인 tomcat)이다. 보통 웹서버에서 TLS 복호화를 알아서 하기 때문에 어플리케이션 레벨에서는 신경 쓸 필요가 없다.

- TLS 핸드셰이크는 일반적으로 클라이언트랑 데이터를 주고받는 첫 엔드포인트 사이에 이뤄진다. (위와 같은 얘기)

- nginx랑 백엔드랑 서로 다른 컴, 다른 네트워크에 있다고 하면?? 그럼 얘네끼리도 TLS 핸드셰이크 해야되는 거 아님??

  • yes, 웹서버랑 백엔드가 서로 다른 컴 or 단일네트워크상(같은 데이터센터내)이 아닐 경우 추가적인 TLS 인증을 할 수도 있음. 이런 경우에는 스프링의 톰캣 설정에 ssl 인증서 정보를 적용시켜야되는 걸로 보임.
  • 기본적으로 웹서버는 http를 써서 백엔드에 데이터를 보내긴 하는데, 이는 신뢰할 수 있는 “내부 네트워크” 상에서 권장되는 방식임. 예를 들어.. 아마존의 VPC에다가 웹서버, 백엔드 서버를 잘 구축해놨다면 VPC의 엔드포인트만 신경 쓰면 되는 것임. 외부 트래픽이 서버 사이에 낄 수 없으니..
  • TLS 연결은 언제 끊기나? → 브라우저 껐을 때 or 연결 끊겼을때. 근데 이런경우에도, 만약 세션키와 관련된 세션ID를 서버가 메모리상에 가지고 있는 경우에는, 클라이언트가 세션ID를 확인하는 과정을 통해 새로운 TLS 핸드셰이크 없이 재개될 수 있다.
  • 본 포스트에서 말하는 세션키는, 로그인 기술에 쓰이는 세션쿠키와는 다른 용어임.