안녕하세요! 오랜만에 보안 이야기로 돌아온 '하늘미르'입니다.
요즘 웹이나 앱 서비스를 만들다 보면 '보안'이라는 단어가 정말 뗄 수 없는 존재가 된 것 같아요. 사용자 데이터는 칼같이 지켜야 하고, 로그인 과정도 허술하면 큰일 나니까요.
그런데 막상 보안을 공부하려고 하면 TLS, OAuth, JWT 같은 낯선 용어들이 한꺼번에 쏟아져 나와 머리가 지끈거리신 적 없으신가요?
저도 처음엔 그랬습니다. "이게 다 뭐람..." 하면서 수많은 기술 문서를 뒤적이던 기억이 생생하네요. 하지만 각 기술이 왜 필요하고 어떤 문제를 해결하는지 알고 보면, 생각보다 훨씬 재미있게 느껴진답니다!
그래서 오늘은 저와 함께 웹 보안의 핵심, '암호화 프로토콜과 표준'의 세계로 여행을 떠나보려 합니다.
커피 한 잔 준비하시고, 편안한 마음으로 따라와 주세요. 🚀
🏗️ 기술 배경: 왜 모든 통신은 암호화되어야 할까?
인터넷이 처음 세상에 나왔을 때, 모든 정보는 암호화되지 않은 평문(Plain Text)으로 전송되었습니다.
마치 투명한 유리 상자에 내용물을 담아 보내는 것처럼, 누구나 중간에서 그 내용을 엿볼 수 있었죠.
이런 심각한 문제를 해결하기 위해 1990년대 넷스케이프에서 SSL(Secure Sockets Layer)이라는 기술을 개발했습니다.
이것이 바로 오늘날 우리가 아는 HTTPS의 시초가 된 기념비적인 기술입니다.
암호화 프로토콜은 인터넷 세상에서 데이터를 안전하게 주고받기 위해 모두가 따르기로 한 '약속' 또는 '규칙'입니다. 택배 상자를 아무도 못 열게 특수 제작된 테이프로 단단히 봉인하는 것과 같아요!
하지만 시간이 지나면서 SSL에도 여러 보안 취약점이 발견되었습니다.
그래서 국제 인터넷 표준화 기구인 IETF(Internet Engineering Task Force)가 이를 대대적으로 개선하여 TLS(Transport Layer Security)라는 새로운 표준을 만들게 됩니다.
그 후로도 TLS는 계속 발전하여 현재는 TLS 1.3 버전이 가장 널리 사용되고 있답니다.
💡 핵심 개념: TLS, OAuth, JWT 완전 정복
현대 웹 보안을 이야기할 때 절대 빼놓을 수 없는 세 명의 주인공이 있습니다.
바로 TLS, OAuth 2.0, 그리고 JWT입니다. 이 세 가지가 각각 어떤 역할을 하는지 정확히 아는 것이 정말 중요합니다.
1. TLS 1.2 vs TLS 1.3: 더 빠르고 더 안전하게
TLS는 웹 브라우저와 서버 간의 모든 통신 데이터를 암호화하는 역할을 합니다.
우리가 웹사이트 주소창에서 안심의 상징인 자물쇠 아이콘(🔒)을 볼 수 있는 이유죠.
특히 최신 버전인 TLS 1.3은 이전 1.2 버전에 비해 속도와 보안 양쪽에서 크게 향상되었습니다.
| 구분 | TLS 1.2 | TLS 1.3 | 개선 효과 |
|---|---|---|---|
| 핸드셰이크 과정 | 2-RTT (왕복 2번) | 1-RTT (왕복 1번) | 연결 지연시간 50% 감소 |
| 암호화 스위트 | 37개 (취약점 포함) | 5개 (강력하고 검증된 것만) | 보안성 대폭 강화 |
| Forward Secrecy | 선택적 지원 | 필수 지원 | 과거 통신 데이터 보호 |
쉽게 말해, TLS 1.3은 더 빨리 연결되고, 구식이고 취약한 암호화 방식은 아예 사용하지 못하도록 강제하는 셈입니다.
이는 사용자 경험과 보안 수준을 동시에 높이는 중요한 발전입니다.
2. OAuth 2.0 & OpenID Connect: 권한과 인증의 분리
"구글 계정으로 로그인하기" 기능, 다들 한 번쯤은 사용해보셨죠?
이 편리한 기능의 중심에 바로 OAuth 2.0과 OpenID Connect(OIDC)가 있습니다.
많은 분들이 이 둘을 같은 것으로 생각하시는데, 역할이 명확히 다릅니다.
• OAuth 2.0 (권한 부여): "A라는 서비스가 당신의 구글 캘린더 정보를 '읽을 수 있도록 허락'하시겠습니까?" 와 같이 특정 기능에 대한 권한을 위임받는 프레임워크입니다.
• OpenID Connect (인증): "그래서, 지금 로그인하려는 이 사용자가 '누구'인가요? (예: 이메일 주소, 이름)" 와 같이 사용자의 신원을 확인하는 역할을 합니다. OAuth 2.0 위에 구축된 레이어죠.
즉, OAuth 2.0은 '허락'에 관한 것이고, OIDC는 '신원 확인'에 관한 것입니다.
3. JWT: 정보를 담는 디지털 신분증
JWT(JSON Web Token, 발음은 'jot')는 인증이나 권한 정보를 담아 웹 환경에서 안전하게 전달하기 위한 '토큰'의 한 형식입니다.
마치 위변조 방지 홀로그램이 붙어있는 디지털 신분증과 비슷하다고 생각할 수 있어요.
JWT는 암호화된 토큰이 아닙니다! Base64로 인코딩되어 있을 뿐, 누구나 디코딩해서 내용을 볼 수 있습니다. 따라서 비밀번호나 주민등록번호 같은 민감 정보는 절대 포함하면 안 됩니다. 서명은 '위변조'를 막을 뿐, 내용을 '숨기지' 않습니다.
JWT는 헤더(Header), 페이로드(Payload), 서명(Signature)의 세 부분으로 구성됩니다.
이 세 부분은 각각 Base64URL로 인코딩되어 점(.)으로 구분됩니다. 바로 이 서명 덕분에 토큰이 중간에 변조되지 않았음을 확인할 수 있죠.
🏛️ 아키텍처: 보안 프로토콜은 어떻게 동작할까?
그렇다면 이런 프로토콜들이 실제로 어떻게 상호작용하며 우리의 정보를 지키는지 궁금하시죠?
가장 중요한 두 가지 흐름, TLS 핸드셰이크와 OAuth 2.0 인증 과정을 살펴보겠습니다.
위 그림처럼 TLS 1.3은 여러 단계로 나뉘어 있던 핸드셰이크 과정을 단순화하여 웹 페이지 로딩 속도를 높여줍니다.
특히 모바일 환경처럼 네트워크 지연에 민감한 경우 그 효과는 더욱 커집니다.
이 흐름 덕분에 우리는 페이스북이나 구글 계정 정보를 제3의 앱에 노출하지 않고도 안전하게 로그인할 수 있습니다.
만약 서비스가 해킹당하더라도 우리의 구글 비밀번호는 안전한 것이죠.
⚙️ 실무 구현 방법과 베스트 프랙티스
개념을 이해했다면 이제 실전으로 넘어가야겠죠?
서버에 TLS 1.3을 설정하고, JWT를 안전하게 사용하는 방법을 알아보겠습니다.
1. Nginx에서 TLS 1.3 설정하기
가장 널리 쓰이는 웹 서버인 Nginx에서 TLS 1.3을 활성화하는 것은 생각보다 간단합니다.
설정 파일(`nginx.conf` 또는 사이트 설정 파일)에 몇 줄만 추가하면 됩니다.
server {
listen 443 ssl http2;
server_name your_domain.com;
ssl_certificate /path/to/your/fullchain.pem;
ssl_certificate_key /path/to/your/privkey.pem;
# TLS 1.3을 최우선으로 사용하고, 하위 호환성을 위해 1.2도 포함
ssl_protocols TLSv1.3 TLSv1.2;
# TLS 1.3의 강력한 암호화 스위트만 명시적으로 지정
ssl_ciphers 'TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256';
# 클라이언트가 선호하는 암호화 스위트를 존중 (TLS 1.3 권장사항)
ssl_prefer_server_ciphers off;
# ... 기타 설정
}
이렇게 사용할 프로토콜과 암호화 스위트를 명시적으로 지정해주는 것이 보안적으로 좋습니다.
또한, Let's Encrypt 같은 무료 서비스를 이용해 SSL/TLS 인증서를 발급받고, `certbot`을 통해 자동으로 갱신되도록 설정하는 것이 현대적인 웹 서버 운영의 기본입니다.
2. JWT, 이것만은 꼭 지키자!
JWT는 매우 편리하지만, 잘못 사용하면 보안에 큰 구멍이 생길 수 있습니다.
다음 체크리스트는 반드시 기억하고 코드 리뷰 시에도 확인해 주세요.
- □ 강력한 서명 알고리즘 사용: 'none' 알고리즘은 절대 사용 금지! RS256/ES256 등 비대칭키 알고리즘 사용을 강력히 권장합니다.
- □ 짧은 만료 시간 설정: 액세스 토큰은 15분 내외로 짧게, 리프레시 토큰은 7일 정도로 설정하여 탈취 시 피해를 최소화해야 합니다.
- □ 필수 클레임 검증: `iss`(발급자), `aud`(대상자), `exp`(만료시간)는 라이브러리에만 맡기지 말고, 서버에서 반드시 직접 검증해야 합니다.
- □ 안전한 키 관리: 서명에 사용하는 비밀키는 환경 변수나 Vault 같은 안전한 곳에 보관하고, 주기적으로 교체해야 합니다.
- □ HTTPS는 기본: JWT는 항상 HTTPS 위에서만 전송되어야 토큰 탈취를 막을 수 있습니다.
특히 서명 알고리즘을 서버에서 강제하지 않으면, 공격자가 알고리즘을 'none'으로 변경하여 서명 검증을 우회할 수 있는 치명적인 취약점이 발생할 수 있으니 각별히 주의해야 합니다.
🔧 실무에서 흔히 겪는 실수와 해결 팁
이론은 완벽해도 실전에서는 예상치 못한 문제들이 발생하기 마련이죠.
제가 현업에서 자주 봤거나 직접 겪었던 실수들과 해결 팁을 공유해 드릴게요.
1. TLS 관련 트러블슈팅
이런 작은 실수 하나가 전체 페이지의 보안 수준을 낮추고 사용자에게 불안감을 줄 수 있습니다.
2. OAuth 2.0 & JWT 관련 트러블슈팅
OAuth 2.0은 절차가 복잡한 만큼 실수할 수 있는 포인트도 많습니다.
이 문제는 정말 많은 개발자들이 초기에 겪는 문제이니, 에러 메시지를 본다면 가장 먼저 확인해보세요.
🔑 JWT의 생명주기 관리: 리프레시 토큰의 역할
앞서 액세스 토큰의 만료 시간을 짧게(예: 15분) 가져가야 한다고 말씀드렸죠?
그런데 이렇게 하면 사용자는 15분마다 다시 로그인해야 하는 끔찍한 경험을 하게 됩니다.
이 문제를 해결하기 위해 등장한 것이 바로 리프레시 토큰(Refresh Token)입니다.
액세스 토큰은 유효 기간이 짧아 탈취되어도 피해가 제한적입니다.
반면, 리프레시 토큰은 훨씬 긴 유효 기간(예: 7일)을 가지며, 오직 새로운 액세스 토큰을 발급받는 용도로만 사용됩니다.
- □ 안전한 저장: 리프레시 토큰은 httpOnly, Secure 속성이 적용된 쿠키나, 앱의 안전한 저장소에 보관해야 합니다.
- □ 단 한 번만 사용: 보안 강화를 위해 리프레시 토큰을 사용해 새 토큰을 발급받으면, 기존 리프레시 토큰은 즉시 폐기하고 새로운 리프레시 토큰을 발급하는 'Refresh Token Rotation' 전략을 사용하는 것이 좋습니다.
- □ 탈취 감지: 만약 이미 사용된 리프레시 토큰으로 재발급 요청이 들어온다면, 이는 토큰이 탈취되었을 가능성이 높으므로 해당 사용자의 모든 세션을 강제 종료시켜야 합니다.
이러한 리프레시 토큰 메커니즘을 잘 구현하는 것이 현대적인 인증 시스템의 핵심 중 하나입니다.
📱 PKCE: 모바일/SPA 환경의 필수 보안 강화
전통적인 웹 애플리케이션은 Client Secret이라는 비밀키를 서버에 안전하게 보관할 수 있었습니다.
하지만 자바스크립트 기반의 SPA(Single Page Application)나 모바일 앱은 어떨까요?
이런 환경에서는 코드가 사용자 기기에 그대로 노출되므로 Client Secret을 안전하게 저장할 방법이 없습니다.
앱 코드 안에 Client Secret을 하드코딩하는 것은 우리 집 현관문 비밀번호를 문 앞에 적어두는 것과 같습니다. 누구나 앱을 디컴파일해서 비밀키를 훔쳐갈 수 있기 때문이죠.
이 문제를 해결하기 위해 등장한 기술이 바로 PKCE(Proof Key for Code Exchange, '픽시'라고 발음) 입니다.
PKCE는 Client Secret 없이도 Authorization Code 탈취 공격을 막을 수 있게 해주는 똑똑한 방법입니다.
중간에 공격자가 Authorization Code를 가로채더라도, 맨 처음에 생성된 비밀 정답(`code_verifier`)을 모르기 때문에 토큰을 발급받을 수 없습니다.
따라서 최신 OAuth 2.1 표준에서는 SPA나 모바일 앱 같은 Public 클라이언트의 경우 PKCE 사용을 의무화하고 있습니다.
⚖️ 국내외 암호화 표준과 규정
개발자라면 기술뿐만 아니라 우리가 만든 서비스가 지켜야 할 관련 법규와 표준도 알아야 합니다.
특히 개인정보를 다루는 서비스라면 이는 선택이 아닌 필수입니다.
1. 국내 vs 국제 암호화 표준
우리나라는 KISA(한국인터넷진흥원)를 중심으로 국산 암호 알고리즘을 개발하고 표준화하고 있습니다.
국제 표준인 AES와 함께 SEED, ARIA 같은 국산 알고리즘이 공공 및 금융 분야에서 널리 사용됩니다.
| 분류 | 국내 표준 (KISA 주도) | 국제 표준 (NIST 등) | 주요 적용 분야 |
|---|---|---|---|
| 블록 암호 | SEED, ARIA, LEA, HIGHT | AES, 3DES | 데이터 대칭키 암호화 |
| 해시 함수 | LSH | SHA-2, SHA-3 | 데이터 무결성 검증 |
| 전자서명 | KCDSA | RSA, ECDSA | 인증 및 디지털 서명 |
어떤 알고리즘을 선택할지는 서비스의 대상과 규제 준수 여부에 따라 달라집니다.
일반적인 글로벌 서비스는 호환성이 높은 국제 표준을, 공공기관 프로젝트는 국산 표준을 따라야 하는 경우가 많습니다.
2. KCMVP와 개인정보보호법
공공기관에 납품하거나 금융 서비스를 개발한다면 KCMVP(국가용 암호모듈 검증제도)를 꼭 알아야 합니다.
국가에서 안전성을 검증한 암호모듈만 사용해야 하는 일종의 인증 제도로, 이를 만족하는 하드웨어 또는 소프트웨어 모듈을 사용해야 합니다.
또한 GDPR(유럽 개인정보보호법), PCI DSS(신용카드 데이터 보안 표준) 등 국제 규제도 서비스의 범위에 따라 준수해야 할 수 있으므로, 프로젝트 초기 단계에서 반드시 확인해야 합니다.
혹시 실무에서 특정 보안 규제 때문에 어려움을 겪으신 경험이 있나요?
KCMVP나 ISMS-P 인증 준비 과정의 노하우나 고충을 댓글로 공유해주시면 다른 분들께 큰 도움이 될 것 같습니다! 🤝
🔮 2025년 이후, 보안 기술의 미래
기술은 계속해서 발전하고, 보안 위협 역시 그에 맞춰 진화하고 있습니다.
미래에는 어떤 기술들이 우리 디지털 세상을 지키는 중심이 될까요?
1. 양자내성암호 (PQC, Post-Quantum Cryptography)
먼 미래의 이야기 같지만, 강력한 성능의 양자컴퓨터가 개발되면 현재의 공개키 암호체계(RSA, ECC 등) 대부분이 무력화될 수 있습니다.
이에 대비하여 양자컴퓨터로도 해독하기 어려운 새로운 암호 알고리즘, 즉 양자내성암호(PQC)로의 전환이 이미 시작되고 있습니다. NIST를 중심으로 표준화가 활발히 진행 중이죠.
2. 제로 트러스트 아키텍처 (Zero Trust Architecture)
"내부망은 안전하고 외부망은 위험하다"는 기존의 경계 기반 보안 모델은 더 이상 유효하지 않습니다.
제로 트러스트는 "절대 신뢰하지 말고, 항상 검증하라(Never Trust, Always Verify)"는 원칙 아래, 네트워크 위치에 상관없이 모든 접근 요청을 의심하고 인증하는 모델입니다.
3. WebAuthn과 Passkey
비밀번호 없는 세상이 점점 가까워지고 있습니다.
WebAuthn과 이를 기반으로 한 Passkey 기술은 지문이나 얼굴 인식 같은 기기의 생체 정보를 이용해 피싱에 강하고 편리하게 인증하는 시대를 열고 있습니다. FIDO 얼라이언스를 중심으로 구글, 애플, MS가 적극적으로 도입하고 있죠.
🎯 기술 요약
지금까지 정말 많은 내용을 다루었네요!
머릿속이 복잡하실 수 있으니, 오늘 이야기한 내용의 핵심만 다시 정리해 보겠습니다.
- TLS 1.3은 이제 표준: 성능과 보안을 위해 새로운 시스템에는 TLS 1.3을 우선적으로 적용하고, 강력한 암호화 스위트만 사용해야 합니다.
- OAuth 2.0 + OIDC: 현대적인 인증 시스템의 표준으로, 권한 부여(OAuth)와 인증(OIDC)을 분리하여 안전하고 확장성 있게 구현합니다.
- JWT는 신분증, 아닌 비밀 노트: JWT는 서명을 통해 위변조를 막을 뿐, 내용이 암호화되지 않으므로 절대 민감 정보를 담지 말아야 합니다.
- 모바일/SPA엔 PKCE 필수: Client Secret을 안전하게 저장할 수 없는 환경에서는 Authorization Code 탈취 공격을 막기 위해 PKCE를 반드시 사용해야 합니다.
- 규정 준수는 기본: 서비스 대상에 따라 KCMVP, 개인정보보호법(신용카드/계좌번호 암호화) 등 국내 규제를 반드시 확인하고 준수해야 합니다.
- 미래를 향한 준비: 양자내성암호(PQC), 제로 트러스트, Passkey 등 차세대 보안 기술에 대한 지속적인 관심과 준비가 필요합니다.
이 여섯 가지만 잘 기억하셔도 오늘 포스팅의 90% 이상을 가져가시는 겁니다!
🏁 마무리하며
오늘은 웹 보안의 근간을 이루는 암호화 프로토콜과 표준에 대해 알아보았습니다.
처음에는 낯설고 복잡하게 느껴질 수 있지만, 하나씩 뜯어보면 모두 우리가 만드는 서비스를 더 안전하고 신뢰성 있게 만들기 위한 약속들이죠.
제가 신입사원이던 시절, 보안은 그저 '귀찮은 절차'라고 생각했던 적이 있습니다. 하지만 한 번의 보안 사고가 얼마나 큰 금전적, 신뢰의 손실로 이어지는지 직접 겪고 나서는 생각이 180도 바뀌었죠. 보안은 비용이 아니라, 고객과의 신뢰를 지키는 가장 중요한 투자입니다.
이 글이 여러분의 서비스에 '튼튼한 보안'이라는 날개를 달아주는 데 작은 도움이 되었으면 좋겠습니다.
궁금한 점이 있다면 언제든지 댓글로 질문해주세요.
긴 글 읽어주셔서 진심으로 감사합니다!