HTTPS에 대해 들어보셨을 것이고, 브라우저에 나타나는 초록색 자물쇠 아이콘이 안심을 준다는 것도 알고 계실 겁니다. 하지만 앱 개발 세계에서는 인증서가 유효하다고 맹목적으로 믿는 것만으로는 충분하지 않을 수 있습니다. 암호화된 연결이라 하더라도 누군가가 사용자의 기기와 서버 간에 오가는 통신 내용을 몰래 엿들을 수 있는 잠재적인 위험이 존재하기 때문입니다.
이러한 보안 취약점을 해결하기 위해 '인증서 고정(Certificate Pinning) '이라는 기술이 등장했습니다 . 기본적으로 이 기술은 애플리케이션에 "아무 인증 기관이나 신뢰하지 마세요. 서버가 정확히 이 인증서 또는 공개 키를 제시하는 경우에만 연결을 허용하세요."라고 지시하는 것입니다. 마치 통신 문 앞에 매우 엄격한 문지기를 세워두는 것과 같습니다.
SSL 피닝이란 정확히 무엇이며 왜 필요한가요?
이를 제대로 이해하려면 먼저 표준 HTTPS가 신뢰 체인 에 기반한다는 점을 기억해야 합니다 . 서버에 연결하면 서버는 디지털 인증서를 전송합니다. 모바일 기기는 이 인증서가 운영 체제에서 신뢰하는 인증 기관(CA)에 의해 서명되었는지 확인합니다. 서명이 유효하고 인증서가 만료되지 않은 경우 연결이 설정됩니다.
문제는 공격자가 연결 과정 중간에 침투하는 악명 높은 중간자 공격(MITM) 에서 발생합니다 . 해커가 인증 기관(CA)으로부터 위조된 유효한 인증서를 발급받거나, 피해자의 기기에 악성 루트 인증서를 설치하는 데 성공하면 운영 체제는 연결을 승인합니다. 이 시점에서 공격자는 사용자가 아무런 이상 징후도 눈치채지 못하게 은행 정보나 비밀번호와 같은 중요한 데이터를 가로채거나 수정할 수 있습니다.
바로 이 부분에서 인증서 고정(pinning)이 중요한 역할을 합니다. 앱은 공인된 CA(인증 기관)를 신뢰하는 대신 서버의 인증서 또는 공개 키 해시 값을 복사하여 저장합니다. 핸드셰이크 과정에서 앱은 수신한 인증서를 저장된 인증서와 비교합니다. 두 인증서가 비트 단위로 일치하지 않으면 연결이 즉시 종료되어 서버 스푸핑을 방지합니다.
앵커링 유형: 인증서 방식 vs. 공개 키 방식
모든 인증서 고정 방식이 동일한 것은 아닙니다. 어떤 항목을 "고정"할지에 따라 크게 두 가지 접근 방식이 있습니다. 첫 번째는 인증서 고정으로 , 전체 인증서 파일(.pem 또는 .der)을 저장하는 방식입니다. 구현은 가장 간단하지만 유지 관리가 가장 까다롭습니다. 서버 인증서가 만료되고 갱신될 때마다 저장소에 있는 애플리케이션을 업데이트 해야 하며 , 그렇지 않으면 사용자가 서비스를 이용할 수 없게 됩니다.
두 번째 옵션은 공개 키 고정(Public Key Pinning )입니다 . 이 경우 인증서의 공개 키 해시값(일반적으로 SHA-256)만 저장합니다. 가장 큰 장점은 인증서가 갱신되더라도 공개 키는 그대로 유지될 수 있다는 점입니다. 이를 통해 인증서 유연성이 향상 되고 앱의 강제 업데이트 빈도가 줄어듭니다. 또한 해시값만 저장하므로 코드가 더 깔끔해지고 역공학을 통해 정보를 추출하기가 더 어려워집니다.
다양한 플랫폼에서의 기술 구현
우리가 ~와 함께 일한다면 Android가장 현대적인 방법은 파일을 사용하는 것입니다. network_security_config.xml이 XML 파일에서는 인증하려는 인증서(핀)의 도메인과 해시값을 정의하여 다음과 같은 작업을 수행할 수 있습니다. 안드로이드에서 필수 보안 설정을 활성화하세요 네이티브 방식으로 구현한 다음, 해당 파일을 링크하기만 하면 됩니다. AndroidManifest.xml과거에는 더 복잡한 작업들을 클래스 자체를 덮어쓰는 방식으로 처리했습니다. DefaultHttpClient Java 인증서 저장소 관리는 다음을 통해 이루어집니다. keytool하지만 XML 기반 구성이 훨씬 더 효율적입니다.
생태계에서 iOS상황이 조금 달라집니다. 파일 설정을 통해 앱 전송 보안(ATS)을 활용할 수 있습니다. Info.plist 고정된 도메인을 정의하기 위해서입니다. 하지만 완벽한 제어를 위해서는 런타임 유효성 검사를 구현하는 것이 일반적입니다. URLSessionDelegate인증 챌린지 방식에서는 서버에서 인증서를 추출하여 우리의 인증서와 비교합니다. 로컬에 저장된 인증서 애플리케이션 번들에 포함되어 있습니다.
이용하시는 분들을 위해 커패시터 또는 하이브리드 프레임워크다음과 같은 플러그인이 있습니다. @capgo/capacitor-ssl-pinning 이러한 경우 프로세스를 통합하기 위해 앱의 구성 파일에서 인증서 목록을 지정하고 유효성 검사를 활성화하는 방식으로 구성이 이루어집니다. 이러한 구현은 다음과 같은 도구를 사용하여 테스트하는 것이 매우 중요합니다. Charles 프록시MITM 공격을 시뮬레이션하여 인증서가 예상과 다를 경우 애플리케이션이 연결을 효과적으로 거부하는지 확인합니다.
위험, 제한 사항 및 유지 관리
PIN 설정이 항상 좋은 것만은 아닙니다. 가장 큰 위험은 ' 만료 잠금' 입니다 . 서버 인증서가 만료되었는데 새 PIN으로 앱을 업데이트하지 않으면 모든 사용자가 연결 오류를 보게 됩니다. 이러한 문제를 방지하려면 백업 PIN을 사용하는 것이 가장 좋습니다 . 비상 상황이나 예상치 못한 PIN 변경 시에만 사용할 보조 공개 키의 해시값을 저장하는 것입니다.
반면, 핀 고정은 통신 디버깅이 필요한 개발자에게는 골칫거리가 될 수 있습니다. 모니터링 도구가 제대로 작동하려면 개발 환경에서 핀 고정을 비활성화 하거나 특정 디버그 버전을 만들어야 하는 경우가 있는데, 최종 사용자에게 제공되는 프로덕션 버전에서는 이 기능이 반드시 활성화되어 있어야 합니다.
웹과 관련하여 크롬은 유사한 개념을 구현하는 데 선구적인 역할을 했습니다. 크롬은 HSTS(HTTP Strict Transport Security) 를 사용 하여 HTTPS 사용을 강제하고, 최초 접속 시 취약점을 방지하기 위해 "사전 로드된" 사이트 목록을 유지합니다. 웹용 HPKP 표준도 존재했지만, 구성 오류 발생 시 웹사이트 접속이 불가능해질 수 있는 위험성 때문에 결국 사용되지 않게 되었습니다.
인증서 고정(certificate pinning)을 구현하는 것은 최고의 보안 과 서비스 운영성을 균형 있게 유지하는 전략적 결정입니다 . 특정 기관에 대한 신뢰로 제한함으로써 정교한 공격으로부터 통신을 보호할 수 있습니다. 단, 고객이 서비스에 접근할 수 없는 상황이 발생하지 않도록 키와 인증서의 수명 주기를 엄격하게 관리해야 합니다.
