호다닥 공부해보는 x509와 친구들
Overview
종종 Web App을 개발할때나 Docker혹은 Kubernetes에 접속할 때 다음과 같은 에러를 만날때가 있습니다.
x509 certificate signed by unknown authority
그리고 인터넷 서핑을 하다보면
위 사진과 같이 "Your connection is not Private"라는 문구가 뜨며 하단의 Advanced를 눌러야만 사이트에 들어갈 수 있는 경우를 심심찮게 발견할 수 있습니다.
또 들어가게되더라도 아래 사진과 같이
"Your Connection to this site is not secure"이라는 경고문을 확인할 수 있을겁니다.
사이트는 정상적으로 돌아다닐 수 있겠지만 어딘가 찝찝한 기분과 함께 돌아다니게 되겠죠...
세가지 에러에서 공통적으로 발견할 수 있는 부분은 Certificate가 유효하지 않다는 겁니다.
여기서 말하는 Certificate란 무엇이고, 어떻게해야 이런 에러들을 없앨 수 있을까요?
이번 포스팅에서는 x509란 무엇이며, 관련된 개념들에 대해서 알아보도록 하겠습니다.
x509?
한마디로 x509란 ITU-T가 만든 PKI(Public Key Infrastructure, 공개키기반구조)의 표준입니다.
Background++
ITU-T(국제전기통신연합 전기통신표준화부문, International Telecommunication Union Telecommunication Standardization Sector)는 모든 전기통신 분야에 적용하는 표준을 만들어내는 단체입니다.
설명을 더 이어가기 전에 PKI가 뭔지 간단하게 짚고 넘어가도록 하겠습니다.
PKI란?
PKI-공개키기반구조(Public Key Infrastructure)는 기본적으로 인터넷과 같이 안전이 보장되지 않은 공개된 망 사용자들이 한쌍의 공개키와 개인키를 사용함으로써, 안전하게 데이터를 교환할 수 있게 합니다.
기존의 암호화는 암호화를 하는 키와 복호화를 하는 키가 같은 대칭키 알고리즘을 사용하여 정보를 교환했었습니다.
구현이 쉽고 속도가 빠르다는 장점이 있지만, 키를 sniffing이나 spoofing따위의 해킹으로 빼앗겨버린다면 제 3자에게 정보가 쉽게 노출될 수 있다는 단점이 있습니다.
그래서 암호화를 하는 키와 복호화키를 따로 가져가는 기술이 등장했고, 이런 기반을 마련해둔 것이 PKI(Public Key Infrastructure)입니다.
- Private Key : 누구와도 공유하지 않고 자기 자신만 가지고 있는 키
- Public Key : 공개적으로 공개가 되어 있는 키. 누구나 공개키를 얻을 수 있음
PKI를 사용한 정보교환에서 크게 두가지 상황을 가정할 수 있는데요,
A의 공개키를 사용하여 암호화하고, A에게 보냅니다. 그럼 오직 A만 자신의 개인키를 이용해 암호문을 복호화 시킬 수 있게 됩니다.
두번째는 개인키를 가지고 암호화하는 경우입니다. 공개키는 만인에게 공개되어있으므로 아무나 쉽게 암호문을 복호화할 수 있습니다.
이 경우에는 자신이 보낸 내용을 증명할 때 쓰이게 됩니다.
이 두가지가 공개키 암호화와 전자서명의 원리입니다.
그런데, 앞서 말씀드린대로 공개키는 말그대로 공개되어있기 때문에 전자서명의 경우 해당 공개키가 과연 내가 원하는 공개키가 맞는지 의심할 수가 있습니다.
그래서 신뢰할 수 있는 인증기관(CA:Certificate Authority)가 등장하게 됩니다.
CA(Certificate Authority)
공인 인증 기관은 인증 정책을 수립하고, 인증서발급과 관리역할을 하며 다른 CA와 상호 인증을 제공합니다.
다시 풀어서 설명하면, CA에서는 개인키와 공개키 쌍을 만들고, 개인키를 자신이 만들었다고 인증서를 발행하게 됩니다.
즉, Private key를 보증하기 위해 쌍이되는 Public Key, 그리고 인증기관이 정식으로 발행했다는 것을 알리기 위해 공인 인증 기관의 전자 서명이 인증서에 들어있습니다.
그런데 이 때 인증서를 작성하는 인증기관마다 상이하면 인증서의 내용을 이해하는데 문제가 있을 것입니다.
이러한 인증서들의 표준이 되는 규칙이 있어야 하는데, 현재 가장 널리 사용되고 있는 PKI의 표준은 X509
입니다.
(여기서 이제 위에서 언급했던 X509가 등장!)
X509규칙을 따르는 CA의 항목들
그럼 이제 X509규칙을 따르는 인증서에 무슨 내용이 있는지 살펴보도록 하겠습니다.
더 자세한 설명 : KISA/전자서명 인증서 프로파일 규격
항목명 | 필수/옵션 | 설명 |
---|---|---|
Version | 필수 | 인증서의 버전(현재 X509의 버전은 3이므로 v3) |
SerialNumber | 필수 | 고유 일련번호 |
Signature | 필수 | 발급자의 서명 |
Issuer | 필수 | 발급자의 정보, DN(Distinguished Name)형식 |
Validity | 필수 | 유효기간, 시작~종료날짜가 기재됨 |
Subject | 필수 | 소유자의 정보, DN형식 |
SubjectPublicKeyInfo | 필수 | 소유자의 공개키 |
X509가 버전이 v3가 되면서 이전버전과 달라진 점들은 Extension정보들을 인증서에 추가할 수 있게 된 점입니다.
아래표는 Extension항목의 일부분입니다.
항목명 | 필수/옵션 | 설명 |
---|---|---|
SubjectAltName | 필수/옵션 | 소유자의 다른 이름, DN형식이 아닌 아무 값이라도 들어갈 수 있음. 주로 도메인네임이 들어감 |
PolicyMappings | 옵션 | 정책 정보를 다른 정책과 연결할 수 있는 정보 제공 |
PolicyConstraints | 옵션 | 인증서 경로의 제약사항 |
IssuerAltName | 옵션 | 발급자의 다른 이름, 주로 발급자의 도메인네임이 들어감 |
AuthorityKeyIdentifier | 옵션 | 발급자의 공개키를 식별하기 위함 (총 세가지필드: KeyIdentifier , authorityCertIssuer , authorityCertSerialNumber -> SHA-1해쉬값이 들어감) |
SubjectKeyIdentifier | 옵션 | 소유자의 공개키를 식별하기 위함 (총 한가지필드: KeyIdentifier -> SHA-1해쉬값이 들어감) |
BasicConstraints | 필수/옵션 | 제약사항, 해당 인증서가 다른 인증서를 발급할 권한(CA역할)이 있는지 없는지 나타냄, CA용 인증서에만 포함되며 사용자 인증서에는 포함되지않음 |
CRLDistributionPoints | 옵션 | 해당 인증서의 CRL(Certificate Revocation List:인증서 폐기 목록)을 확인할 수 있는 위치정보 |
KeyUsage | 옵션 | 인증서에 등록된 공개키가 사용되는 보안서비스의 종류를 결정(서명, 부인방지, 전자서명, 키교환 등) |
위의 필수항목에서 언급한 DN형식은 다음 항목들로 구성됩니다.
항목 | 설명 | DN | 예 |
---|---|---|---|
ContryName | 국가코드(2자리) | C | KR |
stateOrProvinceName | 주 이름, 한국은 도 또는 시정보 | ST | <st1:city w:st="on">SEOUL</st1:city> |
localityName | 시 이름 또는 구 이름 | L | SEOGU |
organizationName | 소속 기관 명 | O | IBM |
organizationalUnitName | 소속 부서 명 | OU | Garage |
commonName | 주체를 나타낼 수 있는 이름 | CN | Hololy |
emailAddress | 이메일 | emailAddress | hololy@mail.net |
위 DN표를 바탕으로 X509인증서에 들어가는 subject항목을 구성하면 다음과 같습니다.
Subject: C=KR, ST=<st1:city w:st="on">SEOUL</ct1:city>, L=SEOGU, O=IBM, OU=Garage, CN=Hololy/emailAddress=hololy@mail.net
이렇게 소유자와 발급자에 대한 정보를 인증서안에 표기하게 되어있습니다.
차후 실제로 인증서만들기 실습을 하면서 좀 더 자세히 살펴보겠습니다.
어쨌든 이렇게 정보를 입력하고나서 인증서를 생성하게 되면 크게 두가지 형식으로 인증서가 저장되게 되는데요, base64로 인코딩되어 저장되는 형식을 PEM, 바이너리 형식으로 저장되는 형식을 DER이라고 합니다.
그러면 이제 인증서에 뭐가 들었는지 알았으니 인증서는 어떻게 발급받는지 알아보도록 하겠습니다.
인증서
앞서 말씀드린대로 신뢰할 수 있는 인증서는 공인인증기관이 발급하게 됩니다. 공인인증기관은 철저하게 수직적인 구조를 기반으로 신뢰성이 상속되는 구조입니다.
최상위 루트기관이 서명한 하위 인증서가 있을거고, 이 하위인증서를 사용하는 하위 인증기관이 다시 서명하는 체인형태로 인증서가 발급됩니다.
예를들어 네이버의 주소창 왼쪽의 자물쇠를 눌러보면 이렇게 Connection is secure라고 뜨고 밑의 Certificate는 Valid하다고 확인할 수 있습니다.
Certificate를 눌러서 인증경로탭으로 가보면 아래와 같이 트리구조로 인증서가 발급되어 있는 것을 확인할 수 있습니다.
네이버의 인증서는 최상위 인증기관인 DigiCert로부터 인증받은 하위 인증서인 DigiCert SHA2~CA로부터 인증을 받았네요.
이렇게 수직적인 구조로 인증받게 되는데 어떻게 인증서가 작동되어 인증이 되게 되는지 알아보도록 하겠습니다.
이 세상에는 무조건 신뢰할 수 있는 기관이 몇군데 존재합니다. 최상위 인증기관(RootCA)이라고도 하며 가장 최상위의 인증서를 발급하는 기관입니다.
위 네이버 예시의 DigiCert가 이 상황에서의 RootCA이 되겠네요.
이러한 RootCA의 인증서들은 일반적으로 웹브라우저에 미리 내장되어 있으며, 해당 인증서에 대응하는 공개키또한 인증서 내부에 포함되어 있습니다.
그리고 암묵적으로 이 RootCA들은 신용할 수 있다! 를 서로 약속하고 RootCA들의 공개키로 복호화가 가능한 데이터는 RootCA의 꽁꽁숨겨진 비밀키로 암호화되었기 때문에 신용할 수 있는 데이터라고 간주하는겁니다.
위의 네이버 예시와 같이 인증서는 대부분 계층구조로 되어있습니다.(보통은 3계층)
RootCA가 DigiCert
이고, 중간에 있는 DigiCert SHA2~CA
도 인증기관입니다. RootCA와 구분짓기 위해 ICA(Intermidiate CA):중간인증기관이라고 부릅니다.
하지만 우리는 암묵적으로 RootCA들을 신뢰할 수 있다고 약속했지만 ICA에 대해서는 약속하지 않았습니다. 그런데 어떻게 ICA에서 발급받은 인증서를 신뢰할 수 있다고 할 수 있을까요?
인증서 발급받기
인증서를 발급받는 과정은 다음과 같습니다.
위에서 언급했다싶이, 우리는 이미 RootCA의 공개키로 복호화할 수 있는 데이터는 신뢰하기로 약속했습니다.
B회사가 인증서 발급요청을 하게되면, B회사 인증서해시값을 RootCA의 비밀키로 암호화하게 됩니다.
이렇게 하면 B회사의 인증서해시값은 RootCA의 공개키로 복호화가 가능할것이고, 만약 복호화 시의 해시값과 인증서 내용물의 해시값이 상이하다면 B회사 인증서 내용물은 누군가에 의해 변조되었음을 의미합니다.
즉, 상위기관의 공개키로 하위기관의 인증서 해시값을 복호화함으로써 쉽게 변조 유무를 확인할 수 있게 되니, 하위기관을 신뢰할 수 있다고 간주할 수 있습니다.
이러한 원리를 Chain of Trust라고 부르며 ICA에서 발급받은 인증서도 신뢰할 수 있게되는 근간이 됩니다.
보안연결 과정
신뢰할 수 있는 인증서를 발급받아서 개인 웹서버를 운영한다고 가정해봅시다.
해당 웹서버에 접근해서 데이터를 주고받는다고 할 때, 이 인증서가 보안 연결을 하는데에 어떤 역할을 하는지 알아보도록 하겠습니다.
- 웹서버에 접근 (클라이언트의 난수데이터, 지원하는 암호화 방식, 세션아이디 전송)
- 웹서버에서는 자신의 인증서와 서버의 난수데이터를 클라이언트에게 전송
- 클라이언트는 웹브라우저에 등록된 "신뢰할 수 있는 인증서"목록에 있는 공개키로 인증서 해시값 비교
- 신뢰할 수 있는 사이트임을 확인
Background++
보통 유저가 받는 인증서는 RootCA가아니라 ICA에서 받을 것입니다. 그런데 모든 ICA의 인증서가 브라우저의 신뢰할 수 있는 인증서 목록에 있을까요? 만약 없다면 어떻게 신뢰할 수 있는 인증서라고 판별할 수 있을까요?
ICA가 브라우저의 신뢰할 수 있는 인증서 목록에 없을 경우를 대비하여 보통 ICA에서 인증서를 발급해줄때는 자신의 인증서를 이어붙여서 발급해줍니다.
그러면 ICA의 인증서가 브라우저에 없더라도 같이 제출된 ICA의 인증서를 RootCA의 공개키로 인증할 수 있게되기 때문입니다.
비대칭키로도 암호화 통신을 할 수 있겠지만 비대칭키 방식은 많은 컴퓨터 파워를 소모하기때문에, 실제로 데이터를 주고받을 때에는 대칭키를 사용하여 암호화를 진행합니다.
그러면 대칭키를 서버와 클라이언트 모두 가지고 있어야 할텐데요,
- 클라이언트는 주고받은 랜덤데이터를 조합하여 PMS(Pre Master Secret)이라는 일종의 난수값 생성
- 서버의 인증서 안에 들어있는 서버 공개키로 암호화해서 서버로 전송
- 서버/클라이언트는 PMS, Client 난수, Server 난수 세가지 값을 바탕으로 대칭키 생성
- 이 대칭키를 사용해 암호화 통신 시작
이런 순서로 보안 통신이 시작됩니다!
이러한 기법은 노출되면 위험한 대칭키를 외부망에 노출시키지 않음으로써 안전하게 통신할 수 있다는 장점이 있습니다.
다시 X509 unknown authority...
그런데 이런 Handshake과정에서 서버로부터 받은 인증서가 내가 가지고있는 신뢰할 수 있는 인증서목록으로 검증할 수 없다면?
그러면 브라우저는 신뢰할 수 없는 인증서라는 경고를 출력하거나 접근을 허용하지 않을수도 있습니다.
신뢰할 수 없는 기관의 인증서를 사용하는 웹페이지에 접속할 경우, 암호화된 패킷이 제 3자에 의해 복호화되어 변조될 수 있기때문에 주의하여야 합니다.
따라서 안전한 보안 연결을 위해서는 신뢰할 수 있는 기관에서 인증서를 발급받아 구성하는게 좋습니다.
다음 포스트에서는 무료로 인증서를 발급받아 사용할 수 있는 Let's Encrypt 사용법에 대해서 알아보고 인증서가 어떻게 생겼는지 실습해보도록 하겠습니다.