공개키 기반구조
고친 사람 github-actions[bot]
공개키 기반구조는 처음 보는 상대가 내민 공개키가 정말 그 상대의 것인지 믿게 해 줍니다. 인증서를 내주는 쪽과 받아서 확인하는 쪽이 같은 규칙을 따르도록 역할과 절차를 한 벌로 정해 둔 체계입니다. 브라우저가 처음 가 보는 웹사이트와도 곧바로 안전한 연결을 맺는 것이 이 체계 덕분입니다.
쉽고 빠른 이해
공개키 기반구조는 「이 공개키는 이 서버의 것」이라는 보증을 누가 해 주고 어떻게 확인할지 정한 약속 묶음입니다. 브라우저가 주소창에 자물쇠를 띄울 때 서버를 믿는 근거가 이 체계입니다.
이게 없으면 받은 공개키의 주인을 알 길이 없습니다. 중간에서 가로챈 쪽이 자기 공개키를 내밀어도 구별하지 못합니다.
- 인증 기관이 신청자를 확인하고 공개키와 이름을 묶은 인증서에 서명해 줍니다
- 인증 기관의 인증서에는 다시 윗단의 인증 기관이 서명해서, 서명이 여러 층으로 이어집니다
- 브라우저와 운영체제는 믿을 맨 윗단 인증 기관의 목록을 미리 갖고 있습니다
- 인증서를 받은 쪽은 서명을 한 층씩 따라 올라가 그 목록에 닿으면 믿습니다
대가는 인증 기관을 믿어야 한다는 것입니다. 인증 기관 한 곳이 뚫리면 가짜 인증서도 진짜처럼 통합니다. 인증서를 제때 갈고 거두는 운영 부담도 따라옵니다.
통신하는 양쪽이 몇 안 되고 미리 키를 주고받을 수 있으면 굳이 이 체계를 쓰지 않습니다.
상세
처음 가 본 은행 창구의 직원은 나를 모르지만 신분증을 보고 계좌를 열어 줍니다. 직원이 믿는 것은 내가 아니라 그 신분증을 내준 기관입니다. 이 일이 굴러가려면 누가 신분증을 내주는지, 창구가 무엇을 보고 진짜를 가리는지, 잃어버린 신분증을 어떻게 막는지가 미리 정해져 있어야 합니다.
공개키 기반구조(Public Key Infrastructure, PKI)는 이런 약속을 공개키에 대해 세운 것입니다. 인증서를 내주는 기관, 인증서를 받아 확인하는 쪽, 확인에 쓰는 규칙과 목록을 한데 묶어 부르는 이름입니다. 프로그램 하나나 파일 하나가 아니라 여러 역할과 절차가 모인 체계입니다.
공개키만으로는 모자란 까닭
공개키 암호는 키를 한 쌍으로 만듭니다. 공개키는 누구에게나 보여 줍니다. 짝인 개인키는 주인만 갖습니다. 공개키로 잠근 것은 개인키로만 풀립니다. 그래서 상대의 공개키만 알면 비밀을 미리 나누지 않고도 그 상대만 읽는 메시지를 보낼 수 있습니다.
문제는 공개키가 숫자 덩어리라는 점입니다. 값 어디에도 주인 이름이 적혀 있지 않습니다. 누가 만들어 내밀어도 생김새가 같습니다.
그 틈을 노리는 것이 중간자 공격입니다. 둘 사이에 끼어든 공격자가 상대의 공개키 대신 자기 공개키를 건넵니다. 보내는 쪽은 공격자가 읽는 줄 모르고 그 키로 암호화합니다.
sequenceDiagram
participant 송신 as 보내는 쪽
participant 공격자
participant 상대
상대->>공격자: 자기 공개키를 보낸다
공격자->>송신: 상대 공개키 대신 자기 공개키를 건넨다
송신->>공격자: 받은 키로 암호화해 보낸다
Note over 공격자: 자기 개인키로 풀어 읽는다
그림에서 보내는 쪽은 암호화를 제대로 했습니다. 잘못은 키를 받는 단계에서 이미 났습니다. 암호가 아무리 튼튼해도 키를 잘못 받으면 소용이 없습니다.
「이 공개키는 이 이름의 것」이라는 보증이 필요한 까닭이 여기 있습니다. 공개키 기반구조는 이 보증을 누가 하고 받는 쪽이 어떻게 확인하는지를 정합니다.
보증을 담는 인증서
보증은 인증서라는 문서에 담깁니다. 인증서에는 공개키와 그 주인의 이름이 한 묶음으로 적혀 있습니다. 양쪽이 믿는 제삼자가 그 묶음에 서명합니다. 이 제삼자를 인증 기관(Certification Authority, CA)이라고 부릅니다.
여기서 서명은 디지털 서명을 말합니다. 서명하는 쪽이 자기 개인키로 내용에서 값을 계산해 붙이면, 누구든 그의 공개키로 그 값을 확인할 수 있습니다. 내용이 한 글자라도 바뀌면 확인이 실패합니다. 누가 이름이나 키를 몰래 바꿔도 확인에서 드러납니다.
인증서에는 이 보증을 믿어도 되는 유효 기간도 함께 적힙니다. 보증을 영원히 믿게 두면 키가 오래될수록 샐 위험이 쌓이기 때문입니다.
인증서에 들어가는 칸과 적는 방식은 X.509 라는 표준이 정합니다. 웹에서 오가는 인증서는 거의 다 이 형식입니다.
체계를 이루는 역할
공개키 기반구조에는 참여자가 여럿입니다. 참여자마다 맡는 일이 갈립니다. 아래 표는 인증서 한 장을 두고 누가 무엇을 하는지 모은 것입니다.
| 역할 | 하는 일 | 웹에서 맡는 쪽 | |---|---|---| | 주체 | 자기 공개키와 이름을 인증서에 올려 달라고 신청하고, 받은 인증서를 내민다 | 웹 서버 | | 등록 기관 | 신청자가 그 이름의 주인이 맞는지 확인한다 | 대개 인증 기관이 겸한다 | | 인증 기관 | 확인이 끝난 묶음에 서명해 인증서를 내준다. 기간이 남은 인증서를 못 쓰게 돌리기도 한다(폐기) | 인증서 발급 업체 | | 신뢰 당사자 | 받은 인증서를 확인하고 믿을지 정한다 | 브라우저 | | 공개 저장소 | 인증서와 폐기 정보를 누구나 조회하게 둔다 | 인증 기관이 여는 조회 서버 |
표에서 주체와 신뢰 당사자는 서로 모르는 사이입니다. 둘을 잇는 것은 둘 다 믿는 인증 기관뿐입니다.
신뢰 당사자는 웹에서는 대개 접속하는 브라우저입니다. 서버가 거꾸로 클라이언트에게 클라이언트 인증서를 요구하면 서버도 신뢰 당사자가 됩니다.
인증서 한 장이 발급되어 쓰이기까지는 이렇게 흐릅니다.
sequenceDiagram
participant 주체
participant 기관 as 인증 기관
participant 당사자 as 신뢰 당사자
주체->>기관: 공개키와 이름을 보내 신청한다
Note over 기관: 이름의 주인이 맞는지 확인한다
기관-->>주체: 서명한 인증서를 내준다
당사자->>주체: 접속한다
주체-->>당사자: 인증서를 내민다
Note over 당사자: 서명과 기간과 폐기 여부를 확인한다
인증 기관은 발급할 때 나섭니다. 접속이 있을 때마다 서명을 새로 해 주지는 않습니다. 신뢰 당사자는 인증서에 붙은 서명만으로 인증 기관의 보증을 확인합니다. 인증서를 믿지 못하는 통신망으로 건네도 괜찮은 까닭입니다.
신뢰가 출발하는 뿌리
인증 기관의 서명을 확인하려면 그 인증 기관의 공개키가 있어야 합니다. 그런데 그 공개키가 진짜인지는 또 누가 보증할까요. 이 물음을 끝없이 거슬러 올라갈 수는 없으므로, 어딘가에서 「이것은 따지지 않고 믿는다」고 정해야 합니다.
그 출발점이 루트 인증서입니다. 루트 인증서는 인증 기관이 자기 개인키로 자기 인증서에 서명한 것이라 위에 물어볼 곳이 없습니다. 이 인증서를 가진 인증 기관을 루트 인증 기관이라고 부릅니다.
루트 인증서를 믿는 근거는 서명이 아니라 미리 받아 둔 목록입니다. 운영체제와 브라우저는 믿을 루트 인증서 목록을 설치할 때부터 갖고 들어옵니다. 이 목록을 신뢰 저장소라고 부릅니다. 앞 표의 공개 저장소는 인증 기관이 여는 서버이고, 신뢰 저장소는 내 기기 안에 든 목록입니다.
신뢰 저장소에 든 인증서를 신뢰 시작점이라고 부릅니다. 확인을 거슬러 올라가다 여기에 닿으면 더 따지지 않는다는 뜻에서 붙은 이름입니다. 웹에서는 대개 루트 인증서가 곧 신뢰 시작점입니다.
루트 아래로 뻗는 계층
루트 인증 기관은 웹 서버 같은 최종 주체의 인증서에 직접 서명하지 않는 편입니다. 대신 중간 인증 기관에게 인증서를 내줍니다. 최종 주체의 인증서에는 중간 인증 기관이 서명합니다. 그 결과 루트를 꼭대기로 한 나무 모양이 생깁니다.
flowchart TD
R["루트 인증 기관 · 신뢰 저장소에 들어 있다"]
R -->|자기 서명| R
R -->|서명| I1["중간 인증 기관 A"]
R -->|서명| I2["중간 인증 기관 B"]
I1 -->|서명| E1["서버 인증서"]
I1 -->|서명| E2["서버 인증서"]
I2 -->|서명| E3["클라이언트 인증서"]
I2 -->|서명| E4["코드 서명 인증서"]
그림 꼭대기의 루트만 자기 인증서에 스스로 서명합니다. 그 아래는 전부 윗단이 서명해 줍니다.
중간 단계를 두는 까닭은 루트의 개인키를 되도록 꺼내지 않으려는 것입니다. 루트의 키가 새면 그 아래 나무 전체를 믿을 수 없게 됩니다. 그래서 루트 키는 네트워크에서 떼어 둔 장비에 보관합니다. 날마다 서명하는 일은 중간 인증 기관이 맡습니다.
중간 인증 기관은 용도별로 나눠 두기도 합니다. 그림처럼 한 중간 인증 기관은 서버 인증서만, 다른 하나는 클라이언트 인증서와 코드 서명 인증서를 내주는 식입니다. 코드 서명 인증서는 프로그램에 서명할 때 쓰는 인증서입니다. 이렇게 나누면 한쪽 키가 새도 다른 쪽 인증서는 무사합니다.
경로를 따라 확인하기
신뢰 당사자가 받는 것은 서버 인증서 한 장만이 아닙니다. 서버는 자기 인증서에 중간 인증 기관의 인증서인 중간 인증서를 붙여 보냅니다. 루트 인증서는 신뢰 당사자가 이미 갖고 있으므로 보내지 않아도 됩니다.
flowchart TD
subgraph SENT["서버가 보내는 것"]
S["서버 인증서"]
M["중간 인증서"]
end
subgraph HELD["신뢰 당사자의 신뢰 저장소"]
R["루트 인증서"]
end
S -->|서명한 쪽을 찾는다| M
M -->|서명한 쪽을 찾는다| R
신뢰 당사자는 서버 인증서에서 출발해 그 인증서에 서명한 인증 기관을 따라 한 칸씩 올라갑니다. 칸마다 서명이 맞는지, 기간 안인지, 폐기되지 않았는지를 봅니다. 신뢰 저장소에 든 루트에 닿으면 믿습니다. 중간에 끊기면 거절합니다.
이렇게 이어진 인증서 줄을 인증 경로라고 합니다. 인증서가 고리처럼 이어진다고 해서 인증서 사슬이라고도 부릅니다. 이 줄을 따라 올라가며 확인하는 절차는 경로 검증이라고 부릅니다.
서버가 중간 인증서를 빠뜨리면 그림의 가운데 칸이 빕니다. 신뢰 당사자는 서버 인증서에서 루트로 올라갈 길을 못 찾고 거절합니다. 이 오류를 인증서 사슬 누락이라고 부릅니다.
만료 전에 인증서를 거두기
유효 기간이 지나면 인증서는 저절로 못 씁니다. 문제는 그 전에 주체의 개인키가 새는 때입니다. 키를 훔친 쪽은 기간이 남은 인증서를 들고 주인 행세를 할 수 있습니다.
그래서 인증 기관은 인증서를 기간 전에 무효로 돌리는 인증서 폐기 수단을 둡니다. 신뢰 당사자가 폐기 여부를 알아내는 방법은 크게 둘입니다.
| 방법 | 어떻게 알아내나 | 걸리는 점 |
|---|---|---|
| 인증서 폐기 목록(Certificate Revocation List, CRL) | 인증 기관이 폐기한 인증서 번호를 모아 서명한 목록을 주기적으로 내려받는다 | 목록이 커지고, 다음 목록이 나오기 전의 폐기는 모른다 |
| OCSP(Online Certificate Status Protocol, 온라인 인증서 상태 프로토콜) | 인증서 한 장의 상태를 인증 기관의 응답 서버에 그때그때 묻는다 | 접속마다 조회가 한 번 더 들고, 응답 서버가 누가 어디에 접속하는지 알게 된다 |
두 방법 모두 조회할 곳에 닿지 못하면 곤란해집니다. 조회가 실패했다고 접속을 막으면 서비스가 멈춥니다. 그냥 넘어가면 폐기가 소용없어집니다. 이 곤란을 덜려고 유효 기간을 짧게 잡고 자주 갈아 끼워 폐기에 덜 기대는 방식을 함께 씁니다.
신뢰를 잇는 방식의 갈래
지금까지 본 것은 루트 하나를 꼭대기로 한 계층형입니다. 인증 기관끼리 신뢰를 잇는 방식에 따라 다른 모양도 있습니다.
| 방식 | 신뢰가 이어지는 모양 | 어울리는 곳 |
|---|---|---|
| 계층형 | 루트 하나 아래로 중간 인증 기관이 나무처럼 뻗는다 | 웹처럼 여럿이 같은 신뢰 저장소를 쓰는 곳 |
| 망형 | 대등한 인증 기관들이 서로의 인증서에 서명해 준다 | 따로 운영하던 조직들이 서로를 믿어야 할 때 |
망형에서 인증 기관끼리 서로의 인증서에 서명하는 일을 교차 인증이라고 부릅니다. 아래 그림에서 조직 A 의 신뢰 당사자는 인증 기관 A 만 신뢰 시작점으로 갖고 있습니다.
flowchart TD
subgraph ORGA["조직 A"]
CA["인증 기관 A · A 쪽 신뢰 시작점"]
end
subgraph ORGB["조직 B"]
CB["인증 기관 B · B 쪽 신뢰 시작점"]
EB["B 쪽 서버 인증서"]
end
CA -->|교차 인증 서명| CB
CB -->|교차 인증 서명| CA
CB -->|서명| EB
A 쪽 신뢰 당사자가 B 쪽 서버 인증서를 받았다고 해 봅시다. 서버 인증서에는 인증 기관 B 가 서명했습니다. 인증 기관 B 의 인증서에는 교차 인증으로 인증 기관 A 가 서명해 두었습니다. 그래서 서버 인증서 → 인증 기관 B → 인증 기관 A 로 올라가 자기 쪽 신뢰 시작점에 닿습니다.
신뢰 웹은 이 체계 바깥에서 신뢰를 잇는 방식입니다. 인증 기관 없이 사용자끼리 서로의 공개키에 서명해 줍니다. 중앙의 보증 대신 개인의 판단을 모으므로 아는 사람끼리 키를 주고받는 작은 모임에 어울립니다. 모르는 사람이 많아질수록 누구를 믿을지 정하기가 어려워집니다.
쓰는 곳과 안 쓰는 곳
가장 흔한 쓰임은 웹입니다. 주소가 https:// 로 시작하는 연결은 TLS(Transport Layer
Security, 전송 계층 보안)로 암호화됩니다. 이 과정에서 서버의 인증서를 이 체계로 확인합니다.
웹 말고도 쓰이는 곳이 여럿입니다. 쓰임마다 확인하는 쪽과 믿게 되는 내용이 다릅니다.
| 쓰임 | 확인하는 쪽 | 믿게 되는 내용 |
|---|---|---|
| 웹 접속 | 브라우저 | 접속한 서버가 그 주소의 주인이다 |
| 상호 TLS | 서버와 클라이언트 양쪽 | 서로가 주장하는 서비스가 맞다 |
| 코드 서명 | 프로그램을 설치하는 운영체제 | 누가 만들었고 도중에 바뀌지 않았다 |
| 이메일 서명 | 받는 사람의 메일 프로그램 | 보낸 사람이 맞고 본문이 바뀌지 않았다 |
사내 서비스끼리는 회사가 직접 세운 사설 인증 기관을 쓰기도 합니다. 그 루트 인증서를 사내 장비의 신뢰 저장소에 넣어 두면, 밖의 인증 기관 없이도 같은 방식으로 서로를 확인합니다.
반대로 통신하는 양쪽이 몇 안 되고 미리 만날 수 있으면 이 체계 없이도 됩니다. 두 장비가 설치할 때 공개키를 직접 주고받거나 사전 공유 키를 나눠 두면 상대를 알아볼 수 있습니다. 그런 구성에 공개키 기반구조를 들이면 인증 기관을 세우고 갱신과 폐기를 굴리는 비용만 늘어납니다.
이 체계가 치르는 대가
가장 큰 대가는 인증 기관을 믿어야 한다는 것입니다. 신뢰 저장소에 든 인증 기관은 어느 이름으로든 인증서를 내줄 수 있습니다. 그중 한 곳이 뚫리거나 확인을 소홀히 하면, 남의 이름으로 잘못 나간 인증서도 경로 검증을 통과합니다.
이 약점을 메우려고 나온 것이 인증서 투명성입니다. 인증 기관이 발급한 인증서를 누구나 열람하는 공개 기록에 남기게 합니다. 그러면 자기 이름으로 몰래 나간 인증서를 주인이 찾아낼 수 있습니다.
인증서를 갈아 끼우는 부담도 따라옵니다. 기간이 끝나기 전에 새로 받아 바꿔야 합니다. 이를 놓치면 인증서 만료로 서비스가 멈춥니다. 발급과 갱신을 자동으로 처리하는 ACME(Automatic Certificate Management Environment, 자동 인증서 관리 환경) 같은 프로토콜이 이 부담을 덜어 줍니다.
개인키를 지키는 일도 짐입니다. 인증 기관의 키가 새면 체계 전체가 흔들립니다. 인증 기관이 키를 밖으로 꺼낼 수 없게 만든 전용 장비인 하드웨어 보안 모듈에 키를 넣어 두는 까닭입니다.
관련 항목
공개키 기반구조가 속하는 상위 분류
공개키 기반구조에 참여하는 역할
인증 기관 · 루트 인증 기관 · 중간 인증 기관 · 등록 기관 · 신뢰 당사자 · 사설 인증 기관
공개키 기반구조가 발급하는 인증서의 종류
인증서 · 루트 인증서 · 중간 인증서 · 서버 인증서 · 클라이언트 인증서 · 자기 서명 인증서 · 코드 서명 인증서 · 와일드카드 인증서
신뢰를 세우고 확인하는 절차
신뢰 시작점 · 신뢰 저장소 · 인증 경로 · 경로 검증 · 교차 인증 · 인증서 서명 요청
인증서를 거두고 상태를 알리는 수단
인증서 폐기 · 인증서 폐기 목록 · OCSP · OCSP 스테이플링 · 유효 기간 · 인증서 투명성
공개키 기반구조가 기대는 암호 기술
공개키 암호 · 공개키 · 개인키 · 전자 서명 · 해시 함수 · RSA · 타원 곡선 암호
인증서 형식을 정하는 표준
X.509 · ASN.1 · DER · PEM · PKCS
공개키 기반구조로 상대를 확인하는 용도
TLS · HTTPS · 상호 TLS · 코드 서명 · 이메일 서명
공개키 기반구조를 운영하는 작업
인증서 발급 · 인증서 갱신 · 키 회전 · 하드웨어 보안 모듈 · ACME
공개키 기반구조를 대신하는 신뢰 방식
신뢰 웹 · 사전 공유 키 · 인증서 고정 · 공개키 지문
공개키 기반구조에서 나는 공격과 오류
중간자 공격 · 인증서 만료 · 인증서 사슬 누락 · 인증서 오발급 · 호스트 이름 불일치
다른 이름: PKI · Public Key Infrastructure · 공개 키 기반 구조 · 공개키 기반 구조