본 강연은 Rails 애플리케이션의 HTML Sanitization에 대한 심층적인 분석을 제공하며, 특히 HTML4 기반의 기존 Sanitizer가 HTML5를 지원하는 최신 웹 브라우저 환경에서 발생시키는 보안 취약점과 이에 대한 Rails의 대응 전략을 다룹니다. 발표자인 Shopify의 엔지니어링 디렉터이자 Rails 보안 팀원인 본인은, HTML4 Sanitizer와 HTML5 브라우저 간의 파싱 방식 차이로 인해 발생하는 'Mutation XSS'라는 심각한 보안 문제를 제기하고, 이를 해결하기 위한 Rails Sanitizer 스택의 전반적인 진화 과정을 상세히 설명합니다.
HTML Sanitizer는 사용자로부터 입력받은 HTML 문서에서 안전하지 않다고 판단되는 태그나 속성을 제거하여, 잠재적인 크로스 사이트 스크립팅(XSS) 공격을 방지하는 역할을 합니다. 전통적으로 Rails는 HTML4 사양에 기반한 Sanitizer 스택을 사용해왔습니다. 그러나 HTML4는 오류 수정에 대한 명확한 지침이 없어 파서마다 동작이 달라 예측 불가능한 결과를 초래할 수 있습니다. 반면, HTML5(또는 Living Standard)는 상세한 상태 머신 정의와 오류 수정 지침을 제공하여 모든 HTML5 파서가 일관되고 견고하게 동작하도록 설계되었습니다.
이러한 HTML4 Sanitizer와 HTML5 브라우저 간의 파싱 방식 차이는 ‘Mutation XSS’라는 새로운 유형의 취약점을 야기합니다. 예를 들어, <select><style><script>alert(1)</script></style></select>
와 같은 페이로드는 HTML4 Sanitizer에서는 <style>
태그 내의 <script>
를 단순한 문자열 데이터로 인식하여 안전하다고 판단하고 통과시킵니다. 하지만 HTML5 브라우저에서는 <select>
태그 내에 <style>
태그가 올 수 없다는 규칙에 따라 <style>
태그를 제거하고, 그 안에 있던 <script>
를 독립적인 실행 가능한 스크립트 태그로 재해석하여 XSS 공격이 발생하게 됩니다. SVG 및 MathML과 같은 ‘외래 컨텍스트(foreign contexts)’ 태그들도 유사한 방식으로 파서의 동작을 변경시켜 취약점을 유발할 수 있습니다.
Rails는 이 문제를 해결하기 위해 전체 Sanitizer 스택을 HTML5 기반으로 전환하는 대규모 작업을 수행했습니다. 이 과정은 ‘M-메서드’라는 하향식 탐색(목표에서 전제 조건으로) 및 상향식 실행(하위 모듈부터 구현) 방식을 따랐습니다. 핵심적인 진화 단계는 다음과 같습니다:
- Nokogiri의 HTML5 지원: 기존
libxml2
가 HTML5를 지원하지 않으므로,nokogumbo
라이브러리(Google의libgumbo
기반)를nokogiri
에 통합하여 HTML5 파싱 기능을 추가했습니다. 이 과정에서nokogumbo
개발자들과의 협업 및 Git 기록 보존 등 ‘인간적 요소’에 대한 고려가 중요하게 다루어졌습니다. 또한, SVG/MathML과 같은 네임스페이스를 가진 요소에 대한 CSS/XPath 쿼리 성능 문제를 해결하기 위해libxml2
에 와일드카드 네임스페이스 검색 패치를 적용하여 성능을 최적화했습니다. - Loofah 업데이트:
nokogiri
의 HTML5 지원을 기반으로,loofah
는 HTML4 및 HTML5 문서 및 프래그먼트 클래스를 분리하고, 헬퍼 메서드를 노출하여 Rails HTML Sanitizer가 적절한 파서를 선택할 수 있도록 했습니다. 이 단계에서는 기존의 HTML4 파싱 특성에 의존하는 방대한 테스트 코드를 HTML5 파싱 동작에 맞춰 수동으로 업데이트하는 데 상당한 시간이 소요되었습니다. - Rails HTML Sanitizer 업데이트:
loofah
의 변경 사항을 통합하고, 코드 정리 및 리팩토링을 통해 HTML5 Sanitizer 지원을 도입했습니다. 이는 기존 코드를 ‘쉬운 변경’으로 만들기 위한 사전 작업이었습니다. - Rails 프레임워크 통합:
ActionView
,ActionText
및 테스트 관련 젬(rails-dom-testing
,action-dispatch-assertions
)에 HTML5 Sanitizer를 통합했습니다. 새로운 Rails 애플리케이션은 기본적으로 HTML5 Sanitizer를 사용하도록 설정되며, 기존 애플리케이션은 호환성을 위해 설정을 통해 점진적으로 전환할 수 있도록 옵션을 제공했습니다.
이러한 노력의 결과, Rails 7.1은 강력한 HTML5 Sanitization 지원을 제공하게 되었습니다. 앞으로는 파싱 컨텍스트(즉, HTML 문자열이 문서 내에서 어떤 부모 요소에 포함되는지에 따라 해석 방식이 달라지는 것)를 고려하는 표준화된 Sanitizer API 도입을 통해 보안을 더욱 강화할 계획입니다.
결론적으로, Rails는 HTML4 Sanitizer와 HTML5 브라우저 간의 불일치로 인한 Mutation XSS 취약점이라는 중대한 보안 과제를 성공적으로 해결했습니다. `nokogiri`의 HTML5 파싱 기능 강화부터 `loofah`, `rails-html-sanitizer`를 거쳐 Rails 프레임워크 전반에 걸친 체계적인 업데이트를 통해, Rails 7.1은 이제 HTML5 Sanitization을 기본으로 지원하며 사용자 데이터를 더욱 안전하게 보호합니다. 이는 Rails 커뮤니티의 지속적인 노력과 오픈소스 협업의 중요성을 보여주는 사례이며, 향후 파싱 컨텍스트를 고려하는 표준화된 Sanitizer API 도입을 통해 웹 보안의 미래를 선도할 것입니다.