이슈 트래커 프로젝트를 진행하면서 클라이언트-서버 통신 간을 안전하게 진행하기 위해 SSL 인증서를 적용해 HTTPS 통신을 수행하기 위해서 Certbot을 이용해보았습니다. HTTPS 통신과정의 이해와 어떻게 적용했는지 남기려고 합니다.
HTTPS는 말그래로 SSL(Secure Socket Layer)에 HTTP를 얹은 프로토콜입니다. 즉 보안이 보장된 HTTP 이라고 볼 수 있습니다.
HTTPS는 SSL 핸드쉐이크를 통해 클라이언트와 서버 간 연결을 진행하게 됩니다. 이 과정은 꽤 복잡하기 때문에 먼저 대칭키
, 비대칭키
암호화 방식을 알 필요가 있습니다.
대칭키는 말 그대로 암호화와 복호화시 사용하는 키가 동일한 암호화 기법입니다. 그러기 위해서는 양쪽이 모두 같은 키를 가져야 한다는 특징이 있습니다.
위 그림에서 A에서 B로 데이터를 전송할 때 대칭키를 통해 암호화를 하고 이를 받은 B는 같은 키를 통해 복호화를 진행할 수 있습니다.
그런데 이 방식에는 단점이 하나 있습니다. 바로 서로 같은 키를 가지기 위해 키를 주고 받아야 한다는 점입니다. 만약 A에서 B로, 혹은 B에서 A로 대칭키를 전달할 때 대칭키가 탈취되면 다른 사람도 데이터를 복호화 할 수 있게 됩니다.
이런 배경에서 나온 것이 비대칭키(공개키)
방식입니다.
공개키 방식은 대칭키 방식과 다르게 키가 두 개 존재합니다. a라는 키로 암호화를 했다면 b라는 키로 복호화할 수 있고 b키로 암호화하면 a키로 복호화를 할 수 있게 됩니다. 둘 중 하나를 공개키, 나머지 하나를 비공개키로 정하게 됩니다.
HTTPS는 대칭키 암호화
방식과 비대칭키 암호화
방식을 모두 사용하는 프로토콜입니다.
각 키를 이용해서 데이터를 주고받는 순서를 알아보겠습니다.
A의 공개키가 탈취되어도 이를 복호화할 수 있는 것은 A의 비공개키를 통해서만 가능하기 때문에 대칭키 방식의 단점을 해결했다고 볼 수 있습니다.
그런데 데이터를 주고받을 때 A의 비공개키로 데이터를 암호화하는 경우도 있습니다. 이는 공개키가 탈취될 경우 데이터가 그대로 보이는 문제가 발생하는데 왜 사용되는 것일까요?
이 방식의 목적은 데이터의 보호가 목적이 아니기 때문입니다.
A에서 자신의 비공개키로 암호화된 데이터를 전달하고 이를 복호활 수 있다면 이는 A에서 보낸 데이터임을 보장할 수 있기 때문입니다.
즉, 공개키로 복호화 가능한 경우 정보를 전달한 사람의 신원을 보장해줍니다. 이것을 전자 서명이라고 하고 SSL 통신에서 사용됩니다.
SSL 통신에서 SSL 인증서를 사용하게 됩니다. SSL인증서에는 다음과 같은 정보가 포함되어 있습니다.
🧐 CA?
인증서의 역할은 클라이언트가 접속한 서버가 신뢰할 수 있는 서버임을 보장하는 역할을 합니다. 이 역할을 하는 기업들이 있는데 이런 기업들을CA(Certificate Authority)
라고 합니다.
위와 같은 내용들은 CA에 의해 암호화됩니다. 이때 사용하는 방식이 공개키 방식입니다. CA는 자신의 CA 비공개키를 이용해 서버가 CA에게 제출한 인증서를 암호화합니다.
그러면 이를 받은 클라이언트는 어떻게 CA의 비공개키로 암호화된 데이터를 복호화할 수 있을까요?
브라우저는 CA 리스트를 알고 있기 때문입니다. 이말은 브라우저는 CA 리스트와 함께 CA의 공개키를 이미 알고 있다는 얘기가 됩니다.
HTTPS는 위 대칭키 암호화 방식과 비대칭키 암호화 방식을 모두 이용합니다. 먼저 비대칭키 방식을 이용해 대칭키를 주고받고, 실제 데이터는 대칭키로 암호화/복호화를 진행해 주고받습니다.
간단하게 말했지만 실제는 좀 더 복잡합니다. 먼저 간략하게 설명하자면
handshake -> 통신 -> 통신종료
과정으로 진행됩니다. 좀 더 자세히 HTTPS 통신 과정을 알아보겠습니다.
SSL 통신은 데이터를 주고받기 전에 서버가 신원이 검증된 서버인지
, 어떻게 데이터를 암호화 할지
등에 대해 핸드쉐이크 과정을 통해 확인합니다.
SSL 인증서
를 전달합니다.pre master secret
이라는 키를 생성합니다.pre master secret
은 임시적인 보안키입니다.공개키
방식을 이용합니다. SSL 인증서에는 서버의 공개키가 포함되어 있기 때문에 이를 통해 pre master secret
키를 암호화해 전달합니다.pre master secret
복호화pre master secret
을 복호화합니다.master secret
을 통해 세션키를 생성하고 세션키를 이용해 서로가 데이터를 주고받을 때 암호화/복호화
를 수행합니다.통신 단계는 클라이언트와 서버가 데이터를 주고받는 단계입니다.
데이터의 전송이 모두 끝나면 SSL 통신이 끝났음을 서로에게 알려줍니다. 이때 master secret
은 폐기 합니다.
가비아에서 도메인을 하나 구매합니다.
DNS에 도메인을 등록합니다. 가비아의 DNS 설정으로 가서 아래와 같이 설정합니다. 값/위치에는 NGINX를 설치할 EC2의 IP주소를 기입합니다.
아래의 명령어를 통해 EC2에 NGINX를 설치해줍니다.
sudo apt update
sudo apt install nginx
HTTPS는 통신과정에서 인증서를 필요로 하기 때문에 인증서를 발급해야 합니다.
이를 간단하게 진행해주는 Certbot을 설치해줍니다. Certbot은 무료 오픈소스 소프트웨어로 Let's Encrypt 인증서를 통해 HTTPS 설정을 가능하게 합니다.
아래의 명령어를 통해 Certbot을 설치합니다.
sudo snap install certbot --classic
Certbot은 도메인에 인증서를 발급해주면서 NGINX에 관련 설정을 자동으로 세팅해줍니다.
아래 명령어를 입력해 인증서를 발급합니다.
sudo certbot --nginx -d {도메인}
위 명령어 사용시 이메일을 입력하라는 명령이 나올텐데 이메일을 입력해주고 이메일에서 인증을 눌러주면 설정이 완료됩니다.
아래 경로로 이동해 default
파일을 수정해줍니다.
/etc/nginx/sites-available
default
파일을 열어보면 cerbot이 자동으로 https 관련 설정을 해줄 것입니다.
하지만 자동설정만은 https 설정만 해줄 뿐이지 리버스 프록시의 역할등의 추가적인 설정이 필요합니다.
server {
server_name codesquad-project.site; # managed by Certbot
location / {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; # 클라이언트가 프록시 처리한 모든 서버의 IP 주소 목록
proxy_set_header X-Forwarded-Proto $scheme; #프록시 서버의 HTTP 응답이 HTTPS로 변환
proxy_set_header X-Real-IP $remote_addr; # 실제 방문자의 원격 ip 주소
proxy_set_header Host $http_host; # 클라이언트가 요청한 원래 호스트 주소
proxy_pass http://{private-ip}:8080; # 프록시 해줄 서버의 IP
}
listen [::]:443 ssl ipv6only=on; # managed by Certbot
listen 443 ssl; # managed by Certbot
# SSL 인증 설정
ssl_certificate /etc/letsencrypt/live/codesquad-project.site/fullchain.pem; # managed by Certbot
ssl_certificate_key /etc/letsencrypt/live/codesquad-project.site/privkey.pem; # managed by Certbot
include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
}
server {
# http로 요청이 오면 https로 리다이렉트
if ($host = codesquad-project.site) {
return 301 https://$host$request_uri;
} # managed by Certbot
listen 80 ;
listen [::]:80 ;
server_name codesquad-project.site;
return 404; # managed by Certbot
}
모든 설정이 완료되었으니 NGINX를 재시작 해줍니다.
sudo systemctl restart nginx
certbot을 통해 간단하게 HTTPS 통신을 적용할 수 있었습니다.
또한 NGINX를 리버스 프록시 처럼 사용하면서 클라이언트가 Spring WAS에 직접적으로 연결되지 않게 되고 WAS가 늘어나게 되어도 SSL 인증서를 추가로 발급받지 않게 되니 확장성 측면에서도 좋을 것 같습니다.