3P by GN⁺ 21시간전 | ★ favorite | 댓글 2개
  • 웹의 주요 취약점인 XSS 공격을 방지하기 위해 Firefox가 표준화된 Sanitizer API를 최초로 지원
  • 기존의 innerHTML 대신 setHTML() 메서드를 사용하면, 신뢰할 수 없는 HTML을 DOM 삽입 전 자동 정화(sanitize) 하여 악성 스크립트를 제거
  • 개발자는 기본 설정이 과하거나 부족할 경우 맞춤형 설정을 통해 허용할 요소와 속성을 제어할 수 있음
  • Firefox의 이 기능은 Trusted Types와 결합해 웹 전반의 보안 수준을 높이고, 개발자가 별도 보안팀 없이도 XSS를 예방할 수 있게 함

XSS 취약점과 Firefox의 대응

  • 교차 사이트 스크립팅(XSS) 은 사용자가 입력한 콘텐츠를 통해 공격자가 임의의 HTML이나 JavaScript를 삽입할 때 발생
    • 공격자는 이를 이용해 사용자 상호작용을 감시하거나 데이터를 탈취할 수 있음
    • XSS는 거의 10년간 상위 3대 웹 취약점(CWE-79) 으로 분류되어 왔음
  • Firefox는 2009년부터 Content-Security-Policy(CSP) 표준을 주도하며 XSS 방어를 강화해 왔음
    • CSP는 웹사이트가 로드 및 실행할 수 있는 리소스를 제한함
    • 그러나 기존 사이트 구조 변경과 지속적인 보안 검토가 필요해 광범위한 채택에는 한계가 있었음

Sanitizer API와 setHTML()의 역할

  • Sanitizer API는 악성 HTML을 무해한 형태로 변환하는 표준화된 방법을 제공
    • 예시 코드에서 <img src="x" onclick="alert('XSS')"> 요소는 제거되고 <h1>Hello my name is</h1> 만 남음
  • setHTML() 메서드는 HTML 삽입 시 자동으로 정화 과정을 수행해 기본적으로 안전한 동작을 보장
    • 기존의 innerHTML 대입을 setHTML()로 교체하는 것만으로 강력한 XSS 방어 가능
  • 개발자는 기본 설정이 너무 엄격하거나 느슨할 경우, 커스텀 설정을 통해 허용할 HTML 요소와 속성을 정의할 수 있음
    • 실험을 위해 Sanitizer API playground 도구를 활용할 수 있음

Trusted Types과의 결합

  • Trusted Types API는 HTML 파싱과 삽입을 중앙에서 제어해 추가적인 보안 계층을 제공
    • setHTML() 사용 시 Trusted Types 정책을 쉽게 적용할 수 있음
    • 엄격한 정책은 setHTML()만 허용하고 다른 위험한 삽입 방식을 차단해 미래의 XSS 회귀 방지에 기여

Firefox 148의 보안 향상 효과

  • Firefox 148은 Sanitizer APITrusted Types를 모두 지원해 기본 보안 수준을 크게 향상
  • 개발자는 복잡한 보안 정책이나 별도의 보안팀 없이도 간단한 코드 변경만으로 XSS 방지 가능
  • 이 표준의 도입은 모든 브라우저의 안전한 웹 환경 확산으로 이어질 것으로 기대됨

요약

  • Firefox 148은 setHTML() 메서드와 Sanitizer API를 통해 웹 개발자가 손쉽게 XSS 공격을 차단할 수 있도록 지원
  • 이 기능은 CSP의 한계를 보완하며, 기본적으로 안전한 HTML 삽입 방식을 웹 표준으로 정착시키는 계기임
  • Trusted Types와의 결합으로 장기적인 보안 유지와 XSS 회귀 방지가 가능함
  • 결과적으로, Firefox는 보안이 기본값인 웹 환경으로의 전환을 주도하고 있음

오 확실히 이런게 필요하긴 하죠. 모든 브라우저에서 지원되면 엄청 좋을거 같네요

Hacker News 의견들
  • 이런 종류의 기능은 항상 좀 불안함
    사용자 입력을 임의로 넘겨도 안전하게 처리되는 메서드와 그렇지 않은 메서드가 섞여 있는데, 이름만 봐서는 구분이 어렵기 때문임
    이상적으로는 처음부터 위험한 함수는 이름에서 명확히 드러나야 함
    또, HTML을 “sanitize”한다는 개념 자체가 모호하고, 실제로 안전한지 판단하기 어려움

    • “안전”의 정의가 모호하다는 건 맞지만, 여기서 목표는 XSS-safe
      스크립트를 실행할 수 있는 요소나 속성을 제거하고, 이 로직이 브라우저 엔진 내부에서 동작해 문자열 기반의 sanitizer보다 정확하게 처리됨
      자세한 내용은 MDN setHTML 문서 참고
    • 사실 이미 명확한 구분이 있음
      elementNode.textContent는 신뢰할 수 없는 입력에도 안전하고, elementNode.innerHTML은 그렇지 않음
      전자는 모든 문자를 escape하고, 후자는 아무것도 escape하지 않음
      “HTML sanitization”은 근본적으로 해결 불가능한 문제라는 의견도 있음
      관련 논의는 이 댓글 참고
      이런 API는 제안 단계에서 통과되지 말았어야 함
    • innerHTMLsetHTML을 섞어 쓰는 게 아니라, innerHTML을 완전히 제거하고 예전 동작이 필요하면 setHTMLUnsafe를 쓰는 식으로 설계해야 함
    • 웹 개발자가 전역 설정으로 innerHTML 같은 구식 API를 비활성화할 수 있으면 좋겠음
      다만 그렇게 하면 오래된 브라우저에서는 사이트가 작동하지 않을 수도 있음
    • 페이지를 Content-Security-Policy: require-trusted-types-for 'script' 헤더와 함께 제공하면, sanitizer가 없는 메서드에 일반 문자열을 전달하는 걸 차단할 수 있음
  • 예시처럼 <h1>이나 <br> 같은 태그를 사용자 이름에 삽입할 수 있다면, 스크립트 실행은 막더라도 여전히 임의의 마크업 주입이 가능함
    <style> 태그로 CSS를 바꿔버릴 수도 있어서, 예컨대 PayPal 프로필 페이지의 디자인을 바꿔버릴 수도 있음
    이런 걸 누가 원하겠는가 하는 의문이 듦

    • 그래도 포럼처럼 사용자가 Markdown을 쓸 수 있게 하고 싶을 때는 유용할 수 있음
      Markdown으로 생성된 HTML을 sanitizer로 한 번 더 제한해 특정 태그만 허용하는 식으로 방어층을 추가할 수 있음
    • 이런 경우라면 innerHTML이 아니라 innerTexttextContent를 써야 했음
      setHTMLinnerHTML의 대체용임
    • setHTML()의 기본 설정이 너무 엄격하거나 느슨하면, 개발자가 허용할 HTML 요소와 속성을 직접 정의하는 커스텀 설정을 제공할 수 있음
    • CSS만으로도 보안 위험이 생길 수 있기 때문에, 여전히 주의가 필요함
      관련 논의는 이 스레드 참고
    • 예를 들어
      .setHTML("<h1>Hello</h1>", new Sanitizer({}))
      
      이렇게 하면 모든 요소가 제거됨
      결국 백엔드에서도 여전히 사용자 이름을 표준 방식으로 sanitize해야 하고, 출력 시에는 HTML escape를 적용해야 함
      RFC 2119에 따르면 이는 “SHOULD” 수준의 요구사항임
  • 이 기능이 등장한 건 반갑지만, 브라우저 지원이 충분히 퍼지려면 시간이 걸릴 듯함
    Can I use에서 지원 현황을 확인할 수 있음

    • 다른 브라우저 API처럼 몇 년은 걸릴 수도 있고, 최신 버전만 대상으로 한다면 몇 달 안에 가능할 수도 있음
      그동안은 polyfill로 대체할 수 있음
  • 제목이 약간 자극적이었음
    사실 innerHTML에 넘기기 전에 입력을 검사하는 함수로도 sanitization을 구현할 수 있지 않나 싶음
    다만 이런 시도들이 결국 바퀴 재발명처럼 느껴짐
    또, 오래된 Firefox에서는 hacks.mozilla.org가 아예 열리지 않고, Pale Moon이나 SeaMonkey에서는 MDN이 깨져 보임
    마치 “브라우저 카르텔”이 웹을 망치려는 것 같음

    • “입력 검사 함수로 해결 가능하다”는 건 “C 언어도 버그만 없으면 메모리 안전하다”는 말과 같음
      파서 간의 차이(parser differential) 문제도 고려하지 않은 주장임
  • Sanitizer API를 잘못 쓰면 footgun이 될 수 있음
    특히 “remove” 모드를 쓸 때 조심해야 함
    차라리 setText만 쓰고, 사용자에게 HTML 추가를 전혀 허용하지 않는 게 낫다고 생각함

    • 허용 목록 기반(allowlist) Sanitizer를 쓰면 위험은 줄지만, setHTML을 쓰는 한 XSS는 발생하지 않음
    • 하지만 페이지 작성자가 큰 HTML 조각을 추가해야 할 때는 어떻게 할 것인가
      innerHTML이 자주 쓰이는 현실을 보면, 완전히 배제하기는 어려움
    • 오히려 이런 API가 “100% 안전하다”는 착각을 불러일으켜 더 위험할 수도 있음
  • 네트워크 접근의 모든 측면이 제대로 제어되어, 이제는 보안 체인이 코드 신뢰에서 호스트 설정 신뢰로 옮겨간 점이 인상적임
    기본값도 안전하게 설정되어 있음

  • 내가 진짜 원하는 건 위험한 코드를 안전하게 실행할 수 있는 <sandbox> 요소
    위험한 코드를 수정하는 게 아니라, 격리된 환경에서 돌릴 수 있게 하는 것임
    iframe은 DOM과 함께 흐르지 못하는 제약이 있고, AI나 동적 콘텐츠가 늘어나는 시대에는 구성 가능한 캡슐화가 필요함

  • setHTMLUnsafe라는 이름이 정말 마음에 듦
    보안 기능은 개발자가 opt-in해야 하는 구조로는 실패함
    대신 “위험한 경로가 위험하게 느껴지게” 만드는 게 효과적임

  • set_html()이라는 이름이 inner_html보다 훨씬 직관적
    자바스크립트의 API는 정말 뒤죽박죽이라 언젠가 정리돼야 함
    이번 논의는 보안 중심이지만, 새 API를 공개할 때는 설계 자체도 깔끔해야 함

    • 엄밀히 말하면 이건 DOM API
      DOM API는 예전부터, 그리고 지금도 “API를 만들어본 적 없는 사람들이 만든 것 같다”는 느낌을 줌
  • 90년대 개발자들:

    SQL("select * from user where name = " + name);
    

    2020년대 개발자들:

    div.innerHTML = "Hello " + user.name;
    
    • 2030년대 개발자들:
      "Summarize this email: " + email.contents
      
      프롬프트 인젝션은 단지 새로운 기술 위의 같은 문제임
      우리는 90년대에서 아무것도 배우지 못했음