FlawOpen

flawopen.com/JavaScript의 XSS/dangerouslySetInnerHTML

React의 dangerouslySetInnerHTML은 안전할까?

참고 페이지
핵심 답변

일반 JSX는 텍스트가 텍스트로 남는 라벨 프린터와 같습니다. dangerouslySetInnerHTML은 문자열을 HTML로 해석하는 인쇄기로 전환합니다. 공격자가 제어하는 내용이 문자열에 들어 있으면 브라우저가 이를 활성 마크업으로 처리할 수 있습니다. 명시적으로 신뢰하거나 정확한 HTML 컨텍스트에 맞게 정제한 HTML에만 이 출력 지점을 사용하세요.

일반 JSX에는 왜 필요하지 않을까

위험 — 원시 HTML 입력
function Comment({ html }) {
  return <p dangerouslySetInnerHTML=
    {{ __html: html }} />;
}
안전 — 일반 JSX 보간
function Comment({ text }) {
  return <p>{text}</p>;
}

dangerouslySetInnerHTML은 언제 적절할까?

일반 React 자식 요소로 표현할 수 없는 제한된 리치 텍스트 형식을 제품에서 보존해야 할 때만 사용하세요. CMS, 편집기, Markdown 렌더러라고 해서 자동으로 신뢰할 수 있는 것은 아닙니다. 저장된 콘텐츠와 렌더러 출력에도 신뢰할 수 없는 마크업이 들어갈 수 있습니다. 허용할 요소와 속성을 정하고 DOMPurify 같은 유지 관리되는 HTML 정제 라이브러리로 처리한 뒤 결과를 이 지점에 바로 전달하세요.

올바른 사용법

렌더링 경계에서 정제

dangerouslySetInnerHTML에 값을 전달하기 직전에 DOMPurify 같은 유지 관리되는 라이브러리로 정제하세요. 정규식으로 HTML을 정제하지 마세요. 정제한 문자열을 이후에 변경하면 보장이 무효화될 수 있으므로 피하세요. 정제 라이브러리와 파서 환경을 최신 상태로 유지하세요.

허용 마크업을 제한

알려진 태그만 차단하는 목록으로는 부족합니다. 속성, URL 필드, 네임스페이스, 파서 동작도 위험 요인이 될 수 있습니다. 기능에 필요한 최소한의 요소와 속성만 허용하도록 정하고 그 정책에 맞게 정제기를 설정하세요. 링크와 URL 속성은 제품에서 허용하는 목적지를 기준으로 별도 검토하세요.

코드베이스 확인 방법

grep -rn "dangerouslySetInnerHTML" --include="*.jsx" --include="*.tsx" .
각 항목에서 값의 출처와 모든 변환 과정을 추적하세요. 사용자 입력, 가져온 콘텐츠, 저장된 리치 텍스트를 신뢰할 수 없는 것으로 취급하고, 정제 정책이 출력 컨텍스트에 맞는지 및 이후 단계에서 결과를 바꾸지 않는지 확인하세요.

자주 묻는 질문

Markdown 렌더링은 자동으로 안전할까?

렌더러와 설정에 따라 다릅니다. 원시 HTML을 허용하는지, 출력물을 정제하는지 확인하세요. Markdown 변환만으로 HTML이 안전해지지는 않습니다.

Vue의 v-html에도 적용될까?

그렇습니다. v-html도 프레임워크의 일반 텍스트 보간을 거치지 않고 HTML을 브라우저에 전달합니다. HTML 출력 지점으로 보고 적절한 정책으로 신뢰할 수 없는 내용을 정제하세요.

참고 자료

함께 보기 크로스 사이트 스크립팅(XSS, CWE-79): 동작 원리와 언어별 방어 방법 — flawopen.com DOMPurify면 innerHTML을 안전하게 만들 수 있나요? Markdown 렌더링은 XSS로부터 안전한가요? Svelte는 기본적으로 XSS를 막을까? SVG 업로드는 XSS 위험이 있나요? Vue v-html XSS 위험과 안전한 사용법 WKWebView loadHTMLString은 신뢰할 수 없는 콘텐츠에 안전한가요?