mirror of
https://github.com/hanzoai/DOMPurify.git
synced 2026-09-24 16:55:05 +00:00
90 lines
3.8 KiB
HTML
90 lines
3.8 KiB
HTML
<!doctype html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="utf-8" />
|
|
<title>DOMPurify demo: Hook to sandbox JavaScript via MentalJS</title>
|
|
<script src="../dist/purify.js"></script>
|
|
<!-- Grab the latest version of MentalJS -->
|
|
<script src="./lib/Mental.js"></script>
|
|
</head>
|
|
<body>
|
|
<!-- Our DIV to receive content -->
|
|
<div id="sanitized"></div>
|
|
<div id="test"></div>
|
|
<!-- Now let's sanitize that content -->
|
|
<script>
|
|
'use strict';
|
|
|
|
// Initialize MentalJS
|
|
MentalJS().init({ dom: true, parseInnerHTML: filter });
|
|
|
|
// Specify dirty HTML
|
|
const dirty = `
|
|
abc<script>alert('from script:'+location)<\/script>
|
|
<img src="xyz" onerror="document.getElementById('test').innerHTML='<img src=123 onerror=alert(/from_innerhtml/);';" />
|
|
<img src="xyz" onerror="alert('from img:'+location)">
|
|
<img src="xyz" onload="alert\`3\`">
|
|
<img src="xyz" onload="">
|
|
<script src=//evil.com><\/script>
|
|
<script>alert\`4\`<\/script>
|
|
<script src=//evil.com>alert(5)<\/script>
|
|
<svg><script xlink:href=//evil.com>alert(6)<\/script></svg>
|
|
<svg><script href="//evil.com">123<\/script><p>
|
|
`;
|
|
|
|
// Add a hook to sanitize all script content with MentalJS
|
|
DOMPurify.addHook('uponSanitizeElement', (node, data) => {
|
|
if (data.tagName === 'script') {
|
|
const script = node.textContent;
|
|
// Note: we never remove the <script> node ourselves -
|
|
// it is not an allowed tag, so DOMPurify removes it
|
|
// after this hook returns. Pre-detaching it here would
|
|
// trip DOMPurify's fail-closed removal guard.
|
|
if (!script || 'src' in node.attributes
|
|
|| 'href' in node.attributes
|
|
|| 'xlink:href' in node.attributes) {
|
|
return;
|
|
}
|
|
try {
|
|
const mental = MentalJS().parse({
|
|
options: { eval: false, dom: false },
|
|
code: script
|
|
});
|
|
const scriptNode = document.createElement('script');
|
|
scriptNode.appendChild(document.createTextNode(mental));
|
|
document.head.appendChild(scriptNode);
|
|
} catch (e) {
|
|
// parse failed - DOMPurify removes the node anyway
|
|
}
|
|
}
|
|
});
|
|
|
|
// Add a hook to sanitize all allow-listed events with MentalJS
|
|
DOMPurify.addHook('uponSanitizeAttribute', (node, data) => {
|
|
if (data.attrName.match(/^on\w+/)) {
|
|
const script = data.attrValue;
|
|
try {
|
|
return data.attrValue = MentalJS().parse({
|
|
options: { eval: false, dom: false },
|
|
code: script
|
|
});
|
|
} catch (e) {
|
|
return data.attrValue = '';
|
|
}
|
|
}
|
|
});
|
|
|
|
function filter(dirty) {
|
|
const config = {
|
|
ADD_TAGS: ['script'],
|
|
ADD_ATTR: ['onclick', 'onmouseover', 'onload', 'onunload', 'onerror']
|
|
};
|
|
const clean = DOMPurify.sanitize(dirty, config);
|
|
return clean;
|
|
}
|
|
|
|
document.getElementById('sanitized').innerHTML = filter(dirty);
|
|
</script>
|
|
</body>
|
|
</html>
|