세션(Session)
클라이언트와 서버가 TLS 핸드셰이크를 한 번 하고 나서 안전하게 통신하는 하나의 연결 단위
핸드셰이크할 때:
• 클라이언트가 자기만 아는 비밀값 a 생성
• 서버가 자기만 아는 비밀값 b 생성
• 디피헬만 계산
• Shared Secret 생성
• 거기서 대칭키 파생
🎯 이 과정이 연결할 때마다 매번 다시 일어남.
왜 세션마다 새로 만드는건가?
- 만약 대칭키를 계속 재사용하면:
• 키가 유출되면 모든 통신이 위험
• 과거 통신도 복호화 가능- 근데 매 세션마다 새로 만들면:
• 이번 연결 키가 유출돼도
• 예전 연결은 안전
• 다음 연결도 안전
이게 바로 Forward Secrecy(키 또는 암호의 향후 유출로부터 과거 세션을 보호)의 핵심
쉽게,
통화할때 암호키 사용 후
다시 통화할때 암호키 다시 만듬
L5(UDP): DNS 조회로 IP 획득.
L4(TCP): 3-Way Handshake로 번호표(Seq/Ack) 맞추고 통로 연결.
L5(TLS): 인증서(공개키)로 대칭키를 안전하게 교환. (TLS handshake)
L5(HTTP): 이제 정해진 대칭키로 암호화해서 실제 데이터(fetch 결과)를 주고받음.
디지털 서명(인증서)과 TLS 핸드셰이크의 과정
(1) 서버가 공개키를 보냅니다.
(ex, Let's Encrypt를 통해 발급받은 인증서의 경우, 비대칭키 쌍(개인키와 공개키)이 생성됩니다. 이 중 개인키(Private Key)는 서버에 안전하게 저장)
서버는 디지털 인증서를 통해 공개키(디지털 인증서에 포함)를 클라이언트에게 보냅니다. (디지털 인증서 안에 공개키와 디지털 서명이 포함)
클라이언트는 이 공개키가 신뢰할 수 있는 기관(인증서 발급 기관, CA)이 발급했는지 확인합니다. (자신의 신뢰할 수 있는 CA 목록(브라우저나 OS에 내장된 루트 인증서 저장소)을 통해 서버 인증서를 검증)
아래 디지털 서명 및 검증은 CA(인증기관, Certificate Authority), 즉 인증서에서 생성 및 검증함
서버(또는 AWS ACM 같은 서비스)는 가장 먼저 비대칭키 쌍을 만들고 CA에게 보증을 받는데, CA는 서버의 공개키와 도메인 정보를 묶어서 디지털 인증서를 만들어주고 TLS Handshake 단계에서 클라이언트가 서버에게 요청하면 서버는 디지털 인증서를 클라이언트에 전달하고 클라이언트는 서버의 공개키를 꺼내서 사용한다.
클라이언트는 대칭키를 하나 만들고 해당 대칭키를 서버가 보내준 공개키로 암호화해서 서버에게 전달
발신자(서버) :
평문 -> 해시값 생성 -> 개인키로 암호화(디지털 서명)
평문을 해시값으로 만들고 해시값을 개인키로 암호화하면 서명이 만들어집니다.
(평문과 서명을 수신자에게 전달)수신자(클라이언트) :
평문 -> 해시값 생성 -> 서명을 공개키로 복호화 -> 해시값을 비교
전달 받은 평문으로 해시값을 생성(동일한 입력이면 해시값이 동일)하고 전달 받은 서명을 공개키로 복호화하면 발신자가 만든 해시값을 얻을 수 있으며 이 해시값을 내가 만든 해시값과 비교해서 두 값이 동일하면 유효하다면 신뢰할 수 있는 기관(인증서 발급 기관, CA)에서 발급한 것이 확인됩니다.
(2) 클라이언트가 세션 키(대칭키)를 생성합니다.
클라이언트는 데이터를 암호화하는 데 사용할 대칭키(세션 키)를 생성합니다.
(3) 클라이언트가 세션 키를 서버의 공개키(인증서에 포함)로 암호화합니다.
클라이언트는 서버의 공개키를 사용해 생성한 세션 키를 암호화한 후 서버에 보냅니다.
여기서 중요한 점은 공개키로 암호화된 데이터는 서버의 개인키로만 복호화할 수 있다는 점입니다.
(4) 서버가 개인키로 세션 키를 복호화합니다.
서버는 자신의 개인키로 세션 키를 복호화해서 대칭키를 얻습니다.
(5) 이제 클라이언트와 서버는 같은 대칭키를 가지고 있습니다.
이 대칭키를 사용해 데이터를 암호화하고 복호화하며 HTTPS 통신을 진행합니다.
--> 위 방식(대칭키를 공개키로 암호화하여 보내는 방식) 사용하지 않음
현재는 디피 헬만 키 교환 방식을 써서 대칭키를 만듬
클라이언트와 서버가 각각 비밀값을 하나씩 생성하고 서로의 공개값만을 교환하여 각자 계산을 통해 최종 대칭키를 만듬
SSH (깃허브 예시) - 비대칭키 생성후 공개키를 깃허브에 등록했다는 가정
(1) 내가 git push를 실행하면 내 컴퓨터(클라이언트)가 GitHub 서버에 SSH 연결을 요청합니다.
(2) GitHub 서버는 내가 개인키를 가지고 있는지 확인하기 위해 Challenge(도전문자)를 만듭니다.
이 도전문자는 내 공개키로 암호화돼서 나에게 전달됩니다.
(3) 내 컴퓨터는 로컬에 저장된 개인키를 사용해서 도전문자를 복호화합니다.
복호화된 도전문자는 서버가 보낸 원본 메시지여야 합니다.
(4) 클라이언트는 복호화된 도전문자를 서버에 다시 보냅니다.
서버는 이 응답을 보고 클라이언트가 올바른 개인키를 가지고 있음을 확인합니다.
(5) SSH 인증이 성공하면, 클라이언트와 서버는 세션키(대칭키)를 생성합니다.
(Diffie-Hellman 키 교환(혹은 유사한 알고리즘)을 사용해 세션키를 안전하게 생성)
Diffie-Hellman 방식은 클라이언트와 서버가 서로 협력해서 동일한 세션키를 생성
어떻게 동일한 세션키를 생성할 수 있는지 쉽게 설명
공개된 값: 기본색 P (예시: 노란색) 와 섞는 도구 G (예시: 붓)
비밀 색: 클라이언트는 빨간색, 서버는 파란색
공개 색 교환: 클라이언트는 노란색+빨간색, 서버는 노란색+파란색을 서로 교환
같은 색 만들기:
결과적으로 둘 다 같은 색(노란색+빨간색+파란색)(세션 키:대칭 키)를 가지게 됩니다.