DOMPurify는 HTML, MathML 및 SVG를 위한 DOM 전용, 초고속, 뛰어난 내성을 갖춘 XSS 살균제입니다.
사용 및 시작도 매우 간단합니다. DOMPurify는 2014년 2월에 시작되었으며 현재 v3.2.1 버전에 도달했습니다.
DOMPurify는 JavaScript로 작성되었으며 모든 최신 브라우저(Safari(10+), Opera(15+), Edge, Firefox 및 Chrome뿐만 아니라 Blink, Gecko 또는 WebKit을 사용하는 거의 모든 브라우저)에서 작동합니다. MSIE 또는 기타 레거시 브라우저에서는 중단되지 않습니다. 그것은 단순히 아무것도 하지 않습니다.
DOMPurify v2.5.7은 MSIE를 지원하는 최신 버전입니다. MSIE와 호환되는 중요한 보안 업데이트를 받으려면 2.x 분기를 사용하세요.
우리의 자동화된 테스트는 현재 24개의 다양한 브라우저를 다루고 있으며 앞으로 더 많은 브라우저가 포함될 예정입니다. 또한 jsdom에서 DOMPurify를 실행하는 Node.js v16.x, v17.x, v18.x 및 v19.x를 다룹니다. 이전 Node 버전도 작동하는 것으로 알려져 있지만... 보장할 수는 없습니다.
DOMPurify는 웹 공격 및 XSS에 대한 광범위한 배경 지식을 가진 보안 전문가가 작성했습니다. 두려워하지 마세요. 자세한 내용은 보안 목표 및 위협 모델을 읽어보세요. 꼭 읽어주세요. 정말요.
DOMPurify는 HTML을 삭제하고 XSS 공격을 방지합니다. 더티 HTML로 가득 찬 문자열을 DOMPurify에 제공할 수 있으며 달리 구성하지 않는 한 깨끗한 HTML이 포함된 문자열을 반환합니다. DOMPurify는 위험한 HTML이 포함된 모든 것을 제거하여 XSS 공격 및 기타 불쾌감을 방지합니다. 그것도 엄청나게 빠릅니다. 우리는 브라우저가 제공하는 기술을 사용하여 이를 XSS 필터로 전환합니다. 브라우저가 빠를수록 DOMPurify가 더 빨라집니다.
쉽습니다. 귀하의 웹사이트에 DOMPurify를 포함시키면 됩니다.
<script type="text/javascript" src="src/purify.js"></script>
<script type="text/javascript" src="dist/purify.min.js"></script>
그런 다음 다음 코드를 실행하여 문자열을 정리할 수 있습니다.
const clean = DOMPurify.sanitize(더러운);
또는 Angular 등을 사용하여 작업하는 것을 좋아한다면 다음과 같을 수도 있습니다.
import DOMPurify from 'dompurify';const clean = DOMPurify.sanitize('<b>안녕하세요</b>');
결과 HTML은 innerHTML
사용하여 DOM 요소에 작성하거나 document.write()
사용하여 DOM에 작성할 수 있습니다. 그것은 전적으로 당신에게 달려 있습니다. 기본적으로 HTML, SVG 및 MathML이 허용됩니다. 매우 일반적인 사용 사례인 HTML만 필요한 경우에도 쉽게 설정할 수 있습니다.
const clean = DOMPurify.sanitize(dirty, { USE_PROFILES: { html: true } });
먼저 HTML을 삭제한 다음 나중에 수정하면 삭제 효과가 쉽게 무효화 될 수 있습니다. 정리된 마크업을 정리한 후 다른 라이브러리에 공급하는 경우 라이브러리가 자체적으로 HTML을 조작하지 않는지 확인하세요.
마크업을 삭제한 후 DOMPurify.removed
속성을 살펴보고 어떤 요소와 속성이 삭제되었는지 확인할 수도 있습니다. 보안에 중요한 결정을 내리는 데 이 속성을 사용하지 마십시오 . 이것은 호기심 많은 사람들을 위한 작은 도우미일 뿐입니다.
DOMPurify는 기술적으로 Node.js와 함께 서버 측에서도 작동합니다. 우리의 지원은 Node.js 릴리스 주기를 따르기 위해 노력하고 있습니다.
서버에서 DOMPurify를 실행하려면 DOM이 있어야 하는데 이는 놀랄 일이 아닙니다. 일반적으로 jsdom이 선택되는 도구이므로 최신 버전의 jsdom을 사용하는 것이 좋습니다 .
왜? 이전 버전의 jsdom 은 DOMPurify가 모든 것을 100% 올바르게 수행 하더라도 XSS를 발생시키는 방식으로 버그가 있는 것으로 알려져 있기 때문입니다. 예를 들어 jsdom v20.0.0 에서 수정된 jsdom v19.0.0 에는 알려진 공격 벡터가 있습니다. 따라서 jsdom을 최신 상태로 유지하는 것이 좋습니다.
happy-dom과 같은 도구가 존재하지만 현재로서는 안전한 것으로 간주되지 않는다는 점에 유의하세요. DOMPurify와 happy-dom을 결합하는 것은 현재 권장되지 않으며 XSS로 이어질 가능성이 높습니다.
그 외에는 서버에서 DOMPurify를 사용해도 괜찮습니다. 아마. 이것은 실제로 jsdom 또는 서버 측을 활용하는 DOM에 따라 다릅니다. 당신이 그것을 감당할 수 있다면, 이것이 작동하게 하는 방법은 다음과 같습니다:
npm 설치 dompurify npm 설치 jsdom
jsdom 의 경우(최신 버전을 사용하세요) 다음과 같이 하면 됩니다.
const createDOMPurify = require('dompurify');const { JSDOM } = require('jsdom');const window = new JSDOM('').window;const DOMPurify = createDOMPurify(window);const clean = DOMPurify.sanitize(' <b>안녕하세요</b>');
또는 가져오기 작업을 선호하는 경우에도 마찬가지입니다.
import { JSDOM } from 'jsdom'; import DOMPurify from 'dompurify';const window = new JSDOM('').window;const purify = DOMPurify(window);const clean = purify.sanitize('<b>안녕하세요< /b>');
특정 설정에서 작동하는 데 문제가 있는 경우 사람들이 직면할 수 있는 많은 문제를 해결하는 놀라운 isomorphic-dompurify 프로젝트를 살펴보세요.
npm 설치 동형-dompurify
import DOMPurify from 'isomorphic-dompurify';const clean = DOMPurify.sanitize('<s>hello</s>');
물론 데모도 있습니다! DOMPurify로 플레이
우선, 문제를 해결할 수 있도록 즉시 이메일로 연락해 주시기 바랍니다. PGP 키
또한, 당신은 아마도 버그 현상금을 받을 자격이 있을 것입니다! Fastmail의 훌륭한 사람들은 서비스에 DOMPurify를 사용하고 버그 현상금 범위에 우리 라이브러리를 추가했습니다. 따라서 DOMPurify를 우회하거나 약화시키는 방법을 찾으면 해당 웹사이트와 버그 바운티 정보도 살펴보시기 바랍니다.
정제된 마크업은 어떻게 생겼나요? 음, 데모에서는 불쾌한 요소가 많이 있음을 보여줍니다. 하지만 더 작은 예도 보여드리겠습니다!
DOMPurify.sanitize('<img src=x onerror=alert(1)//>'); // <img src="x">DOMPurify.sanitize('<svg><g/onload=alert(2)//<p>')가 됩니다. // <svg><g></g></svg>DOMPurify.sanitize('<p>abc<iframe//src=jAva	script:alert(3)>def</p>');가 됩니다. // <p>abc</p>DOMPurify.sanitize('<math><mi//xlink:href="data:x,<script>alert(4)</script>">')가 됩니다. // <math><mi></mi></math>DOMPurify.sanitize('<TABLE><tr><td>HELLO</tr></TABL>')가 됩니다. // <table><tbody><tr><td>HELLO</td></tr></tbody></table>DOMPurify.sanitize('<UL><li><A HREF=//google이 됩니다. .com>클릭</UL>'); // <ul><li><a href="//google.com">클릭</a></li></ul>이 됩니다.
DOMPurify는 현재 HTML5, SVG 및 MathML을 지원합니다. 기본적으로 DOMPurify는 CSS, HTML 사용자 정의 데이터 속성을 허용합니다. DOMPurify는 Shadow DOM도 지원하며 DOM 템플릿을 재귀적으로 삭제합니다. DOMPurify를 사용하면 알려진 문제 없이 jQuery $()
및 elm.html()
API와 함께 사용하기 위해 HTML을 정리할 수 있습니다.
DOMPurify는 전혀 아무것도 하지 않습니다. 단순히 입력한 문자열을 정확하게 반환합니다. DOMPurify는 isSupported
라는 속성을 노출합니다. 이 속성은 작업을 수행할 수 있는지 여부를 알려주므로 사용자는 자신만의 백업 계획을 세울 수 있습니다.
버전 1.0.9에서는 Trusted Types API에 대한 지원이 DOMPurify에 추가되었습니다. 버전 2.0.0에서는 이와 관련된 DOMPurify의 동작을 제어하기 위해 구성 플래그가 추가되었습니다.
Trusted Types API를 사용할 수 있고 RETURN_TRUSTED_TYPE
이 true
로 설정된 환경에서 DOMPurify.sanitize
사용하면 문자열 대신 TrustedHTML
값을 반환하려고 시도합니다( RETURN_DOM
및 RETURN_DOM_FRAGMENT
구성 옵션의 동작은 변경되지 않음).
DOMPurify를 사용하여 trustedTypes
에 정책을 생성하려면 RETURN_TRUSTED_TYPE: false
필요합니다. createHTML
TrustedHTML
이 아닌 일반 문자열을 기대하기 때문입니다. 아래 예는 이를 보여줍니다.
window.trustedTypes!.createPolicy('기본값', { createHTML: (to_escape) =>DOMPurify.sanitize(to_escape, { RETURN_TRUSTED_TYPE: false }),});
예. 포함된 기본 구성 값은 이미 매우 훌륭하지만 물론 이를 재정의할 수 있습니다. DOMPurify를 사용자 정의하는 방법에 대한 여러 예를 보려면 /demos
폴더를 확인하세요.
// {{ ... }}, ${ ... } 및 <% ... %>를 제거하여 템플릿 시스템에 대한 출력을 안전하게 만듭니다.// 주의하세요. 이 모드는 프로덕션 용도로 권장되지 않습니다.// 허용 사용자 제어 HTML의 템플릿 구문 분석은 전혀 권장되지 않습니다.// 실제로 대안이 없는 경우에만 이 모드를 사용하십시오.const clean = DOMPurify.sanitize(dirty, {SAFE_FOR_TEMPLATES: true});// 위험한 내용이 포함된 주석 등 방법을 변경하세요. HTML 문자 // 매우 주의하세요. 실제로 HTML만 처리하고 // 다른 것, SVG, MathML 등은 처리하지 않는 경우에만 이 설정을 'false'로 설정해야 합니다. // 그렇지 않으면 `true`에서 `false`로 변경하면 이런 방식이나 다른 방식으로 XSS가 발생합니다.const clean = DOMPurify.sanitize(dirty, {SAFE_FOR_XML: false});
// 매우 엄격한 <b> 요소만 허용const clean = DOMPurify.sanitize(dirty, {ALLOWED_TAGS: ['b']});// 스타일 속성이 있는 <b> 및 <q>만 허용const clean = DOMPurify.sanitize( dirty, {ALLOWED_TAGS: ['b', 'q'], ALLOWED_ATTR: ['style']});// 모든 안전한 HTML 요소를 허용하지만 SVG나 요소는 허용하지 않습니다. MathML// USE_PROFILES 설정은 ALLOWED_TAGS 설정보다 우선하므로 // 함께 사용하지 마십시오.const clean = DOMPurify.sanitize(dirty, {USE_PROFILES: {html: true}});// 모든 안전한 SVG 요소 및 SVG를 허용합니다. 필터, HTML 또는 MathML 없음const clean = DOMPurify.sanitize(dirty, {USE_PROFILES: {svg: true, svgFilters: true}});// 모든 안전한 MathML 요소와 SVG를 허용하지만 SVG 필터는 허용하지 않습니다.const clean = DOMPurify.sanitize(dirty, {USE_PROFILES: {mathMl: true, svg: true}});// 기본 네임스페이스 변경 HTML에서 다른 것으로 const clean = DOMPurify.sanitize(dirty, {NAMESPACE: 'http://www.w3.org/2000/svg'});// 모든 안전한 HTML을 그대로 두고 <style> 요소를 block-list에 추가합니다.const clean = DOMPurify.sanitize(dirty, {FORBID_TAGS: [' style']});// 모든 안전한 HTML을 그대로 두고 블록 목록에 스타일 속성을 추가합니다.const clean = DOMPurify.sanitize(dirty, {FORBID_ATTR: ['style']});// 허용된 태그의 기존 배열을 확장하고 <my-tag>를 허용 목록에 추가합니다.const clean = DOMPurify.sanitize(dirty, {ADD_TAGS: ['my-tag']});/ / 허용된 속성의 기존 배열을 확장하고 my-attr을 허용 목록에 추가합니다.const clean = DOMPurify.sanitize(dirty, {ADD_ATTR: ['my-attr']});// 금지 ARIA 속성, 다른 안전한 HTML을 그대로 유지(기본값은 true)const clean = DOMPurify.sanitize(dirty, {ALLOW_ARIA_ATTR: false});// HTML5 데이터 속성을 금지하고, 다른 안전한 HTML을 그대로 유지(기본값은 true)const clean = DOMPurify.sanitize(dirty, {ALLOW_DATA_ATTR: false});
// DOMPurify를 사용하면 맞춤 요소에 대한 규칙을 정의할 수 있습니다. CUSTOM_ELEMENT_HANDLING// 리터럴을 사용할 때 허용하려는 요소를 정확히 정의하는 것이 가능합니다(기본적으로 어떤 요소도 허용되지 않습니다).//// 해당 속성도 마찬가지입니다. 기본적으로 내장 또는 구성된 허용 목록이 사용됩니다.//// RegExp 리터럴을 사용하여 허용되는 항목이나 조건자를 지정할 수 있습니다. 두 가지에 대한 예는 아래에서 볼 수 있습니다.// 기본값은 매우 제한적입니다. 우발적인 XSS 우회를 방지합니다. 조심해서 다루세요!const clean = DOMPurify.sanitize('<foo-bar baz="foobar" allowed="true"></foo-bar><div is="foo-baz"></div>', {CUSTOM_ELEMENT_HANDLING: {tagNameCheck: null, // 허용되는 맞춤 요소가 없습니다attributeNameCheck: null, // 기본/표준 속성 허용 목록이 사용됩니다allowCustomizedBuiltInElements: false, // 사용자 정의 내장 기능은 허용되지 않습니다.},}); // <div is=""></div>const clean = DOMPurify.sanitize('<foo-bar baz="foobar" allowed="true"></foo-bar><div is="foo-baz "></div>',{CUSTOM_ELEMENT_HANDLING: {tagNameCheck: /^foo-/, // "foo-"로 시작하는 모든 태그 허용attributeNameCheck: /baz/, // 다음을 포함하는 모든 속성 허용 "baz"allowCustomizedBuiltInElements: true, // 사용자 정의 내장 기능이 허용됩니다},}); // <foo-bar baz="foobar"></foo-bar><div is="foo-baz"></div>const clean = DOMPurify.sanitize('<foo-bar baz="foobar" 금지됨 ="true"></foo-bar><div is="foo-baz"></div>',{CUSTOM_ELEMENT_HANDLING: {tagNameCheck: (tagName) => tagName.match(/^foo-/), // "foo-"attributeNameCheck: (attr) => attr.match(/baz/), // "baz"를 포함하는 모든 태그 허용allowCustomizedBuiltInElements: true, // 맞춤형 내장 기능 허용},}); // <foo-bar baz="foobar"></foo-bar><div is="foo-baz"></div>
// 데이터 URI를 사용할 수 있는 기존 요소 배열 확장const clean = DOMPurify.sanitize(dirty, {ADD_DATA_URI_TAGS: ['a', 'area']});// URI에 안전한 기존 요소 배열 확장 값과 유사함(조심하세요, XSS 위험)const clean = DOMPurify.sanitize(dirty, {ADD_URI_SAFE_ATTR: ['내 속성']});
// URL 속성에서 외부 프로토콜 처리기를 허용합니다(기본값은 false입니다. XSS 위험에 주의하세요)// 기본적으로 http, https, ftp, ftps, tel, mailto, callto, sms, cid 및 xmpp만 허용됩니다.const clean = DOMPurify.sanitize(dirty, {ALLOW_UNKNOWN_PROTOCOLS: true});// 정규식을 통해 URL 속성에 특정 프로토콜 처리기를 허용합니다(기본값은 false입니다. 주의하세요. XSS 위험)// 기본적으로 http, https, ftp, ftps, tel, mailto, callto, sms, cid 및 xmpp만 허용됩니다.// 기본 RegExp: /^(?:(?:(?:f|ht)tps?|mailto|tel|callto|sms|cid|xmpp):|[^az]|[a-z+.-]+(?:[^ a-z+.-:]|$))/i;const clean = DOMPurify.sanitize(dirty, {ALLOWED_URI_REGEXP: /^(?:(?:(?:f|ht)tps?|mailto|tel|callto|sms|cid|xmpp|xxx):|[^az]|[a-z+.-]+(?: [^a-z+.-:]|$))/i});
// HTML 문자열 대신 DOM HTMLBodyElement를 반환합니다(기본값은 false)const clean = DOMPurify.sanitize(dirty, {RETURN_DOM: true});// HTML 문자열 대신 DOM DocumentFragment를 반환합니다(기본값은 false)const clean = DOMPurify.sanitize(dirty, {RETURN_DOM_FRAGMENT: true});// Trusted를 켜려면 RETURN_TRUSTED_TYPE 플래그를 사용하세요. 사용 가능한 경우 유형 지원const clean = DOMPurify.sanitize(dirty, {RETURN_TRUSTED_TYPE: true}); // 가능한 경우 문자열 대신 TrustedHTML 객체를 반환합니다.// 제공된 신뢰할 수 있는 유형 정책을 사용합니다.const clean = DOMPurify.sanitize(dirty, {// 제공된 정책은 createHTML 및 createScriptURLTRUSTED_TYPES_POLICY를 정의해야 합니다.trustedTypes.createPolicy({createHTML(s) { return s},createScriptURL(s) { return s},}});
// <html> 태그를 포함한 전체 문서 반환(기본값은 false)const clean = DOMPurify.sanitize(dirty, {WHOLE_DOCUMENT: true});// 출력 시 DOM 클로버링 보호 비활성화(기본값은 true, 주의해서 처리, 사소한 XSS) 여기서 위험)const clean = DOMPurify.sanitize(dirty, {SANITIZE_DOM: false});// 네임스페이스 격리를 통해 엄격한 DOM 클로버링 보호를 적용합니다(기본값은 false)// 언제 활성화되면 명명된 속성(예: `id` 및 `name` 속성)의 네임스페이스를 JS 변수에 `user-content-` 문자열 접두사를 추가하여 분리합니다. const clean = DOMPurify.sanitize(dirty, {SANITIZE_NAMED_PROPS: true });// 요소가 제거될 때 요소의 콘텐츠를 유지합니다(기본값은 true)const clean = DOMPurify.sanitize(dirty, {KEEP_CONTENT: false});// 스타일, 스크립트 또는 기타 요소와 같은 요소를 document.body에 연결하고 여러 가지 극단적인 경우에서 직관적이지 않은 브라우저 동작을 방지합니다(기본값은 false)const clean = DOMPurify.sanitize(dirty, {FORCE_BODY: true});/ / 제거된 <p> 요소 아래의 모든 <a> 요소를 제거합니다.const clean = DOMPurify.sanitize(dirty, {FORBID_CONTENTS: ['a'], FORBID_TAGS: ['p']});// 삭제된 데이터가 기본값인 HTML이 아닌 XML로 처리되도록 파서 유형을 변경합니다.const clean = DOMPurify.sanitize(dirty, {PARSER_MEDIA_TYPE: 'application/xhtml+xml' });
// IN_PLACE 모드를 사용하여 "제자리" 노드를 삭제합니다. 이는 DOMPurifyconst 사용 방법에 따라 훨씬 빠릅니다. dirty = document.createElement('a');dirty.setAttribute('href', 'javascript:alert(1) )');const clean = DOMPurify.sanitize(dirty, {IN_PLACE: true}); // 자세한 내용은 https://github.com/cure53/DOMPurify/issues/288을 참조하세요.
여기에는 필요에 맞게 DOMPurify를 실행, 사용자 정의 및 구성하는 방법을 보여주는 더 많은 예가 있습니다.
동일한 구성을 DOMPurify.sanitize
에 반복적으로 전달하는 대신 DOMPurify.setConfig
메서드를 사용할 수 있습니다. 구성은 다음에 DOMPurify.setConfig
를 호출하거나 DOMPurify.clearConfig
호출하여 재설정할 때까지 유지됩니다. 활성 구성은 하나만 있다는 점을 기억하세요. 즉, 일단 설정되면 DOMPurify.sanitize
에 전달된 모든 추가 구성 매개변수가 무시됩니다.
DOMPurify를 사용하면 DOMPurify.addHook
메서드를 사용하여 하나 이상의 함수를 다음 후크 중 하나에 연결하여 기능을 강화할 수 있습니다.
beforeSanitizeElements
uponSanitizeElement
('s' 없음 - 모든 요소에 대해 호출됨)
afterSanitizeElements
beforeSanitizeAttributes
uponSanitizeAttribute
afterSanitizeAttributes
beforeSanitizeShadowDOM
uponSanitizeShadowNode
afterSanitizeShadowDOM
필요한 경우 확인된 노드 및 속성 데이터와 DOMPurify 구성이 포함된 리터럴을 콜백에 전달하는 경우 현재 처리된 DOM 노드를 전달합니다. API가 어떻게 효과적으로 사용될 수 있는지 알아보려면 MentalJS 후크 데모를 확인하세요.
예 :
DOMPurify.addHook( 'uponSanitizeAttribute', 함수(currentNode, HookEvent, config) {// 현재 노드로 작업 수행// 현재 노드에 대해 HookEvent를 변경할 수도 있습니다(예: HookEvent.forceKeepAttr = true로 설정)// 'uponSanitizeAttribute' 후크 유형 이외의 경우 HookEvent는 null과 같습니다. });
옵션 | 부터 | 메모 |
---|---|---|
SAFE_FOR_JQUERY | 2.1.0 | 교체가 필요하지 않습니다. |
현재 우리는 BrowserStack과 함께 Github Actions를 사용하고 있습니다. 이를 통해 지원되는 모든 브라우저에서 모든 커밋이 계획대로 진행되고 있는지 확인할 수 있습니다. 여기에서 빌드 로그를 확인하세요: https://github.com/cure53/DOMPurify/actions
npm test
실행하여 로컬 테스트를 추가로 실행할 수 있습니다. 테스트는 Node.js v0.6.2 및 [email protected]에서 잘 작동합니다.
모든 관련 커밋은 추가 보안을 위해 0x24BB6BF4
키로 서명됩니다(2016년 4월 8일부터).
npm i
) 우리는 공식적으로 npm
지원합니다. GitHub Actions 워크플로는 npm
사용하여 종속성을 설치하도록 구성됩니다. 더 이상 사용되지 않는 npm
버전을 사용하면 설치된 종속성 버전을 완전히 보장할 수 없어 예상치 못한 문제가 발생할 수 있습니다.
우리는 도구 인프라와의 통합을 위해 npm 실행 스크립트를 사용합니다. 코드 일관성을 보장하기 위해 ESLint를 사전 커밋 후크로 사용합니다. 또한 형식을 쉽게 지정하기 위해 /dist
자산을 구축하는 동안 rollup
통해 발생하는 경우 더 예쁘게 사용합니다.
다음은 npm 스크립트입니다.
npm run dev
소스 변경 사항을 관찰하면서 빌드를 시작합니다.
npm run test
jsdom과 karma를 통해 테스트 스위트를 실행합니다.
test:jsdom
jsdom을 통해서만 테스트를 실행합니다.
test:karma
- Karma를 통해서만 테스트를 실행합니다.
npm run lint
ESLint를 사용하여 소스를 린트합니다(xo를 통해).
ESLint를 쉽게 전달할 수 있도록 더 예쁜 소스를 사용하여 소스 형식을 지정하는 npm run format
npm run build
npm run build:umd
축소되지 않은 UMD 모듈만 빌드합니다.
npm run build:umd:min
축소된 UMD 모듈만 빌드합니다.
참고: npm run <script>
를 통해 트리거되는 모든 실행 스크립트.
더 많은 npm 스크립트가 있지만 주로 CI와 통합하거나 커밋할 때마다 빌드 배포 파일을 수정하기 위해 "비공개"로 사용됩니다.
우리는 엄마