使用 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 - 但对于脚本标签,由于特殊行为,它们是安全的 - &lt;script&gt; 部分可能根本不包含 &lt;/script&gt;,除非它应该在这个位置结束。因此,很容易将其与正则表达式匹配。但是,快速浏览一下,上面的正则表达式不考虑结束标记内的尾随空格,因此您必须测试 &lt;/script    等是否仍然有效。

【讨论】:

如果将文档中元素的 innerHTML 属性设置为包含具有 defer 属性的脚本元素的标记,它将在某些浏览器(如 IE)中执行。但是,如果将相同的标记分配给不在文档中的元素,或者未设置 defer 属性,则不会执行脚本。使用正则表达式是有问题的,在某些情况下会失败。 Prototype.js 使用不同的正则表达式:/&lt;script[^&gt;]*&gt;([\\S\\s]*?)&lt;\/script&gt;/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 &lt;script type="text/javascript"&gt; var test1 = "&lt;/script&gt;"; var test2 = '&lt;script&gt;'; &lt;/script&gt; &lt;/script&gt; 不允许在脚本标签内。它总是结束它。【参考方案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 代码,它一直很好地为我服务。 你的正则表达式很有趣,因为它能够忽略嵌套字符串。但我建议用&lt;script(?: 替换开头,否则我得到一个总是空的捕获组。说到这个,你看到你的正则表达式捕获 js 内容的解决方案了吗?不必单独删除标签会很有趣.. 感谢 @Kaddath 的 cmets。编辑了正则表达式,见注释。捕获 JS 内容也不应该太难,但这不是问题的一部分。【参考方案5】:

每当您不得不求助于基于正则表达式的脚本标签清理时。至少以

的形式在结束标记中添加一个空格
</script\s*>

否则像

<script>alert(666)</script   >

将保留,因为标记名后的尾随空格有效。

【讨论】:

投票,但请不要将这样的事情单独发布。它必须是评论。【参考方案6】:

如果你想从一些 HTML 文本中删除所有 JavaScript 代码,那么删除 &lt;script&gt; 标签是不够的,因为 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() 他们!

有趣的事实:当您创建带有&lt;script&gt; 标签的元素时,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 中删除所有脚本标签的主要内容,如果未能解决你的问题,请参考以下文章

PHP/SSH 正则表达式脚本/命令从许多文件中删除相同的恶意软件代码

在python中使用正则表达式从文本中删除html标签

基于正则表达式的行删除脚本(JS)不起作用

使用正则表达式从 HTML 中提取所有值

正则表达式从字符串中删除所有特殊字符?

从 HTML 中提取文本的正则表达式