웹을 운영한다면 https 를 사용하는 것이 너무나 자연스럽다.
http 로 접속하게 되면 '안전하지 않음' 이 뜬다.
인증서를 발급받고 https 설정을 하면된다
이것은 영리한 초딩들도 할 수 있다.
https 라는게 뭐지? 인증서는 왜 발급받지?
애초에 http가 뭐지?
라는 물음에서 책을 파고들며 알게된 지식이다
"HTTPS 는 HTTP 요청과 응답을 SSL/TLS 로 암호화하여 보안을 강화한 HTTP 보안 버젼이다. HTTPS를 사용하려면 SSL/TLS 인증서가 필요하며 이 인증서는 서버가 신뢰할 수 있는 서버임을 보증한다"
(만약 이 문장을 보고 뒤로가기를 누르고 싶어졌다면 아래의 글을 보고 오길 추천합니다)
https://biz-ninza.tistory.com/19
HTTPS를 왜 써야하는지, 암호화가 뭔지 모른다면 클릭
웹을 운영한다면 https 를 사용하는 것이 너무나 자연스럽다.http 로 접속하게 되면 '안전하지 않음' 이 뜬다.인증서를 발급받고 https 설정을 하면된다이것은 영리한 초딩들도 할 수 있다. https 라는
biz-ninza.tistory.com
HTTPS의 핵심 키워드는 보안, SSL, 인증서이다.
이 위주로 글을 보면 좋을 것 같다.
- 인증서 신청 및 발급
- 서버에 인증서 설치후 웹서버에 적용
- 클라이언트와 서버가 handshake
- handshake 시 서로를 탐색, 암호화방식 결정, 그리고 서버는 인증서를 전달
- 클라이언트는 인증서안의 공개키를 활용해 대칭키(세션키)를 만들게 됨
- 서버도 가지고 있던 공개키로 같은 대칭키(세션키)를 만들게됨
- 클라이언트와 서버는 세션키를 활용하여 HTTP 데이터를 암호화하며 주고받음
- 통신이 종료되면 세션키 삭제
글을 읽고 나면 위의 과정이 머릿속에 그려질 것이다
목차
1. 인증서와 HTTPS
2. 인증서 딥다이브
3. HTTPS는 SSL 위에서 이렇게 동작한다.
4. HTTPS 세팅 (AWS를 쓸 경우와 나머지)
5. AWS 썼습니다
1. 인증서
SSL 인증서는 클라이언트와 서버간의 통신을 제3자가 보증해주는 전자화된 문서다. (공증)
한 마디로 브라우저를 통해 접속하는 서버가 정보를 탈취하기위해 정성스럽게 마련한 www.never.com 같은 가짜서버가 아니라 진짜 네이버 서버임을 보증해준다.
클라이언트가 SSL 프로토콜 이용해 서버에 접속하면 서버는 클라이언트에게 인증서 정보를 전달한다.
클라이언트는 이 인증서를 검토한 후에 HTTP 요청이 들어간다.
인증서를 사용하면 클라이언트가 서버가 신뢰할 수 있는 곳인지 판단할 수 있고 통신 내용이 노출되거나 변경되는 것을 막을 수 있다. 암호화에 의해 이게 가능하다.
즉, 인증서를 설치하고 HTTPS 통신을 하게 되면 '서버의 신뢰성' 뿐 아니라 통신과정에서 '데이터의 도청, 변조 방지' 의 역할도 기대할 수 있다.
또 한편, Google 같은 검색엔지는 HTTPS 사이트를 우선순위로 노출한다고 하니 SEO 에서의 장점도 있겠다.
2. 인증서 딥다이브
*공개키가 두 번이 나오는데 하나는 브라우저에 내장된 CA의 공개키이고, 또 하나는 서버가 인증서 안에 심어 보내는 서버의 공개키다. 이 둘을 잘 구분해서 이해하여야한다.
SSL 인증서에는 다음과 같은 정보가 포함되어 있다.
- 서비스의 정보 (인증서를 발급한 CA, 서비스의 도메인 등등)
- 서버 측 공개키 (공개키의 내용, 공개키의 암호화 방법) → 클라이언트가 추후 서버와 SSL 통신을 위한 공개키이다
이런 인증서를 보증해주는 민간기관이 CA(Certificate authority) 로, 공인된 기업들만이 참여할 수 있다. 서버는 미리 CA를 통해서 인증서를 구입하고 이 인증서를 클라이언트에게 전달한다.
서버는 공개키, 서비스 정보(도메인 등)를 인증기관에게 보내 심의를 받는다.
인증기관은 이 공개키를 통해 인증서를 생성하고 CA는 비밀키로 서명을 한다.
(이 때 CA는 사업자등록증, 법인서류 등을 확인하는 과정을 거쳐 높은 신뢰도를 보증할 수도 있다)
인증서를 구매했다면 이후 서버와 클라이언트의 통신 절차는 다음과 같다.
- 클라이언트가 서버에 접속하면 서버는 인증서를 제공
- 브라우저는 인증서를 발급한 CA가 자신에게 내장된 CA 리스트에 있는지 확인
- 포함되어 있는 CA라면 브라우저에 내장되어있는 ‘CA의 공개키’ 를 이용해서 인증서를 복호화
- 복호화할 수 있다는 것은 인증서가 CA의 비밀키에 의해 암호화된 것. 믿을 수는 인증서라는 것
- 믿을 수 있는 인증서라는 것은 CA의 검토를 통과했다는 것이고 서버도 믿을 수 있다는 것
CA : “인증서 받았어? 브라우저에 공개키 심어놨으니까 그걸로 복호화해봐. 그게 가능하다면 이 사이트는 믿어도 돼! 이걸 복호화할 수 있다는 것은 내가 인정한 인증서라는 얘기야. 나는 믿을 만한 사람한테만 인증서 줬으니까 믿어”
(공인된 인증기관에서 발급한 인증서를 사용하면 브라우저에서 인증서를 확인할 수 있음. 인증기관과 서버의 도메인이있음)
(사설 인증기관에서 발급한 인증서를 사용하면 브라우저 상에서 아래와 같이 이상하게 뜸)
💡 만약 인증기관이 실수로 비밀키를 유출시켜버리면 어떨까? 누군가가 가짜 인증서를 만들어낼 수 있을 것이다.
실제로는 가짜인증서이지만 브라우저가 가진 공개키에 대응되므로 실제 인증서로 착각한다.
브라우저 입장에서는 인증서에 대한 신뢰가 무너져 버리는 것이다
(실제로 비공개키가 유출되어 해당 인증서가 무효화되어 브라우저에서 제거당하여 회사가 망한 디지노타도 있다함 1998년 설립, 2011년 파산)
💡 브라우저에 심어져있는 CA의 공개키를 통해서 브라우저와 CA사이에 인증서에 대한 믿음이 형성된다. 인증서안에는 서버의 공개키가 있는데 이는 향후 브라우저와 서버사이의 SSL 통신을 위한 것이다
💡 가상 호스트(하나의 서버에 여러 호스트명)로 운영되는 사이트의 보안 트래픽을 다루는 것은 까다롭다. 호스팅 제공자의 도메인과 사용자가 브라우징했던 가상호스트명이 맞지 않을 수 있기 때문. 적절히 보안트랜젝션을 호스팅 제공자쪽으로 리다이렉트한 후 관리하던가 할 것
3. HTTPS 통신과정
공개키-비밀키 방식의 암호화가 서버와 클라이언트가 통신하기 가장 좋다.
그러나 이 과정은 성능상 부담이 있어서, 실제 데이터 전달을 할 때에는 대칭키(양쪽이 같은 키를 가지고 통신하는 방식)를 사용해서 암호화하여 통신한다.
컴퓨터와 컴퓨터가 네트워크 통신을 맺으려면 handshake - session(전송) - session 종료 의 과정을 거친다.
[ handshake ]
handshake 는 말그대로 악수다. 서로 먼저 인사를 하면서 데이터를 주고 받을 준비를 하는 과정이다. 클라이언트는 어떤 브라우저를 쓰는지, 서버는 어떤 웹서버를 쓰는지 등등 서로를 탐색한다.
또 그 과정에서 양쪽의 신원을 인증, 암호화 방식을 선택, 세션 키를 생성해 데이터암호화 준비 과정도 거친다.
1.Client Hello - 클라이언트가 서버에 접속
브라우저, 즉 클라이언트 측에서 생성된 랜덤데이터를 전송한다. (세션키 생성을 위한 난수)
클라이언트가 지원하는 암호화 방식을 서버에 전송한다.
(만약 기존에 handshake 를 한 적이 있다면 세션 아이디를 주며 기존의 세션을 재활용하도록 한다)
2. Server Hello - 서버가 클라이언트에게 응답
서버 측에서 생성한 랜덤데이터를 전송한다.
서버가 암호화 방식을 선택해서 클라이언트로 전달한다 (=협상한다)
서버가 클라이언트에게 인증서를 이 때 전송한다.
3. 클라이언트가 인증서 검증 후 세션키(대칭키) 생성
브라우저에 내장된 CA의 공개키를 통해 인증서가 진짜임을 검증하고, 유효기간과 도메인 일치여부 등을 확인한다.
믿을만한 서버라는 판단이 들면 랜덤데이터를 조합해서 클라이언트는 pre master secret 이라는 키를 생성한다.
이 때 인증서에 있던 서버의 공개키를 사용하여 이 키를 암호화한다!
클라이언트는 서버에게 이 pre master secret 을 전송하게 되는데, 이에 대한 비밀키는 서버만이 가지고 있으므로 안전한 상황이다.
4. 서버에서도 세션키(대칭키) 생성
서버는 pre master secret 값을 자신의 비공개키로 복화하며 서로 이 값을 공유하게 된다.
Session Key = PRF(pre master secret, Client Random + Server Random)
즉 클라이언트와 서버의 랜덤데이터와 pre master secret 값을 이용해서 세션키라는 대칭키를 만든 후데이터를 주고 받는다.
(세션키는 클라이언트, 서버가 모두 생성한다. 최종적으로 session key 가 서로에게 공유됨)
[ session(전송) ]
세션키(대칭키)로 서로 데이터를 암호화, 복호화 과정을 거쳐 데이터를 주고 받는다.
[ session 종료 ]
데이터 전송이 끝나면 SSL 통신이 끝났음을 알려주며 대칭키인 세션키를 폐기한다
이 모든 것은 아주 짧은 시간에 이루어지기 때문에 세션키가 노출되어도 세션은 이미 종료되어버리기 때문에 안전하다.
다시 정리하면, handshake 과정은 클라이언트가 서버가 진짜임을 확인하고 HTTP 통신을 하기 위한 세션키를 생성하는 과정이라고 할 수 있겠다.
💡 이러한 SSL/TLS 핸드셰이크는 시간과 CPU 자원을 많이 소모하기 때문에 서버가 세션ID 를 저장해 캐싱하고 있다가 클라이언트가 세션키를 들고오면 핸드셰이크를 생략하는 과정을 통해 최적화 할 수 있다.
💡 브라우저도 인증서를 미리 캐싱해놓고 매번 인증서 전체를 다운로드하는 과정을 생략할 수 있다.
💡 AWS 같은 클라우드나 CDN 등은 HTTPS 트래픽을 최적화 하기 위한 여러가지 기술들을 사용하는데 이를 생략한다.
4. HTTPS 세팅 (AWS를 쓸 경우와 나머지)
만약 인증서를 AWS 제외한 곳에서 구매한 후 발급받는다면 nginx 같은 웹서버의 /etc/ssl 과 같은 경로에 설치를 해주면 된다.
(인증기관들을 도메인이 없으면 잘 승인을 안해주므로 가급적 도메인을 세팅한 후 https 인증서를 발급받는것)
한편, AWS 에서 발급하는 ACM 인증서는 AWS 서비스 내부에서만 쓸 수 있다.
즉, EC2 인스턴스 서비스 내부에서 설치할 수 없다.
AWS에서는 대신 LoadBalancer, CloudFront, API Gateway 등에 인증서를 적용한후 EC2에 라우팅하는 방식으로 사용하게 된다.
AWS 의 로드밸런서, ELB(Elastic Load Balancer) 는 인스턴스들에게 트래픽을 분산해주는 역할을 한다.
인스턴스가 고장나거나 새로 생긴것도 파악해서(헬스체크) 가용성 높은 트래픽 연결을 보장한다.
인스턴스 뿐 아니라 IP주소, 컨테이너, Lamda 함수 등 여러 대상이 될 수 있다.
다만 IP 고정을 하기 힘들어서 도메인 address 기반으로 사용한다
(Network Load Balancer 사용해서 잘 아키텍쳐 조합하면 IP주소 고정시킬 수 있지만 생략)
5. AWS 썼습니다.
우선 EC2 와 Route53 등 AWS 서비스를 사용하기 때문인것이 가장 크고 AWS 는 내부적으로 SSL 가속기 등을 활용하여 TLS 핸드쉐이크 속도를 최적화 한다.
또한 CDN, ALB, CloudFront 와 통합되어 핸드 셰이크 부하를 감소시킨다 (왜?)
AWS 인증서는 일단 무료이고 Let's Encrypt 같은 타사인증서처럼 3개월마다 갱신할 필요가 없다는 것도 장점이다.
Nginx 설정파일을 직접 수정하지 않는다는 것도 장점이고 TLS 1.3 & 0 -RTT 라는 ... 어떤 고급기술을 써서 연결속도도 최적화 해두었다고 한다.
기타 보안적인 강점도 있다고 하는데 여러모로 그냥 AWS 인증서 쓰는게 나을 것 같아서 AWS 썼다.
ELB의 유형중 도메인을 읽어 해당서버로 라우팅하는 Application LB 를 사용하였다
(TCP 기반으로 트래픽을 분산시키고 Elastic IP 를 할당하는 NetworkLB, 프록시 인증 로깅 캐싱 등을 담당하는 가상어플라이언스를 관리할 수 있는 Gateway LB 등도 있는데 일단 해당 내용은 생략한다)
CloudFront 는 정적/동적 컨텐츠 제공목적이고 EC2 서버에 라우팅하는 것이 목적인데 CDN 을 쓰는 것도 이상해서(?) ALB를 선택했다 - 향후 보충
AWS 인증서를 발급받고 ALB 를 적절히 잘 세팅해주면 된다
🚨 HTTPS 접속시 발생가능한 각종 에러 ( 디버깅시 참고하자 )
- (위의그림) ALB 가 443 포트를 통해서 HTTPS 요청을 받고 해당 요청을 인스턴스에 HTTP 요청을 전달해주는 방식이다
만약 ALB 까지는 요청이 잘 들어가는데 ALB가 백엔드 서버를 제대로 못찾으면 502 Gateway
- LB가 가용영역과 다른 리젼에 인스턴스를 발견하면 503 Temporalily unavailiable
- https:// 스킴을 사용하지 않고 http:// 로 443 포트에 요청을 보내면 400 Bad Request (HTTPS 받을 곳인데 HTTP요청을 하고 있다)
- 인증서를 제대로 안걸어놓고 https 요청을 들어가면 '신뢰할 수 없는 사이트' 라고 막힘
- 443 포트가 아닌 다른 포트로 들어가면 '연결할 수 없다' 는 오류응답을 내뱉고 아예 연결이 거부 (ALB 에서부터 막히는 경우 딜레이가 많이 먹음) 일단 ALB 까지는 통과하면 에러 코드를 빨리 내뱉음.
- 연결할 수 없는게 아니라 '연결 거부' 는 보안그룹에서 짤리는 것이니 디버깅할 때 참고
향후 공부키워드
- HTTPS SSL 터널링 프로토콜
- HTTP 확장 메서드 CONNECT
- 보안 터널, 보안 프록시
- openSSL
- http를 https로 강제 리다이렉션
- cloudFront 에 인증서 설치시 미국 동부 버지니아 북부에서 발급받은것만 사용가능
출처 : 생활코딩, gpt, HTTP 완벽가이드
'[개발일지] > CS 스터디 플랫폼' 카테고리의 다른 글
9장. 프록시 서버가 포함된 HTTPS 아키텍쳐에서 발생가능한 이슈 (Mixed Content, CORS Policy) (0) | 2025.02.11 |
---|---|
8장. EC2 .pem 파일을 분실했을 때 해결방법을 생각해보자 (a.k.a /home/ubuntu 폴더를 삭제해버렸다) (0) | 2025.02.04 |
6장. 도메인 만들어야지. Gabia와 Route53 중에 뭘 쓸까? (0) | 2025.01.23 |
5장. 프론트엔드 서버는 Nginx 에 올려라. 왜? (0) | 2025.01.13 |
4장. 객체의 상속관계는 데이터베이스에 어떻게 표현하지...? (0) | 2024.12.03 |