TLS
개요
TLS(Transport Layer Security)는 컴퓨터간 통신에서 서버와 클라이언트간의 보안된 프라이빗(private) 통신을 도와주는 암호화 프로토콜입니다. "대칭형 암호키"를 사용하여 서버와 클라이언트간의 통신을 암호화하고, 이메일, 메신저, voIP 등에 사용되지만 HTTPS로서 가장 널리 사용됩니다.
용어
SSL(Secure Sockets Layer)는 넷스케이프에서 94~96년에 네비게이터 브라우저의 HTTPS 보안 프로토콜을 추가하면서 개발된 사양입니다. 1999년부터는 IETF(국제 인터넷 표준화 기구)에서 개발된 TLS가 표준이되었고 현재는 2018년 8월에 지정된 TLS 1.3 버전이 표준입니다.
HTTPS는 TLS위에서 HTTP통신을 하는 프로토콜입니다. HTTP는 80번 포트를 사용하지만, HTTPS는 443번 포트를 사용합니다.
HTTP vs HTTPS 예시
Wireshark는 오픈소스 패킷 분석 툴입니다. 네트워크간의 패킷을 캡쳐하여 분석할 수 있는 툴로, 이를 사용하여 HTTP와 HTTPS의 차이를 비교해보겠습니다.
-
HTTP 테스트로 HTTP Forever라는 사이트에 접속한 패킷을 분석하였습니다.
위 화면과 같이 중간에 HTML 페이지 응답이 암호화되지 않고 노출됩니다. 이는 단적인 예로 로그인 폼에서 아이디 비밀번호를 입력한 POST 요청의 Body 또한 중간에 통신이 탈취되었을때 암호화되어 있지 않습니다.
-
HTTPS 반면에 HTTPS 요청의 경우, TLS 프로토콜을 거쳐 암호화 되었기 때문에 탈취된 패킷에서도 정보를 읽을 수 없습니다.
대칭형 키 알고리즘과 TLS 인증서
Node.js 대칭형 키 암호화 예제
실제 인증서와는 다르지만, 개념적으로 TLS 암호화 방식을 이해하기 쉽도록 Node.js에서 대칭형 키 알고리즘을 사용한 코드입니다
다음 커맨드를 통하여 각각 privkey.pem
그리고 fullchain.pem
이라는 Private, Public 키를 생성합니다.
# Private 키 생성
openssl genpkey -algorithm RSA -out privkey.pem
# Private 키로부터 Public 키 생성
openssl rsa -pubout -in privkey.pem --out fullchain.pem
다음과 같은 index.js
자바스크립트 파일을 생성합니다.
const fs = require("fs");
const crypto = require("crypto");
// 원본 메세지
const originalMessage = JSON.stringify({ id: "test", password: "test123!" });
// 원본 메세지 버퍼로 변환
const message = Buffer.from(originalMessage, "utf8");
// Public 키 불러오기
const publicKeyPEM = fs.readFileSync("fullchain.pem", "utf8");
// 원본 메세지 암호화
const encryptedMessage = crypto.publicEncrypt(
{ key: publicKeyPEM, padding: crypto.constants.RSA_PKCS1_PADDING },
message
);
console.log("-----원본 메세지-----");
console.log(originalMessage);
console.log("---------------------\n");
console.log("----암호화 메세지----");
console.log(encryptedMessage.toString("base64"));
console.log("---------------------\n");
// Private 키 불러오기
const privateKeyPEM = fs.readFileSync("privkey.pem", "utf8");
// 암호화 메세지 (base64) 버퍼로 변환
const base64Message = Buffer.from(
encryptedMessage.toString("base64"),
"base64"
);
// 복호화
const decryptedMessage = crypto.privateDecrypt(
{ key: privateKeyPEM, padding: crypto.constants.RSA_PKCS1_PADDING },
base64Message
);
// 복호화 메세지 출력
console.log("----복호화 메세지----");
console.log(decryptedMessage.toString("utf8"));
console.log("---------------------");
위 코드를 node index.js
로 실행하게되면 다음과 같이 로그가 콘솔에 기록됩니다:
-----원본 메세지-----
{"id":"test","password":"test123!"}
---------------------
----암호화 메세지----
Fa9BOuQN2Lt+aolzvWk6gzigQONTmRDWxXowZ6eQpGz7W3YKBHokAQ7dNU9BpTxHhEH38AFGp4+VSduNlGqCEtXAdlt4maaDKcxJD4JCEyDsegNwzs2Ps8f8iMqblCwsW8ZV8bgfB6XNP3NXAJX7mtz1GLMBCyZJsaYIe8m/GeSthBLW8pjUb/GG4YIZspeXqvw2aZ4OILxtQSiYptPPKIXsi1PTP0tKKs7cNr8C9lA0TntOTg645TU526MnEIf62ecm4xcKNgMI7JXhdfcguHvmajbbdniBidusNFoQDr/IhhYTZP+XuNuRWHfmjGpGKucQ0mhKOGKwzH/2thvx+w==
---------------------
----복호화 메세지----
{"id":"test","password":"test123!"}
---------------------
서버와 클라이언트는 symmetricKey
라는 키(인증서)를 공유하여 암호화하고 복호화하고, 중간에 패킷은 암호화되어 키(인증서)가 없으면 정보를 해독할 수 없게됩니다.
TLS 인증서 제공방식
도메인 구매를 도와주는 업체(GoDaddy, AWS, 호스팅 KR 등)들에서 일반적으로 인증서도 함께 판매하거나 제공합니다. 또는, Let's Encrypt와 같은 비영리 인증서 기관의 certbot와 같은 툴로 직접 인증서를 발급하고 관리할 수 도 있습니다.
TLS 인증서 특성상 만료일이 있기때문에 정기적으로 재발급을 해야합니다. 업체를 통해 유료 인증서를 제공받는 경우 대부분의 경우 자동으로 재발급을 관리해줍니다. Let's Encrypt Certbot을 사용한 경우 Linux 계열의 운영체제 같은 경우 Crontab, 윈도우 계열은 Task Scheduler 등을 사용하여 재발급하도록 권장합니다.
TLS 인증서 관리 방법
-
AWS 인증서 관리 툴을 통하여 인증서를 발급하고 관리할 수 있습니다. ACM을 통하여 발급받은 인증서는 무료입니다. 다만, 해당 인증서를 연결시켜 사용할 AWS ALB (Application Load Balancer) 또는 AWS CloundFront 등의 비용이 사용량에 따라 청구됩니다. (AWS 로드밸런서 가격 안내 / AWS CloundFront 가격 안내)
또한, ACM을 통하여 발급된 인증서는 만료일이 가까워지면 자동으로 재발급을 관리해줍니다.
-
Let's Encrypt Certbot
Certbot 웹사이트로 이동하여 웹 서버 소프트웨어명과 운영체제명을 선택하여 안내를 따라서 인증서를 발급하고 적용할 수 있습니다.
이미 발급받은 상태라면, 인증서가 발급되어 있는 서버에서 다음과 같은 커맨드로 인증서 관리가 가능합니다.
-
인증서 조회
sudo certbot certificates
아웃풋 설명
-
인증서 재발급 테스트
sudo certbot renew --dry-run
-
인증서 재발급
sudo certbot renew
-
인증서 재발급 스케줄러 조회
# 다음중 하나의 경로에서 인증서 재발급 스케줄러가 등록되었는지 확인합니다 (우분투 기준) /etc/crontab/ /etc/cron.*/* systemctl list-timers
-