dayone 서버 배포 과정 중 마지막으로 수행한 작업은 https를 적용하는 것이었습니다. http로도 통신을 원활하게 할 수 있습니다. 그럼에도 크롬에서는 주의 요함 을 나타내며 https를 적용하는 것을 권장하고 있습니다. 왜 https를 적용해야하는 것일까요?
HTTP는 두 대 이상의 컴퓨터가 데이터를 주고 받을 때 이용하는 프로토콜이며 HTTPS는 데이터 전송의 보안을 강화하기 위해 컴퓨터 끼리 주고 받는 통신에 암호화를 적용한 방식입니다.
암호화 방식에는 대칭키 방식과 비대칭키 방식이 있으며 각각의 방식에 대해서 알아보겠습니다.
대칭키 방식은 동일한 키를 통해서 데이터를 암호화하고 받는 쪽에서 복호화하는 방식입니다. 다음은 hello라는 메세지를 보내기 위한 과정입니다.

대칭키 방식은 두 통신자가 같은 키를 가지고 데이터를 암호화 하고 복호화 한다는 점이 직관적이지만 한편으로는 키가 악의적인 사용자에게 탈취된다면 기밀성이 보장되지 않는 문제가 발생할 수 있을 것 같습니다. 기밀성은 허가된 사용자만 정보에 접근할 수 있는 속성을 의미합니다.

위의 그림과 같이 외부의 사용자에게 키를 탈취 당한다면 그 누구든지 저 둘의 대화를 볼 수 있을 것입니다.
비대칭 키 방식은 공개키를 방식으로 불리며 서로 다른 키를 통해 데이터를 암호화하고 복호화하는 방식입니다. 데이터를 암호화할 때는 공개키로 암호화를 하고 복호화할 때에는 개인키를 이용합니다. 공개키와 개인키는 한 쌍이며 공개키로 암호화한 것은 오직 개인키로만 복호화할 수 있기에 누구든지 공개키를 가져도 문제가 되지 않습니다. (공개키는 누구에게나 공유 되어 있는 키이며, 개인키는 특정 사용자만 가지고 있는 키입니다.)

이렇게 한다면 외부에서 공개키를 탈취하더라도 데이터를 복호화하지 못해서 해당 내용의 정보를 볼 수 없을 것입니다.
비대칭키 방식이 만능일 것처럼 보이지만 항상 비대칭키 방식이 만능인 것은 아닙니다. 먼저 비대칭키 방식의 경우 대칭키 방식에 비해 복잡한 연산을 활용해 암호화 및 복호화 과정이 필요하기에 대칭키 방식에 비해서 통신 속도가 느리다는 단점을 가지고 있습니다. 또한 다음과 같은 사례를 보면 비대칭키 방식을 활용하더라도 데이터가 탈취될 수 있는 문제가 발생할 수 있습니다.

악의적인 사용자가 공개키를 위변저하여 클라이언트에게 제공하고 클라이언트가 암호환 데이터를 가로채 해당 정보를 볼 수 있습니다. 이를 중간자 공격이라고 합니다. 위의 그림처럼 클라이언트는 자신이 문제없이 통신을 하고 있다고 느끼지만 사실은 자신의 데이터가 탈취되고 있는 상황이 발생할 수 있습니다.
결국에는 비대칭키 방식고 대칭키 방식 모두 하나로는 온전하게 안전한 보안을 유지할 수 있는 방안은 아닙니다. 그렇다면 HTTPS는 어떻게 보안을 유지할 수 있는 것일까요?
HTTPS는 대칭키 방식과 비대칭키 방식을 모두 이용합니다. 대칭키 방식은 데이터를 암호화 하고 복호화 하는데 이용하며 비대칭키 방식은 클라이언트의 대칭키 서버의 공개키로 암호화하고 서버의 개인키로 복호화 해 서버가 클라이언트의 대칭키를 받는데 이용됩니다. 그렇다면 HTTPS에서는 어떻게 중간자 공격을 방지했을까요?
CA(인증 기관)을 통해 서버의 공개키가 변조되지 않았음을 보장함으로써 중간자 공격을 막을 수 있습니다.

서비스에 HTTPS를 적용하는 방법에는 크게 2가지 방법을 찾을 수 있었습니다.
이 둘을 비교하면 Cloudfront를 이용하면 AWS와 연동해서 작업이 가능하면 인증서를 자동으로 관리해주는 장점이 있지만 추가적인 비용이 발생할 수 있는 가능성이 있는 반면 nginx와 Let’s encrypt는 인증서를 직접 관리해야하지만 비용이 무료라는 점입니다. 저는 이 두 방식 중 무료라는 장점이 더 크게 다가와서 nginx와 Let’s encrypt를 이용해서 HTTPS를 적용했습니다.
https를 적용하기에 앞서서 ec2가 HTTPS 통신을 할 수 있게 443 포트를 인바운드 규칙에서 허용해 줍니다.
# nginx 설치 명령어
sudo apt install nginx -y
# nginx의 설치 확인 명령어
nginx -version
# nginx를 실행시키는 명령어
sudo systemctl start nginx
# ec2를 재부팅했을 때 자동으로 동작하도록 적용
sudo systemctl enable nginx
# cerbot 설치
sudo apt install certbot python3-certbot-nginx -y
# 인증서 발급
sudo certbot --nginx -d example.com(자신의 사이트) -d www.example.com(자신의 사이트)
인증서를 발급하면 certbot에서 자동으로 Nginx 설정을 수정해주어서 http 통신으로 요청을 보내더라도 https로 통신이 이루어지게 리다이랙트를 해줍니다.
해당 과정까지 끝나면 인증서 발급이 마무리가 되었지만 저희는 하나의 작업을 더 해주어야 합니다. 현재 과정을 그림으로 표현하면 다음과 같습니다.

사용자의 요청이 ec2 내부에 nginx까지는 접근했지만 해당 요청이 spring으로 이어지지 않는 상황입니다. 그렇기에 요청이 spring으로 이어질 수 있게 포트포워딩 설정이 필요합니다.
포트포워딩은 외부에서 내부 장치로 접근할 수 있도록 하기 위해 특정 포트로 들어오는 네트워크 트래픽을 내부 장치로 전달하는 것을 의미합니다. 즉, 이번에 처리해야하는 것은 HTTPS(443) 요청이 넘어오면 spring(8080)로 요청을 전달하는 설정을 nginx에서 추가해주어야 합니다.
/etc/nginx/site-avaialble/default에 다음 설정을 추가해주면 됩니다.
server {
listen 80;
server_name example.com(자신의 사이트) www.example.com(자신의 사이트);
return 301 https://$host$request_uri; # HTTP -> HTTPS 리디렉션
}
server {
listen 443 ssl;
server_name example.com(자신의 사이트) www.example.com(자신의 사이트);
ssl_certificate /etc/letsencrypt/live/example.com(자신의 사이트)/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com(자신의 사이트)/privkey.pem;
location / {
proxy_pass http://127.0.0.1:8080; # HTTPS 요청을 내부 8080 포트로 전달
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto https;
}
}
이후에 nginx의 설정 테스트를 수행하고 성공한다면 nginx를 재실행 해주면 설정이 적용됩니다.
# nginx 설정 테스트
sudo nginx -t
# nginx 재시작
sudo systemctl restart nginx