HSTS
(HTTP Strict-Transport Security, RFC 6797)란, 웹 사이트가 오직 HTTPS
를 통해서만 접근이 가능하다고 선언하여, 보안 연결을 전제로 하는 상호작용을 지시하고 강제하는 보안 정책 메커니즘입니다.
웹 서버가 모든 클라이언트에 대해 안전하지 않은 HTTP
연결은 거부하고 HTTPS
만을 허용한다고 명시하면, 브라우저는 이를 해석하고 적용함으로써 구현됩니다.
HSTS
를 선언하는 방법은 간단합니다. 웹 서버에서 응답 헤더로 Strict-Transport-Security
헤더를 설정하면 되는데, 예제는 아래와 같습니다.
Strict-Transport-Security: max-age=31536000
이는 HSTS
정책을 31,536,000초(1년) 동안 적용한다는 것을 의미합니다. 브라우저가 HTTPS
응답에서 헤더를 확인하면, max-age
에 명시된 시간만큼 '해당 도메인은 HTTPS
로만 연결해야 한다'고 기억하게 됩니다.
그리고 이후 HTTP
연결이 시도된 경우에는 307 Internal Redirect
라는 특수 리디렉션을 트리거하여, 별도의 DNS 조회나 외부 연결 없이 내부적으로 HTTPS
연결을 재설정합니다.
( 이미지 출처 : web.dev )
이러한 리디렉션은 매우 빠르고, HTTP->HTTPS 연결 전환 간에 소요되는 지연 시간(hop)도 없습니다. 요청이 브라우저 내부를 벗어나지 않으므로 가로채기도 방지할 수 있습니다.
원리는 사용자가 HTTP
로 연결을 시도했을 때, 서버가 아닌 브라우저가 HTTP
요청을 건너뛰고 HTTPS
로 자동 업그레이드하여 요청을 조작/변환하는 것으로, RFC 6797 명세에 따르면 아래와 같이 정의되고 있습니다.
- 웹 애플리케이션을 참조하는 안전하지 않은 링크를 자동으로 보안 링크로 전환합니다. (서버에 액세스하기 전에 수정됩니다)
- 연결 보안을 보장할 수 없는 경우(예: 서버의 TLS 인증서를 신뢰할 수 없는 경우), 사용자 에이전트는 연결을 종료해야 하며(RFC 6797 section 8.4, Errors in Secure Transport Establishment) 사용자가 웹 애플리케이션에 액세스하는 것을 허용해서는 안 됩니다. (section 12.1, No User Recourse)
이를 통해 얻을 수 있는 장점은 당장 크게 두 가지가 있는데, 먼저 첫 번째는 네트워크 비용의 절감입니다.
일반적으로 HTTP
접근을 차단하고 HTTPS
연결을 강제하려고 한다면, 웹 서버에서 301
또는 302
리디렉션을 통해 구현하기 마련인데, 이러한 리디렉션 자체도 엄연히 지연 시간 등 왕복(Round-Trip) 비용이 발생하는 행위입니다.
구체적으로는 아래와 같이 동작하는데, 이러한 과정이 일련의 부담으로 작용할 여지가 있는 것입니다.
- 서버가
HTTP
를 통해 요청을 수신합니다.- 요청된 리소스에 해당하는
HTTPS
로 이동하기 위해 리디렉션을 트리거합니다.- 서버는 브라우저와의 보안 연결을 위해
HTTPS
를 통해 협상합니다.- 콘텐츠가 로드됩니다.
HSTS
는 HTTP
연결 자체를 배제하므로, 301
/ 302
리디렉션이 필요하지 않아 지연 시간 및 비용 문제가 발생하지 않습니다.
두 번째로는 중간자 공격(Man in the middle attack, MITM) / SSL Stripping과 같은 보안 공격을 방지할 수 있다는 것입니다. 이는 HSTS
정책을 통해 해결할 수 있는 대표적이고도 중요한 보안 취약점 중 하나입니다.
301
/ 302
리디렉션은 어쨌든 이미 먼저 HTTP
연결 요청이 발생한 것이지만, HSTS
는 그렇지 않으므로 취약한 요청을 가로채는 방식의 공격을 시도할 만한 여지가 제한되는 것입니다.
HSTS가 해결할 수 있는 가장 중요한 보안 취약점은 SSL-stripping 중간자 공격입니다. 이 공격은 Moxie Marlinspike가 2009년 BlackHat Federal 강연인 "실제 SSL을 무력화하기 위한 새로운 트릭"에서 처음 공개적으로 소개한 것입니다. SSL (및 TLS) Stripping 공격은 안전한 HTTPS 연결을 평문 HTTP 연결로 변환하는 방식으로 동작합니다. 사용자는 이러한 연결이 안전하지 않다는 것을 인지할 수는 있어도, 결정적으로 연결이 안전해야만 하는지 여부를 알 수 있는 방법이 없습니다. Marlinspike의 강연 당시에는 많은 웹 사이트들이 TLS/SSL을 사용하지 않았으므로 (사전 지식 없이는), 평문 HTTP가 공격에 의한 것인지, 아니면 단순히 그냥 웹 사이트가 TLS/SSL을 구현하지 않았기 때문인지를 알 수 없었습니다. 또한 이러한 다운그레이드 과정 중에는 사용자에게 경고가 표시되지 않기 때문에, 경계심이 높은 사용자를 제외한 대부분의 일반 사용자들은 이러한 공격을 감지하기가 상당히 어렵습니다. Marlinspike의 sslstrip 도구는 이러한 공격을 완전히 자동화합니다.
HSTS는 사이트에 대한 연결에서 항상 TLS/SSL을 사용해야 한다고 브라우저에게 알려줌으로써 이 문제를 해결합니다. 하지만 HSTS 헤더는 사용자가 처음으로 방문하는 경우 공격자에 의해 제거될 수 있습니다. Google Chrome, Mozilla Firefox, Internet Explorer 및 Microsoft Edge는 HSTS 사이트의 "사전 로드된" HSTS 사이트 목록을 포함하는 것으로 이러한 문제를 해결하려고 시도합니다. 하지만 유감스럽게도 이러한 해결책은 인터넷의 모든 웹 사이트들을 포괄하여 적용할 수는 없습니다. (...)
-Wikipedia, HTTP Strict Transport Security - Applicability
위의 인용에서도 설명하고 있듯, 헤더를 통해 명시하는 HSTS 정책은 Trust on first use, TOFU 원칙에 따라 사용자가 사이트를 한 번 이상 방문한 다음부터 적용되기 때문에, 사용자가 사이트에 처음으로 방문한 때에는 공격자에 의해 헤더가 제거당할 수 있다는 취약점이 존재합니다.
이를 해결할 수 있는 방법은 HSTS Preload
를 사용하는 것인데, 이에 대해서는 아래에서 이어서 설명하겠습니다.
HSTS Preload
는 단어 그대로 HSTS 정책을 사전에 미리 로드하여 적용하는 것입니다.
HSTS Preload List
라는 데이터베이스에 웹 사이트의 도메인을 등록하는 방법으로, Strict-Transport-Security
응답 헤더를 확인한 적이 없더라도(즉, 방문한 적이 없는 사이트라도) 처음부터 HSTS 정책이 적용되도록 할 수 있습니다.
위와 같이 Google에서 운영, 관리하는 https://hstspreload.org/ 사이트에서 도메인을 직접 제출하거나, 아래와 같이 Strict-Transport-Security
헤더에서 preload
지시자를 명시하면 HSTS Preload List
에 도메인 추가를 요청할 수 있습니다.
리스트에 추가되기까지는 몇 달까지도 소요될 수 있으나, 추가된 이후부터는 브라우저가 해당 도메인에 대해 무조건 HTTPS로만 연결을 시도하게 됩니다.
Strict-Transport-Security: max-age=31536000; preload; includeSubDomains
참고로,
includeSubDomains
지시자를 명시하는 경우 모든 서브 도메인들까지 포함하여 요청할 수 있습니다.
이것이 가능한 원리는, HSTS Preload List
가 브라우저 벤더에 의해 직접적으로 관리된다는 점에 있습니다.
Chromium의 경우, Preload List 자체를 아예 브라우저 엔진 소스 코드에 하드코딩하고 있으며, 다른 주요 브라우저 벤더들 또한 이러한 데이터베이스를 공유하거나, 이를 기반으로 하는 자체적인 Preload List를 운영, 관리하고 있습니다.
Chromium 소스 코드에 하드코딩된 전체
HSTS Preload List
는 해당 링크를 통해 확인해볼 수 있습니다.
그러나 이러한 특성으로 인해 주의할 점이 있는데, Preload List에 한 번 등록된 도메인은 다시 제거하기가 어렵거나 제거되기까지 많은 시간이 소요될 수 있다는 것입니다.
즉, 사이트의 모든 페이지(공개적으로 접근할 수 없는 내부 도메인까지 포함한 사이트의 모든 서브 도메인들까지)가 완벽하게 HTTPS
연결을 허용할 수 있고, 그렇게 하더라도 추후 문제가 없을 상황에서만 리스트에 등록하는 것이 안전합니다.
예를 들어 인증서와 관련한 문제로 HTTPS
연결이 불가하게 된 상황에서, 도메인이 Preload List에 등록되어 있을 경우에는 아예 사이트에 접근할 방법이 없게 될 수 있을 것입니다.
Chromium 계열 브라우저에서는, chrome://net-internals/#hsts 에서 HSTS
도메인을 관리할 수 있습니다.
응답 헤더에 의해 설정되었든(동적), Preload List에 등록된 것이든(정적), 현재 시점에서의 HSTS
정책을 조회해볼 수 있고 추가 요청도 할 수 있습니다만, 이미 Preload List에 등록된 도메인을 삭제할 수는 없습니다.
그래서 HSTS Preload List
에는 등록하지 않고, 점진적으로 max-age
를 조금씩 늘려가면서 이슈가 없는지 체크하는 식으로 안전하게 접근하는 방법도 있습니다. 가령 네이버 같은 경우가 그러한데, Preload List에는 naver.com
도메인이 등록되어 있지 않지만, HSTS 응답 헤더는 설정하고 있습니다.
HTTP Archive의 Web Almanac에 따르면, 이미 2021년 기준으로도 데스크톱과 모바일을 포함해 전 세계 모든 요청 트래픽의 91%가 HTTPS로 처리되고 있는 상황입니다.
일반적인 사용자들을 대상으로 서비스하는 통상적인 사이트라면 애초에 너무나 당연하게 HTTPS
를 사용하고 있는 현재 시점에서, HTTP
보안 이슈를 다룬다는 것이 시의적절하지 않아 보일 수 있습니다.
사실 이번 글에서 HSTS
를 설명하게 된 이유는, 최근 Chrome 브라우저에서 http://
가 명시된 링크를 클릭해 연결을 시도하는 경우라도 강제로 HTTPS
연결로 자동 업그레이드하는 정책을 적용하기 시작했기 때문입니다.
다만 인증서 문제나 404 등의 이유로 업그레이드에 실패한 경우에는 아직 HTTP
연결을 허용, 전환한다는 점에서 HSTS
정책과는 약간 차이가 있습니다(즉, 상대적으로 조금 더 느슨합니다).
정확하게는 지난 7월 12일에 릴리즈된 Chrome 115 (stable) 버전부터, 일부 사용자들을 대상으로 점진적인 HTTPS Upgrades
정책이 시행되고 있습니다.
아직도 약 5% ~ 10%의 HTTP
트래픽이 잔존하고 있는 상황에 대해, 이제는 더욱 공격적인 스탠스를 취하여 완전한 HTTPS
로의 전환을 꾀하려고 한다는 것을 알 수 있습니다.
( Chrome Platform Status, HTTPS Upgrades )
어떠한 배경에서 이러한 정책이 시행되었는지는, 아래 Chromium 블로그에 포스팅된 아티클을 번역, 인용한 내용을 통해 살펴보겠습니다.
HTTPS의 기본화를 향해
지난 몇 년 동안, Chrome 사용자들의 탐색(내비게이션) 중 90% 이상이 모든 주요 플랫폼 전반에 걸쳐 HTTPS 사이트를 방문했습니다. 다행히도 이는 대부분의 트래픽이 암호화 및 인증되어 있으므로 네트워크 공격자로부터 안전하다는 것을 의미합니다. 그러나 여전히 고집스러운 5-10%의 HTTP 트래픽이 잔존하고 있어, 공격자가 해당 데이터를 도청하거나 변경할 수 있는 상황입니다. Chrome은 사이트와의 연결이 안전하지 않을 때 주소 표시줄에 경고를 표시하고는 있지만, 이것만으로는 충분하지 않다고 생각합니다. 많은 이들이 이러한 경고에 주의하지 않을 뿐만 아니라, 경고를 인지한 시점에는 이미 피해가 발생했을 수 있기 때문입니다.
저희는 웹이 기본적으로 안전해야 한다고 믿습니다. HTTPS 우선 모드는 Chrome이 사이트와 안전하지 않은 연결을 설정하기 전에 명시적으로 사용자의 승인을 얻음으로써 그러한 믿음에 정확히 부응할 수 있습니다. 저희의 목표는 결국 모든 사용자들을 대상으로 이 모드를 기본적으로 활성화하는 것입니다. 현재의 웹은 HTTPS 우선 모드를 보편적으로 활성화할 준비가 되어 있지는 않지만, 이러한 목표를 향한 여러 중요한 디딤돌들을 발표하고자 합니다.
자동 업그레이드
Chrome은 모든 http:// 탐색을 자동으로 https:// 로 업그레이드합니다. 명시적으로 http:// 를 선언한 링크를 클릭할 때에도 그러합니다. 이는 HSTS 업그레이드와 상당히 유사하게 동작하지만, Chrome에서는 이러한 업그레이드가 실패할 때(예: 사이트가 잘못된 인증서를 제공하거나 HTTP 404를 반환하는 경우)를 감지하고 자동으로 http:// 로 대체합니다(fallback). 이러한 변경을 통해 HTTPS를 사용할 수 없는 경우에만 보안되지 않은 HTTP를 사용하게 되며, 이는 사용자가 오래되고 안전하지 않은 링크를 클릭했기 때문은 아닙니다. 현재 이러한 변경을 Chrome 버전 115에서 실험하고 있으며, 웹 전반에서 이러한 동작이 표준화될 수 있도록 작업하여 곧 모든 사용자들을 대상으로 적용할 계획입니다. 비록 이러한 변경은 능동적인 네트워크 공격자들로부터 보호할 수는 없지만, 모든 사용자들을 위한 HTTPS 우선 모드로 나아갈 수 있는 발판이며 수동적인 네트워크 공격자들로부터 더 많은 트래픽을 보호할 수 있을 것입니다.
(...)
더 많은 사용자들을 위한 HTTPS 우선 모드 보호 확장
궁극적인 목표는 모든 사용자들이 HTTP 우선 모드를 활성화하는 것입니다. 저희는 이를 위해 HTTPS 우선 모드 보호를 몇 가지 새로운 영역으로 확장해 나가고 있습니다.
- Google의 고급 보호 프로그램에 등록되어 있고, Chrome에도 로그인되어 있는 사용자에 대해 HTTPS 우선 모드를 활성화했습니다. 이러한 사용자는 가장 강력한 보호를 Google에 요청한 것이며, HTTPS 우선 모드는 이러한 사용자가 직면할 수 있는 안전하지 않은 연결의 실질적인 위협을 방지하는 데에 도움이 될 것입니다.
- 보다 안전한 브라우징 경험을 위해서, 시크릿 모드에서 기본적으로 HTTPS 우선 보호 모드를 곧 활성화할 예정입니다.
- 현재 저희는 Chrome을 통해 사용자가 일반적으로 HTTPS를 통해 접근하는 것으로 알려진 사이트에서 HTTPS 우선 보호 모드를 자동으로 활성화하는 실험을 진행하고 있습니다.
- 마지막으로, HTTP를 거의 사용하지 않는 사용자들을 위해 자동으로 HTTPS 우선 모드를 활성화하는 방법을 모색하고 있습니다.
(...)
-Chomium Blog, Towards HTTPS by default
만약 어떤 특수한 상황에 처해 있어 HTTPS
마이그레이션 이슈를 다루어야 하는 엔지니어의 입장이라면, 이러한 HTTPS Upgrades
동작을 변경하고 디버깅해야 할 필요가 있을 수 있습니다.
이때는 아래와 같이 브라우저의 플래그 설정(chrome://flags)을 통해 동작을 변경할 수 있습니다.
지금까지 다룬 내용을 정리하면 아래와 같습니다.
HSTS
란 HTTPS
를 강제하는 보안 정책 매커니즘으로, 브라우저로 하여금 오직 HTTPS
연결만 시도하도록 합니다.Strict-Transport-Security
응답 헤더를 설정하여, 브라우저에 대해 HSTS
정책을 적용하도록 선언할 수 있습니다.HSTS Preload List
에 웹 사이트의 도메인을 등록하여, 첫 방문부터 HSTS 정책이 적용되도록 할 수 있습니다.HTTPS
가 강제되어도 문제가 없을지 신중히 파악해야 합니다.그동안 Chromium 진영에서는 HTTPS
를 통한 안전한 웹 생태계 조성을 위해 적극적인 지원과 다각적인 행동을 오랜 기간 지속적으로 시도하고 있었습니다.
소수 불가피한 경우를 제외하고는, 웹 생태계에서 HTTPS
가 완전히 디폴트가 될 수 있도록 다방면의 정책을 확대 적용해 나가고 있는 것을 알 수 있습니다.
이번에 HTTPS Upgrade
정책을 강제로 적용하기 시작한 것뿐만 아니라, 이후로는 HTTP
로 접근하는 쿠키의 수명을 강제로 축소하는 패널티 정책까지 고려하고 있다고 하니, Chromium 진영에서 말하는 것처럼 '결승선에 매우 가까워진' 상황이라고 볼 수 있겠습니다.