TLS(Transport Layer Security)는 인터넷에서 주고받는 정보를 암호화하는 프로토콜이다. 넷스케이프가 만든 SSL(Secure Sockets Layer)에 바탕을 두고 IETF 가 표준으로 정리했다. 정식 명칭은 TLS 지만 아직도 SSL 이라는 말이 널리 쓰인다. HTTPS 는 TCP 443 포트에서 HTTP 를 TLS 로 감싼 것이고, TLS 자체는 HTTP 전용이 아니라 SMTP · LDAP · 데이터베이스 · OpenVPN 등 여러 프로토콜이 쓴다.
TLS 가 보장하는 것은 셋이다.
| 성질 | 수단 |
|---|---|
| 기밀성 | 합의한 세션 키로 대칭 암호화(AES-GCM · ChaCha20-Poly1305) |
| 무결성 | AEAD 의 인증 태그로 위변조를 잡는다 |
| 인증 | 인증서의 전자 서명으로 상대의 신원을 확인한다 |
현행 버전은 TLS 1.3 이다[1]. TLS 1.0 · 1.1 은 RFC 8996 으로 폐기됐고[2] TLS 1.2 이상만 쓴다. SSL 2.0 · 3.0 은 쓰지 않는다.
| 버전 | 발표 | 상태 |
|---|---|---|
| TLS 1.3 | 2018 (RFC 8446) | 현행. 핸드셰이크 1-RTT, PFS 필수, 취약한 알고리즘 제거 |
| TLS 1.2 | 2008 (RFC 5246) | 현역. 옛 클라이언트 호환을 위해 함께 연다 |
| TLS 1.1 · 1.0 | 2006 · 1999 | 폐기(RFC 8996). 끈다 |
| SSL 3.0 이하 | — | 쓰지 않는다 |
TLS 1.3 이 이전 버전과 다른 점은 다음과 같다.
TLS_AES_128_GCM_SHA256 · TLS_AES_256_GCM_SHA384 · TLS_CHACHA20_POLY1305_SHA256 등.서로의 신원을 확인하고 통신 암호화에 쓸 세션 키를 공유하는 과정이다. TLS 1.3 기준으로 다음 순서다.
key_share)을 미리 보낸다. 접속할 호스트명은 SNI 확장에 담는다.key_share 를 고른다. 이 시점에 양쪽이 Diffie-Hellman 으로 같은 비밀값을 얻고, 이후 메시지는 암호화된다.클라이언트 인증서를 요구하는 상호 인증(mTLS)이면 3단계에서 서버가 CertificateRequest 를 보내고 클라이언트도 같은 방식으로 자기 인증서와 서명을 제출한다.
클라이언트가 서버 인증서를 받아들이려면 다음이 모두 맞아야 한다.
subjectAltName 에 접속한 호스트명이 있다. commonName 만으로는 최신 클라이언트가 받지 않는다.같은 서비스를 TLS 로 여는 방법이 두 가지다.
| 방식 | 동작 | 예 |
|---|---|---|
| 암묵적 TLS | 전용 포트로 접속하면 처음부터 TLS | HTTPS 443 · LDAPS 636 · SMTPS 465 |
| StartTLS | 평문 포트로 접속한 뒤 명령으로 TLS 로 승격 | LDAP 389 + -ZZ · SMTP 587 · PostgreSQL 5432 |
StartTLS 는 포트를 하나만 쓰는 대신, 서버가 평문 연결을 허용하도록 남겨 두면 다운그레이드 위험이 있다. 승격을 강제하는 설정(OpenLDAP 의 security tls=1, Postfix 의 smtpd_tls_security_level=encrypt)을 함께 둔다.
openssl s_client -connect www.example.com:443 -servername www.example.com </dev/null 2>/dev/null | grep -E 'Protocol|Cipher'
# Protocol : TLSv1.3
# Cipher : TLS_AES_256_GCM_SHA384
폐기된 버전이 꺼져 있는지 확인하는 방법이다. 연결이 실패해야 정상이다.
openssl s_client -connect www.example.com:443 -tls1_1 </dev/null
# ... alert protocol version / no protocols available
openssl s_client -connect www.example.com:443 -tls1_2 </dev/null | head -3
openssl s_client -connect www.example.com:443 -servername www.example.com -showcerts </dev/null 2>/dev/null \
| openssl x509 -noout -subject -issuer -dates -ext subjectAltName
openssl s_client -connect ldap.example.com:389 -starttls ldap </dev/null 2>/dev/null | grep Protocol
openssl s_client -connect smtp.example.com:587 -starttls smtp </dev/null 2>/dev/null | grep Protocol
nginx 의 예다. TLS 1.2 이상만 열고 암호 스위트는 기본값에 맡긴다.
ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers off;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
ssl_session_cache shared:SSL:10m;
RHEL 9 는 시스템 전역 암호 정책이 이 값보다 우선한다. update-crypto-policies --show 로 현재 정책을 확인한다.
| 메시지 | 원인 |
|---|---|
unable to get local issuer certificate |
서버가 중간 CA 를 안 보냈거나 클라이언트에 root CA 가 없다. fullchain 을 쓴다 |
certificate verify failed: self-signed certificate |
사설 CA 를 신뢰 목록에 넣지 않았다 |
Hostname mismatch · NET::ERR_CERT_COMMON_NAME_INVALID |
접속한 이름이 SAN 에 없다 |
certificate has expired |
유효기간 초과. 갱신 자동화를 확인한다 |
no protocols available · wrong version number |
버전 · 암호 스위트가 양쪽에서 겹치지 않는다. 평문 포트에 TLS 로 붙었을 때도 난다 |
RFC 8446 — The Transport Layer Security (TLS) Protocol Version 1.3. 2026-09-20 확인. https://www.rfc-editor.org/rfc/rfc8446.html · TLS 1.2 는 RFC 5246 https://www.rfc-editor.org/rfc/rfc5246.html ↩︎
RFC 8996 — Deprecating TLS 1.0 and TLS 1.1. 2026-09-20 확인. https://www.rfc-editor.org/rfc/rfc8996.html ↩︎