이번 글에서는 필자가 공부한 암호화 관련 정보를 정리하고 HTTPS와 SSL/TLS에 대해 이해하고자 글을 정리한다.
암호화 기초는 사실 가져다가 쓰기만 했고 그런가보다~ 했는데 깔끔하게 이를 정리하려고 한다.
해당 글은 생활코딩에 올라와 있는 HTTPS와 SSL 인증서의 흐름을 참고해서 정리했고, 필자의 mini pc 환경에서 실습을 진행했다.
0. 들어가기 전에
알고리즘(Algorithm)이란?
알고리즘을 사전적으로 정의하면 어떤 의미일까?
어떠한 문제를 해결하거나 특정 작업을 완수하기 위해 정의된 명확하고 단계적인 절차나 방법의 집합
다시 쉽게 정리하면 특정 목적을 위해 정의한 절차 혹은 방법을 알고리즘이라고 한다.
1. 암호화 기초 정리
암호화란 무엇인가?
위키피디아 정의에 따르면 승인된 당사자만이 해독할 수 있는 방식으로 정보를 변환하는 과정을 말한다.
(출처 : https://ko.wikipedia.org/wiki/암호화)
쉽게 말하자면 규칙을 아는 사람 혹은 열쇠를 가진 사람만이 되돌릴 수있는 방식으로 정보를 변환하는 것이다.
찾아보니 케르크호프스의 원칙이라는 것이 존재한다.
“알고리즘(섞는 방법)은 온 세상이 알아도 안전해야 한다. 비밀은 오직 열쇠뿐이어야 한다.”
대칭키과 비대칭키
대칭키는 대칭이되는 키, 비대칭키는 비대칭인 키!
무엇을 기준으로 대칭을 이루는건가? 그것은 바로 암호화한 데이터를 기준으로 한다.
암호화를 하면 이를 복호화해서 보는 행위가 있어야 원래 데이터를 명확하게 알 수 있다.
예를 들어, 키메라가 회사 동료에게 데이터 AAA를 전달한다고 하자.
AAA를 특정 키(Key1)를 통해서 암호화를 진행하면 회사 동료는 AAA가 아닌 BPQIRKJDF같은 키를 받는다고 하자.
이렇게 데이터를 주고 받는 과정에서 key1를 이용해서 복호화를 진행한다면?
그러면 그것은 대칭키이다.
이렇게 데이터를 주고 받는 과정에서 key1이 아닌 다른 키 key2를 이용해서 복호화를 진행한다면?
암호화, 복호화가 동일한 키를 이용해서 진행되지 않으므로 비대칭 키라고 한다.
공개키와 비공개키
그렇다면 공개키와 비공개키는 뭔가? (공키는 공대키메라!)
말 그대로 공개키는 공개된 키이고 비공개키는 공개되지 않은 키다.
키를 공개하게 되면 모든 사람이 접근 가능한 것이고, 공개하지 않고 각자 개인들만 사용한다면 비공개키이다.
그래서 비공개키를 개인키 라고도 부른다.
대칭키와 비대칭키, 그리고 공개키와 비공개키의 관계
앞서 설명한 키에 대한 개념들은 완전히 별개의 것이 아니라, 암호화 시스템 안에서 서로 얽혀 있는 개념이다.
암호화와 복호화의 '구조'를 기준으로 이 둘을 연결하면 다음과 같다.
1. 대칭을 이루려면? (대칭키 구조)
- 원리: 암호화하는 키와 복호화하는 키가 완벽히 동일하면 된다.
- 결론: 즉, 데이터를 주고받는 양측이 단 하나의 동일한 비밀키(Secret Key)를 공유하여 사용하는 방식!
그러니까 대칭키는 비공개해야하는 키다. 왜냐? 이 키가 털리는(?) 순간 다 뚫려버린다! 같은 키로 복호화해버리면 다 들키기 때문!
2. 비대칭을 이루려면? (비대칭키 구조)
- 원리: 암호화하는 키와 복호화하는 키가 분리되어 따로 존재
- 결론: 키가 달라야 하므로 필연적으로 두 개의 키가 필요하며, 이것이 바로 모두에게 열려 있는 '공개키'와 나만 안전하게 보관하는 '비공개키(개인키)'를 한 쌍으로 사용하는 방식.


글로 정리하자.
- 대칭키 알고리즘: 양측이 하나의 '비밀키(Secret Key)'를 공유하여 사용
- 비대칭키 알고리즘: 목적에 따라 '공개키(Public Key)'와 '비공개키(Private Key)' 한 쌍을 사용
개인키는 또 뭐야?
여기서 개인키라는 소리를 들어봤을 듯 한데, 개인키는 말 그대로 개인이 가지고 있어야 하는 키를 말한다.
비대칭키 시스템에서 공개키(Public Key)와 수학적으로 한 쌍을 이루며, 오직 소유자 본인만이 안전한 곳에 보관하고 절대 외부에 노출해서는 안 되는 유일한 키를 의미한다.
결국에 비대칭키 프로세스에서 비공개키가 결국 개인키다. 왜냐? 공개되면 안되는 키니까!
2. SSL/TLS 그리고 SSL 인증서 + 대칭키 생성 실습
SSL(Secure Socket Layer)?
SSL은 인터넷을 통해 전달되는 데이터가 해커에게 탈취되거나 조작되지 않도록, 클라이언트(브라우저)와 서버 간의 통신을 암호화하는 글로벌 표준 보안 '프로토콜(규약)'이다.
SSL 인증서?
SSL 프로토콜이 통신을 암호화하는 '행위'나 '규칙'이라면, SSL 인증서는 그 암호화를 시작하기 위해 서버가 클라이언트에게 제시하는 '디지털 신분증'이다.
HTTP에 SSL을 적용하면 HTTPS가 되는 것이다. HTTPS로 인정받기 위해서는 SSL인증서가 필요한 것이다.
필자는 다음을 통해 실습을 했다.
# 1. 원본 데이터 생성 (평문 준비)
# 'this is the plain text'라는 문자열을 담은 plaintext.txt 파일을 생성합니다.
echo 'this is the plain text' > plaintext.txt;
# 2. 대칭키 암호화 진행 (평문 -> Base64 텍스트 암호문)
# OpenSSL을 사용하여 입력된 파일(-in plaintext.txt)을 암호화(-e) 합니다.
# 알고리즘은 Triple DES(-des3)를 사용하며, 보안 강화를 위해 무작위 데이터(-salt)를 추가합니다.
# 핵심: -a 옵션을 추가하여, 터미널에서 깨져 보이는 바이너리가 아닌 안전한 Base64 텍스트 형태로 변환합니다.
# 결과물은 ciphertext.txt 라는 텍스트 파일로 출력(-out)됩니다.
openssl enc -e -des3 -salt -a -in plaintext.txt -out ciphertext.txt;
# 3. 대칭키 복호화 진행 (Base64 텍스트 암호문 -> 평문 복원)
# OpenSSL을 사용하여 암호화된 파일(-in ciphertext.txt)을 복호화(-d) 합니다.
# 핵심: 암호화할 때 -a 옵션을 썼으므로, 복호화할 때도 -a 옵션을 넣어 Base64 디코딩을 처리하도록 해야 합니다.
# 암호화할 때 사용했던 동일한 알고리즘(-des3)과 '정확히 동일한 비밀번호(대칭키)'를 입력해야만 데이터가 정상적으로 복원됩니다.
# 복원된 결과물은 plaintext2.txt 라는 새로운 파일로 출력(-out)됩니다.
openssl enc -d -des3 -a -in ciphertext.txt -out plaintext2.txt;
우분투 환경에서 openssl 은 네트워크 통신을 안전하게 보호(암호화)하는 데 쓰이는 프로그램이다.
대칭키 알고리즘을 위해 des3라는 알고리즘을 사용했다.
중도에 입력을 하다 보면 다음과 같이 물어본다.
// 암호화 시에 대칭키를 요청
enter DES-EDE3-CBC encryption password:
Verifying - enter DES-EDE3-CBC encryption password:
// 복호화 시에 대칭키를 요청
enter DES-EDE3-CBC decryption password:
필자는 비밀번호를 "1234"로 입력해서 진행했다.
중도에 base64를 쓰지 않으면 깨지는게 싫어서 그렇게 설정했다.

3. 비대칭키 실습
이번에는 비대칭키를 만들어보려고 한다.
공개키와 비공개키(개인키)를 만들어서 암복호화에 사용할 것이다.
# RSA 알고리즘을 사용하여 2048비트 길이의 강력한 개인키를 생성합니다.
# 결과물은 private_key.pem 이라는 파일로 저장됩니다.
openssl genrsa -out private_key.pem 2048;
# (확인용) 생성된 개인키의 내용을 텍스트 형태로 확인해 봅니다.
# '-----BEGIN PRIVATE KEY-----' 로 시작하는 복잡한 문자열을 볼 수 있습니다.
cat private_key.pem;
# 만들어둔 개인키(-in private_key.pem)를 읽어 들여서,
# 대중에게 공개할 수 있는 형태(-pubout)의 공개키를 추출해 public_key.pem 으로 저장합니다.
openssl rsa -in private_key.pem -pubout -out public_key.pem;
# (확인용) 생성된 공개키를 확인해 봅니다.
# '-----BEGIN PUBLIC KEY-----' 로 시작하며, 개인키보다 훨씬 길이가 짧습니다.
cat public_key.pem;
# 'Hello, Asymmetric World!' 라는 테스트 문구를 message.txt 파일에 저장합니다.
echo 'Hello, Asymmetric World!' > message.txt;
# pkeyutl: 비대칭키(Public Key) 작업을 수행하는 명령어입니다.
# -encrypt: 암호화를 진행합니다.
# -pubin -inkey public_key.pem: 공개키를 열쇠로 사용하겠다고 명시합니다.
openssl pkeyutl -encrypt -pubin -inkey public_key.pem -in message.txt -out encrypted.bin;
# (확인용) 암호화된 파일은 대칭키 때와 마찬가지로 깨진 바이너리 데이터입니다.
cat encrypted.bin;
# -decrypt: 복호화를 진행합니다.
# -inkey private_key.pem: 나의 개인키를 열쇠로 사용하겠다고 명시합니다.
# 정상적으로 복원된 데이터를 decrypted.txt 파일로 저장합니다.
openssl pkeyutl -decrypt -inkey private_key.pem -in encrypted.bin -out decrypted.txt;
# (최종 확인) 원본 데이터가 정상적으로 복구되었는지 출력해 봅니다.
cat decrypted.txt;
특이한 것은 개인키를 만들엇는데 이 개인키에서 일부를 추출해서 공개키를 만들었다는 점이다.

4. CA(Certificate Authroity, 공인 인증 기관)과의 프로세스 정리
여태 우리는 ubuntu에서 제공하는 openssl 기능을 사용해서 공개키와 비공개키를 생성해서 직접 암복호화를 진행했다.
하지만 우리가 이렇게 할 필요는 없다.
CA에서 우리 도메인과 공개키를 제출해서 SSL 인증서를 받급받으면 알아서 해준다.
여기서 공개키/비공개키를 CA에 우리가 제출하면 안돼고 공개키만 제출해야한다.
왜 비공개키(개인키)는 제출하면 안 될까? (보안의 대원칙)
앞서 강조했듯 개인키는 "오직 소유자 본인만이 안전한 곳에 보관하고 절대 외부에 노출해서는 안 되는 유일한 마스터키"다.
만약 CA가 우리 대신 개인키를 만들어 주거나 우리가 CA에게 개인키를 보낸다면, 전송 과정에서 키가 유출될 위험이 있고 근본적으로 '제3자인 CA 기관도 우리의 마스터키를 알게 된다'는 치명적인 보안 결함이 발생한다.
따라서 실제 인증서 발급은 철저하게 다음과 같은 구조로 진행된다.
1. CSR (인증서 발급 요청서) 작성
우리는 서버 내부에서 생성한 개인키를 아무도 모르게 깊숙이 숨겨둔다. 그리고 대중에게 공개해도 되는 우리의 '공개키'와 서비스의 '도메인 정보(예: kimera.com)'만을 예쁘게 하나로 묶는다.
이를 CSR(Certificate Signing Request)이라고 부르며, 우리는 오직 이 CSR 파일만을 CA에게 제출한다.
2. CA의 전자서명과 인증서 탄생
CA는 우리가 제출한 CSR 내용과 도메인의 실제 소유주가 맞는지 깐깐하게 심사한다. 심사를 통과하면, CA는 제출받은 문서에 'CA 기관 본인들의 개인키'로 쾅 하고 도장(전자서명)을 찍어서 돌려준다. 이렇게 CA의 보증 도장이 찍혀서 돌아온 결과물이 바로 최종적인 'SSL 인증서'다.
3. 브라우저의 자동 검증 메커니즘
이제 클라이언트(크롬, 사파리 등)가 우리 서비스에 접속하면, 서버는 방금 발급받은 이 SSL 인증서를 먼저 내민다.
전 세계의 웹 브라우저들은 프로그램이 설치될 때부터 이미 유명 CA들의 '공개키'를 내부에 내장하고 있다.
브라우저는 내장된 CA의 공개키로 인증서에 찍힌 도장을 열어보고, "검증된 기관이 보증하는 진짜 서버가 맞군!" 하며 즉시 신뢰 상태로 전환한다. 이후 알아서 대칭키를 교환하고 안전한 암호화 통신(HTTPS)을 시작한다.
위 과정은 클라우드 인프라 도움 없이 온프레미스 환경이나 단일 서버에서 직접 서비스를 구축할 때 하는 과정이다.
들어보면 뭐 그런가보다 하는데 필자는 정확한 프로세스를 이해하기 위해서 그림으로도 그려보았다.
큰 흐름을 중심적으로 이해하기로 했고, Gemini와의 문답을 통해서 최대한 정리를하기 위해 노력했다.

잘 안보이니 확대해서 보도록 하자!
🔒 SSL/TLS 발급 및 HTTPS 통신 완벽 시나리오
[1단계: 사전 준비 및 SSL 인증서 발급]
1. 서버 생성: 서비스를 운영할 서버 인프라를 구축합니다.
2. 비대칭키 생성:
서버 내부에서 비대칭키 방식의 '서버 공개키'와 '서버 개인키' 한 쌍을 생성합니다. (개인키는 서버 깊숙한 곳에 꽁꽁 숨깁니다.
3. CSR 생성 및 제출:
대중에게 공개할 '서버 공개키'와 도메인 정보(예: kimera.com)를 묶어 CSR(인증서 발급 요청서)을 만든 뒤, CA(공인 인증 기관)에 제출합니다.
4. CA 심사: CA는 제출된 CSR 내용과 실제 도메인 소유권이 일치하는지 깐깐하게 검증합니다.
5. SSL 인증서 발급:
심사에 통과하면, CA는 해당 문서에 자신들의 'CA 개인키'로 전자서명(도장)을 찍어 서버에게 돌려줍니다.
(최종 SSL 인증서 = 텍스트 상태의 서버 공개키 원본 + CA의 전자서명)
[2단계: 클라이언트 접속 및 1차 검증 (인증서 신뢰도 확인)]
6. 사용자 접속 시도: 사용자가 웹 브라우저(크롬, 사파리 등)를 실행하여 주소창에 도메인을 입력합니다.
7. 서버 요청:
브라우저가 우리 서버에 "HTTPS로 접속할래!"라고 요청을 보냅니다. (이때 대칭키를 만들 때 쓸 브라우저 측 '난수 재료 A'를 함께 보냅니다.)
8. 서버의 인증서 전달:
요청을 받은 서버는 5번에서 발급받았던 'SSL 인증서'를 브라우저에게 반환합니다.
9. 브라우저의 1차 검증 (CA 공개키 사용): 브라우저는 자신의 프로그램 내부에 이미 설치되어 있던 'CA의 공개키'를 꺼냅니다. 이 키로 인증서에 찍힌 CA의 전자서명을 풀어보고 *"아, 위조되지 않은 진짜 기관이 발급한 인증서가 맞구나!"*라고 1차 확신을 합니다.
[3단계: 신원 증명 및 2차 검증 (서버 진짜 주인 확인)]
10. 대칭키 재료 교환 (서버 개인키 사용):
서버도 대칭키를 만들 때 쓸 '난수 재료 B'를 브라우저로 보냅니다.
이때 해커의 중간 바꿔치기를 막기 위해, 2번에서 숨겨둔 '서버 개인키'를 꺼내어 재료 B에 전자서명을 쾅 찍어서 보냅니다.
11. 브라우저의 2차 검증 (서버 공개키 사용):
브라우저는 방금 받은 인증서 안에서 '서버 공개키'를 꺼냅니다.
이 키로 재료 B에 찍힌 서버의 서명을 검증합니다.
서명이 일치하면 *"이 재료를 보낸 놈은 껍데기만 복사한 해커가 아니라, 숨겨진 서버 개인키를 실제로 가진 인증서의 진짜 주인이 맞네!"*라고 2차 확신을 마칩니다.
[4단계: 대칭키 조립 및 HTTPS 통신 개시]
12. 일회용 대칭키 각자 조립:
모든 검증이 끝났고 재료도 안전하게 교환했습니다.
이제 인터넷 통신을 잠시 멈추고, 브라우저와 서버는 각자의 컴퓨터 내부(로컬)에서 [재료 A + 재료 B]를 똑같은 수학 공식에 넣고 돌립니다.
결과적으로 양쪽 컴퓨터에 완벽하게 똑같은 '일회용 대칭키(세션 키)'가 짠! 하고 도출됩니다. (검증과 생성이 완료되었다는 신호도 서로 주고받습니다.)
13. 안전한 HTTPS 통신 시작:
무겁고 복잡했던 비대칭키(공개키/개인키)는 11번을 끝으로 역할을 다했으므로 넣어둡니다.
이제부터는 방금 만들어낸 빠르고 가벼운 '일회용 대칭키'를 자물쇠 삼아, 주고받는 모든 데이터(HTML, 패스워드 등)를 암호화하여 통신합니다. 이 암호화 터널이 완성된 상태를 바로 HTTPS라고 부릅니다.
이 상호 테스트가 완벽하게 통과되는 바로 그 찰나의 순간! 브라우저는 내부적으로 "TLS Handshake(사전 준비) 최종 완료!"를 선언합니다.
이 과정을 통해 공공 인터넷 망 위에 데이터가 보호받는 '논리적 암호화 터널'이 생성된다!
인프라 설계 관점 (클라우드 환경의 적용)
이 복잡한 암호화 과정을 실제 인프라에 적용할 때, 현대의 클라우드 환경은 개발자가 직접 터미널에서 키를 관리하는 수고를 크게 덜어준다.
AWS 환경을 예로 들면, AWS Certificate Manager(ACM)가 바로 이 CA 역할을 수행한다.
ACM은 내부의 고도로 안전한 금고(KMS)를 이용해 우리의 키 쌍을 대신 생성하고 관리해 주므로, 개발자는 클릭 몇 번만으로 인증서를 발급받을 수 있다.
아키텍처 설계 시 이 발급받은 인증서를 비즈니스 로직을 처리하는 백엔드 애플리케이션(Spring Boot)에 직접 심지 않는다.
대신! 트래픽을 가장 먼저 맞이하는 ALB(Application Load Balancer)에 인증서를 장착(SSL Termination)한다.
이렇게 하면 무겁고 복잡한 비대칭키 암복호화 연산은 로드밸런서 인프라가 전담하게 된다.
결과적으로 내부망에 위치한 WAS는 암호화 해제 작업으로 인한 CPU 부하 없이, 대용량 트래픽의 비즈니스 로직 처리에만 온전히 자원을 집중할 수 있는 고가용성 아키텍처가 완성된다.
아무래도 이러한 편리한 기능이 있으니 AWS를 쓸 수 밖에 없지 않나 싶다.
확실한 성능에 전적으로 책임까지 진다니! 돈만 조금 내면 다 관리해주는 것이다!
이번 글에서는 암호화 기초와 SSL의 작동 원리를 알아보고 ubuntu 환경에서 실습해보았다.
그리고 CA에 대해서도 알아보았고 내 나름대로 TLS Handshake 의 프로세스에 대해 간략하게 다뤄보았다.
생활코딩의 글을 전적으로 따라가며 중간중간 AI에게 피드백을 받아가며 정리했다.
특히나 대칭키 비대칭키, 공개키 비공개키(개인키) 이 개념이 자꾸 헷갈려서 다 정리해버렸다.
또한 TLS Handshake의 과정에서는 암호화에 대해서 좀 더 깊은 이해가 필요하다는 생각이 들며 추후에 이에 대해 학습할 예정이다.