使用 JS 正则表达式从 html 中删除所有脚本标签
Posted
技术标签:
【中文标题】使用 JS 正则表达式从 html 中删除所有脚本标签【英文标题】:Removing all script tags from html with JS Regular Expression 【发布时间】:2011-10-03 07:31:38 【问题描述】:我想在 Pastebin 中从这个 html 中去除脚本标签:
http://pastebin.com/mdxygM0a
我尝试使用以下正则表达式:
html.replace(/<script.*>.*<\/script>/ims, " ")
但它不会删除 HTML 中的所有脚本标签。它只删除内联脚本。我正在寻找一些可以删除所有脚本标签(内联和多行)的正则表达式。如果对我的样本http://pastebin.com/mdxygM0a进行测试,将不胜感激
【问题讨论】:
请不要这样做(如果它涉及任何用户输入)。如果您不处理 every 案例 - html5sec.org 谢谢克里斯。我想我会使用 JQuery 来删除它们。 【参考方案1】:在某些情况下,jQuery 使用正则表达式来删除脚本标签,我很确定它的开发人员有充分的理由这样做。可能某些浏览器确实在使用innerHTML
插入脚本时会执行脚本。
这是正则表达式:
/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi
在人们开始哭泣“但 HTML 的正则表达式是邪恶的”之前:Yes, they are - 但对于脚本标签,由于特殊行为,它们是安全的 - <script>
部分可能根本不包含 </script>
,除非它应该在这个位置结束。因此,很容易将其与正则表达式匹配。但是,快速浏览一下,上面的正则表达式不考虑结束标记内的尾随空格,因此您必须测试 </script
等是否仍然有效。
【讨论】:
如果将文档中元素的 innerHTML 属性设置为包含具有 defer 属性的脚本元素的标记,它将在某些浏览器(如 IE)中执行。但是,如果将相同的标记分配给不在文档中的元素,或者未设置 defer 属性,则不会执行脚本。使用正则表达式是有问题的,在某些情况下会失败。 Prototype.js 使用不同的正则表达式:/<script[^>]*>([\\S\\s]*?)<\/script>/img
。
引用 jQuery 正则表达式:github.com/jquery/jquery/blob/1.7.2/src/ajax.js#L14
有人成功使用上述方法一段时间了吗?
but for script tags they are safe
这里失败了:***.com/a/18052486/2570622 <script type="text/javascript"> var test1 = "</script>"; var test2 = '<script>'; </script>
</script>
不允许在脚本标签内。它总是结束它。【参考方案2】:
尝试使用正则表达式删除 HTML 标记是有问题的。您不知道其中的脚本或属性值是什么。一种方法是将其作为 div 的 innerHTML 插入,删除任何脚本元素并返回 innerHTML,例如
function stripScripts(s)
var div = document.createElement('div');
div.innerHTML = s;
var scripts = div.getElementsByTagName('script');
var i = scripts.length;
while (i--)
scripts[i].parentNode.removeChild(scripts[i]);
return div.innerHTML;
alert(
stripScripts('<span><script type="text/javascript">alert(\'foo\');<\/script><\/span>')
);
请注意,目前,如果使用 innerHTML 属性插入脚本,浏览器将不会执行该脚本,并且可能永远不会执行,尤其是因为该元素未添加到文档中。
【讨论】:
非常感谢。我将您的方法与 jQuery 及其完美结合使用。 这在 IE8 中似乎不起作用 div.innerHTML = s;什么都不做,如果我检查 div.innerHTML 的值,它的 "" 它适用于我测试过的所有浏览器,包括 IE 6。我有几天不能尝试 IE 8,但可以肯定的是我在那里测试过并且它可以工作。我会告诉你的。 谢谢!当心 jQuery.html(),它会执行脚本:$('').html('') @scader——如果要保留样式元素,则应将它们添加为 head 元素的 innerHTML,而不是 div,然后使用 DOM 方法放入 head 中。【参考方案3】:正则表达式是可以击败的,但如果您有一个字符串版本的 HTML 并且不想注入到 DOM 中,那么它们可能是最好的方法。你可能想把它放在一个循环中来处理类似的事情:
<scr<script>Ha!</script>ipt> alert(document.cookie);</script>
这是我所做的,使用上面的 jquery 正则表达式:
var SCRIPT_REGEX = /<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi;
while (SCRIPT_REGEX.test(text))
text = text.replace(SCRIPT_REGEX, "");
【讨论】:
这很好用,但需要根据上面的 neongrau 答案进行修改,以允许结束脚本标签中的尾随空格 - 这仍然有效。 你太棒了:)【参考方案4】:这个正则表达式也应该可以工作:
<script(?:(?!\/\/)(?!\/\*)[^'"]|"(?:\\.|[^"\\])*"|'(?:\\.|[^'\\])*'|\/\/.*(?:\n)|\/\*(?:(?:.|\s))*?\*\/)*?<\/script>
它甚至允许在内部包含“有问题的”变量字符串:
<script type="text/javascript">
var test1 = "</script>";
var test2 = '\'</script>';
var test1 = "\"</script>";
var test1 = "<script>\"";
var test2 = '<scr\'ipt>';
/* </script> */
// </script>
/* ' */
// var foo=" '
</script>
看起来 jQuery 和 Prototype 在这些方面都失败了......
2017 年 7 月 31 日编辑:添加了 a) 非捕获组以提高性能(并且没有空组)和 b) 支持 JavaScript cmets。
【讨论】:
所以 HTML 的正则表达式毕竟是邪恶的!任何可以击败您的正则表达式的脚本? 我实际上在几种情况下使用邪恶的正则表达式来解析 HTML,并且它接缝工作得很好。我刚刚编辑了这篇文章,并通过支持 JavaScript 变量中的转义引号来增强正则表达式。 (那会打败我的正则表达式:-) 我在 Notepad++ 中使用这个正则表达式来清除不需要的脚本标签的 HTML 代码,它一直很好地为我服务。 你的正则表达式很有趣,因为它能够忽略嵌套字符串。但我建议用<script(?:
替换开头,否则我得到一个总是空的捕获组。说到这个,你看到你的正则表达式捕获 js 内容的解决方案了吗?不必单独删除标签会很有趣..
感谢 @Kaddath 的 cmets。编辑了正则表达式,见注释。捕获 JS 内容也不应该太难,但这不是问题的一部分。【参考方案5】:
每当您不得不求助于基于正则表达式的脚本标签清理时。至少以
的形式在结束标记中添加一个空格</script\s*>
否则像
<script>alert(666)</script >
将保留,因为标记名后的尾随空格有效。
【讨论】:
投票,但请不要将这样的事情单独发布。它必须是评论。【参考方案6】:如果你想从一些 HTML 文本中删除所有 JavaScript 代码,那么删除 <script>
标签是不够的,因为 JavaScript 仍然可以存在于“onclick”、“onerror”、“href”和其他属性中。
试试这个处理所有这些的 npm 模块: https://www.npmjs.com/package/strip-js
【讨论】:
关于 onevent 属性的要点。如果您不信任该字符串,那么您真的不应该将它作为 HTML 插入到您的页面中!有太多技巧可以绕过基于黑名单的解决方案!【参考方案7】:为什么不使用 jQuery.parseHTML() http://api.jquery.com/jquery.parsehtml/?
【讨论】:
【参考方案8】:在我的例子中,我需要解析页面标题并拥有 jQuery 的所有其他优点,减去它触发脚本。这是我的似乎可行的解决方案。
$.get('/somepage.htm', function (data)
// excluded code to extract title for simplicity
var bodySI = data.indexOf('<body>') + '<body>'.length,
bodyEI = data.indexOf('</body>'),
body = data.substr(bodySI, bodyEI - bodySI),
$body;
body = body.replace(/<script[^>]*>/gi, ' <!-- ');
body = body.replace(/<\/script>/gi, ' --> ');
//console.log(body);
$body = $('<div>').html(body);
console.log($body.html());
);
这种快捷方式会担心脚本,因为您不是要尝试删除脚本标签和内容,而是用 cmets 渲染方案替换它们以破坏它们无用,因为您会让 cmets 分隔脚本声明。
如果这仍然存在问题,请告诉我,因为它也会帮助我。
【讨论】:
这听起来很聪明,而且相当不引人注目。你有好的结果吗?任何人都可以提出这种方法的问题吗? 我正在控制被请求的页面。我没有进行严格的测试来试图以恶意意图破解它,所以我不会为此而相信它。【参考方案9】:试试这个:
var text = text.replace(/<script[^>]*>(?:(?!<\/script>)[^])*<\/script>/g, "")
【讨论】:
虽然我用过这个,而且它似乎可以工作,但 regex101 说有语法错误。【参考方案10】:您可以在没有正则表达式的情况下执行此操作。只需使用document.createElement()
将您的HTML 字符串转换为HTML 节点,找到所有带有element.getElementsByTagName('script')
的脚本,然后只需remove()
他们!
有趣的事实:当您创建带有<script>
标签的元素时,SO 的演示不喜欢它!下面的 sn-p 不会运行,但它确实可以在:Full Working Demo at JSBin.com 运行。
var el = document.createElement( 'html' );
el.innerHTML = "<p>Valid paragraph.</p><p>Another valid paragraph.</p><script>Dangerous scripting!!!</script><p>Last final paragraph.</p>";
var scripts = el.getElementsByTagName( 'script' ); // Live NodeList of your anchor elements
for(var i = 0; i < scripts.length; i++)
var script = scripts[i];
script.remove();
console.log(el.innerHTML);
这是一个比正则表达式更清洁的解决方案,恕我直言。
【讨论】:
【参考方案11】:您可以使用以下各种 shell 脚本来去除不同的元素。
# doctype
find . -regex ".*\.\(html\|py\)$" -type f -exec sed -i "s/<\!DOCTYPE\s\+html[^>]*>/<\!DOCTYPE html>/gi" \;
# meta charset
find . -regex ".*\.\(html\|py\)$" -type f -exec sed -i "s/<meta[^>]*content=[\"'][^\"']*utf-8[\"'][^>]*>/<meta charset=\"utf-8\">/gi" \;
# script text/javascript
find . -regex ".*\.\(html\|py\)$" -type f -exec sed -i "s/\(<script[^>]*\)\(\stype=[\"']text\/javascript[\"']\)\(\s\?[^>]*>\)/\1\3/gi" \;
# style text/css
find . -regex ".*\.\(html\|py\)$" -type f -exec sed -i "s/\(<style[^>]*\)\(\stype=[\"']text\/css[\"']\)\(\s\?[^>]*>\)/\1\3/gi" \;
# html xmlns
find . -regex ".*\.\(html\|py\)$" -type f -exec sed -i "s/\(<html[^>]*\)\(\sxmlns=[\"'][^\"']*[\"']\)\(\s\?[^>]*>\)/\1\3/gi" \;
# html xml:lang
find . -regex ".*\.\(html\|py\)$" -type f -exec sed -i "s/\(<html[^>]*\)\(\sxml:lang=[\"'][^\"']*[\"']\)\(\s\?[^>]*>\)/\1\3/gi" \;
【讨论】:
【参考方案12】:/(?:(?!\w))\w*/gi; - 删除任何与
组合的序列【讨论】:
【参考方案13】:你可以试试
$("your_div_id").remove();
或
$("your_div_id").html("");
【讨论】:
这将剥离所有内容,而不仅仅是脚本标签以上是关于使用 JS 正则表达式从 html 中删除所有脚本标签的主要内容,如果未能解决你的问题,请参考以下文章