관리 메뉴


Kinesis´s Open Document

SSL Configure : HTTP Public Key Pinning (HPKP) 설정하기 본문

MEMO/기술 자료/Security

SSL Configure : HTTP Public Key Pinning (HPKP) 설정하기

Kinesis 2016. 12. 28. 17:36

OWASP - Pinning Cheat Sheet 중 발췌

https://www.owasp.org/index.php/Pinning_Cheat_Sheet


# 무엇이 문제인가?

사용자, 개발자 그리고 응용 프로그램은 보안 채널에서 종단 간 보안 (E2E, End-to-End) 보안을 원하지만 일부 채널은 기대에 미치지 못한다. 특히 VPN, SSL 및 TLS와 같이 잘 알려진 프로토콜을 사용하여 구축 된 채널은 여러 가지 공격에 취약할 수 있다.


# Pinning 이란 무엇인가?

Pinning(고정)은 X509인증서 또는 공개 키와 호스트를 결합(또는 연결, associating)시키는 프로세스다. 호스트에 대한 인증서 혹은 고정키가 확인되면 호스트는 인증서 또는 공개키와 결합(또는 연결, associating)되어 '고정(Pinning)'된다. 만약 둘 이상의 인증서 또는 공개 키가 수용가능하다면 프로그램은 핀셋을 고정(Jon Larimer 와 Kenny Root GoogleIO의 말에 의하면)한다. 이 경우 공시된(advertised) 식별자는(identity) 핀셋에 정의된 요소들 중 하나와 일치해야 한다.


호스트 또는 서비스의 인증서 및 공개 키는 응용프로그램 개발과정 또는 최초 실행시 추가할 수 있으나, 일반적으로는 개발과정에서 추가하는 것이 공격자가 핀을 오염시킬 수 없어 선호하는 편이다.


# 언제 핀(Pin)을 사용하나

원격 호스트의 신원을 비교적 확실하게 알고 싶거나 또는 공격이 발생될 것으로 예상되는 환경에서 작업할 때 Pin을 사용해야 한다. 그러나 전자든 양자든 대부분 해당사항이 있기 때문에 가급적이면 항상 핀(Pin)을 사용해야 한다.


# 어떻게 Pin이 사용되나

아이디어는 기존에 사용한 프로토콜 및 인프라를 다시 사용하지만 강화된 방식으로 사용하는 것이다. 재사용을 위해 프로그램은 기존에 수립했던 보안 연결을 유지한다.


채널 강화를 위해 프로그램은 라이브러리, 프레임워크 및 플랫폼에서 제공하는 OnConnect 콜백을 활용하며, 이 콜백에서 프로그램은 원격 호스트의 식별자와 인증서 및 공개키를 검증한다.




요지는 종단간(E2E, End-to-End) 보안연결을 위한 방법 중 하나로 인증서, 공개키, 해싱을 이용해 중간자공격(MITM, Man In The Middle attack)을 막는 방법 중 하나.


SSL 인증서의 검증 및 검사는 별도의 툴이 없더라도 내부망 안에서의 구축이 아닌이상 다음의 웹사이트(URL)을 통해서 쉽게 확인이 가능하다.


- https://www.htbridge.com/ssl/

- https://www.ssllabs.com/ssltest/


정상적으로 설정이 된 경우 다음과 같이 확인이 가능하다.




위의 2개의 사이트 중 하나에 접속하여 SSL 검증을 하면, 처음에 설정이 되지 않았을 때는 녹색으로 색칠되어 있지 않더라도 PIN영역에 SHA256으로 값이 나타난다. 이를 복사해서 Apache 또는 Nginx 에 맞춰 설정을 해주면 된다.


나의 경우 Nginx로 구성된 Reverse Proxy를 거쳐 외부와 통신하도록 되어 있는 만큼 Nginx 에서만 설정해줘도 외부 통신은 적용이 되는 만큼 Nginx 방법으로만 먼저 서술하도록 한다.

server {
    listen 443 http2;
    server_name kinesis.kr;
    { 생략 }

    add_header Public-Key-Pins 'max-age=31536000; pin-sha256="Zpj3FAj8kVaCsollRCQ5QzYcNPQUBJtkKjwSG6zN7T4=";pin-sha256="klO23nT2ehFDXCfx3eHTDRESMz3asj1muO+4aIdjiuY=";pin-sha256="grX4Ta9HpZx6tSHkmCrvpApTQGo67CYDnvprLg5yRME=";pin-sha256="lCppFqbkrlJ3EcVFAkeip0+44VaoJUymbnOaEUk7tEU=";pin-sha256="ugtFx+0HGXAFUfvn3PNwtGc2SsAQ8ip33GSMOPEH9Uo="';
    { 생략 }
}

pin-sha256 안의 값은 인증서의 순서대로 작성해야 하는 것이 문제가 발생할 여지가 적다. 자신의 인증서가 사용하는 Path를 잘 확인해서 맞춰서 작성하고, Backup-pin을 위해 별도의 pin을 하나 생성하여 맨 마지막에 넣어주는 것이 좋은데, 나열된 PIN번호만 입력해서는 검사를 Pass하지 못하는 경우 다음의 과정을 통해 Backup-pin 하나를 생성하여 마지막에 추가해주면 된다.


Backup-Pin 생성 명령어 요약

openssl genrsa -out your_domain.backup.key 4096
openssl req -new -key your_domain.backup.key -sha256 -out your_domain.backup.csr
openssl req -pubkey < your_domain.backup.key | openssl pkey -pubin -outform der | openssl dgst -sha256 -binary | base64

Backup-Pin 생성 과정 예제

root@host:/your_ssl_path# openssl genrsa -out your_domain.backup.key 4096
Generating RSA private key, 4096 bit long modulus
.............................................................................................
.............
e is 65537 (0x10001)
root@host:/your_ssl_path# openssl req -new -key your_domain.backup.key -sha256 -out your_domain.backup.csr
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [AU]:KO
State or Province Name (full name) [Some-State]:
Locality Name (eg, city) []:Seoul
Organization Name (eg, company) [Internet Widgits Pty Ltd]:Kinesis
Organizational Unit Name (eg, section) []:Kinesis
Common Name (e.g. server FQDN or YOUR name) []:*.kinesis.kr
Email Address []:support@kinesis.kr

Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:
root@host:/your_ssl_path# openssl req -pubkey < your_domain.backup.key | openssl pkey -pubin -outform der | openssl dgst -sha256 -binary | base64
ugtFx+0HGXAFUfvn3PNwtGc2SsAQ8ip33GSMOPEH9Uo=
root@host:/your_ssl_path#

이렇게 하여 마지막에 나온 "ugtFx+0HGXAFUfvn3PNwtGc2SsAQ8ip33GSMOPEH9Uo=" 와 같은 값을 마지막에 backup-pin 으로 추가해주면 된다.


# 기타 주의사항

※ 인증 순서대로 (자신의 도매인부터 상위 도메인까지) Pin 값을 입력하지 않는 경우 검증 실패가 뜰 수 있다.

※ 모든 서브 도메인에도 SSL의 HPKP가 적용되길 바랄 경우 includeSubDomains 를 추가하고, http와 https를 혼용하여 사용해야하는 도메인일 경우 includeSubDomains 옵션을 제거하여 사용한다.

※ Fullchain(여러개의 인증서를 하나로 합친)이 아닌경우 각각의 Pin만 입력해도 될 수 있으나 Fullchain의 경우 또는 순서대로 PIN을 입력하였음에도 불구하고 검증 통과에 실패할 경우 마지막의 Backup Pin 값을 생성하여 추가하면 해결될 수 있다.



Comments