我可以要求浏览器不在元素中运行<script>吗?</script>

时间:2014-09-19 08:16:21

标签: javascript html script-tag

是否可以告诉浏览器不要从HTML文档的特定部分运行JavaScript?

像:

<div script="false"> ...

它可以作为额外的安全功能使用。我想要的所有脚本都加载到文档的特定部分。文档的其他部分应该没有脚本,如果不存在则不应该运行。

7 个答案:

答案 0 :(得分:90)

是的,您可以:-)答案是: Content Security Policy (CSP)。

Most modern browsers support this flag,它告诉浏览器只从可信外部文件加载JavaScript代码并禁止所有内部JavaScript代码!唯一的缺点是,您不能在整个页面中使用任何内联JavaScript(不仅仅是单个<div>)。虽然可以通过动态包含来自具有不同安全策略的外部文件的div来解决此问题,但我不确定。

但是,如果您可以更改您的网站以从外部JavaScript文件加载所有JavaScript,那么您可以使用此标头完全禁用内联JavaScript!

这是一个很好的教程,例如:HTML5Rocks Tutorial

如果你可以配置服务器发送这个HTTP-Header标志,世界将是一个更好的地方!

答案 1 :(得分:13)

您可以使用<script>事件阻止beforescriptexecute加载的JavaScript:

<script>
  // Run this as early as possible, it isn't retroactive
  window.addEventListener('beforescriptexecute', function(e) {
    var el = e.target;
    while(el = el.parentElement)
      if(el.hasAttribute('data-no-js'))
        return e.preventDefault(); // Block script
  }, true);
</script>

<script>console.log('Allowed. Console is expected to show this');</script>
<div data-no-js>
  <script>console.log('Blocked. Console is expected to NOT show this');</script>
</div>

请注意,beforescriptexecute已在HTML 5.0中定义,但已在HTML 5.1中删除。 Firefox是唯一实现它的主要浏览器。

如果您在页面中插入一组不受信任的HTML,请注意该元素中的阻塞脚本不会提供更多安全性,因为不受信任的HTML可以关闭沙盒元素,因此脚本将被放置在外部并且运行

这不会阻止像<img onerror="javascript:alert('foo')" src="//" />这样的内容。

答案 2 :(得分:8)

有趣的问题,我不认为这是可能的。但即使它是,它听起来像是一个黑客。

如果该div的内容不受信任,那么在HTTP响应中发送数据并在浏览器中呈现之前,您需要转义服务器端的数据。

如果你只想删除<script>标签并允许其他html标签,那么只需将它们从内容中删除,剩下的就完成了。

了解XSS预防。

https://www.owasp.org/index.php/XSS_%28Cross_Site_Scripting%29_Prevention_Cheat_Sheet

答案 3 :(得分:7)

执行JavaScript&#34;内联&#34;,即按照它在DOM中出现的顺序(如果不是这样的话,你永远无法确定在不同的脚本中定义的某个变量当你第一次使用它时可见。

这意味着理论上你可以在页面的开头有一个脚本(即第一个<script>元素),它通过DOM查看并删除了你{内部的所有<script>元素和事件处理程序{1}}。

但现实情况更复杂:DOM和脚本加载异步发生。这意味着浏览器只保证脚本可以在之前看到的部分(即我们示例中的标题)。除了<div>之外,没有任何保证。所以你可能会看到下一个脚本标签,或者你可能没有。

您可以锁定文档的document.write()事件 - 这将确保您获得整个DOM - 但此时,恶意代码可能已经执行。当其他脚本操纵DOM,在那里添加脚本时,情况变得更糟。因此,您还必须检查DOM的每个更改。

所以@cowls解决方案(在服务器上过滤)是唯一可以在所有情况下工作的解决方案。

答案 4 :(得分:1)

如果您希望在浏览器中显示JavaScript代码:

使用JavaScript和HTML,您必须使用HTML entities来显示JavaScript代码并避免执行此代码。在这里,您可以找到HTML实体列表:

如果您正在使用服务器端脚本语言(PHP,ASP.NET等),那么很可能会有一个函数可以转义字符串并将特殊字符转换为HTML实体。在PHP中,您将使用&#34; htmlspecialchars()&#34;或&#34; htmlentities()&#34;。后者涵盖了所有HTML字符。

如果您希望以一种不错的方式显示您的JavaScript代码,请尝试使用其中一个代码荧光笔:

答案 5 :(得分:1)

我有一个理论:

  • 将文档的特定部分包含在noscript标记内。
  • 使用DOM函数放弃script标记内的所有noscript标记,然后展开其内容。

概念验证示例:

&#13;
&#13;
window.onload = function() {
    var noscripts = /* _live_ list */ document.getElementsByTagName("noscript"),
        memorydiv = document.createElement("div"),
        scripts = /* _live_ list */ memorydiv.getElementsByTagName("script"),
        i,
        j;
    for (i = noscripts.length - 1; i >= 0; --i) {
        memorydiv.innerHTML = noscripts[i].textContent || noscripts[i].innerText;
        for (j = scripts.length - 1; j >= 0; --j) {
            memorydiv.removeChild(scripts[j]);
        }
        while (memorydiv.firstChild) {
            noscripts[i].parentNode.insertBefore(memorydiv.firstChild, noscripts[i]);
        }
        noscripts[i].parentNode.removeChild(noscripts[i]);
    }
};
&#13;
body { font: medium/1.5 monospace; }
p, h1 { margin: 0; }
&#13;
<h1>Sample Content</h1>
<p>1. This paragraph is embedded in HTML</p>
<script>document.write('<p style="color: red;">2. This paragraph is generated by JavaScript</p>');</script>
<p>3. This paragraph is embedded in HTML</p>
<h1>Sample Content in No-JavaScript Zone</h1>
<noscript>
    <p>1. This paragraph is embedded in HTML</p>
    <script>document.write('<p style="color: red;">2. This paragraph is generated by JavaScript</p>');</script>
    <p>3. This paragraph is embedded in HTML</p>
</noscript>
<noscript>
    <p>1. This paragraph is embedded in HTML</p>
    <script>document.write('<p style="color: red;">2. This paragraph is generated by JavaScript</p>');</script>
    <p>3. This paragraph is embedded in HTML</p>
</noscript>
&#13;
&#13;
&#13;

答案 6 :(得分:0)

如果您想稍后重新启用脚本标记,我的解决方案是破坏浏览器环境,以便任何运行的脚本都会很早就抛出错误。但是,它并不完全可靠,因此您无法将其用作安全功能。

如果您尝试访问全局属性,Chrome会抛出异常。

setTimeout("Math.random()")
// => VM116:25 Uncaught Error: JavaScript Execution Inhibited  

我覆盖window上的所有可覆盖属性,但您也可以将其展开以打破其他功能。

window.allowJSExecution = inhibitJavaScriptExecution();
function inhibitJavaScriptExecution(){

    var windowProperties = {};
    var Object = window.Object
    var console = window.console
    var Error = window.Error

    function getPropertyDescriptor(object, propertyName){
        var descriptor = Object.getOwnPropertyDescriptor(object, propertyName);
        if (!descriptor) {
            return getPropertyDescriptor(Object.getPrototypeOf(object), propertyName);
        }
        return descriptor;
    }

    for (var propName in window){
        try {
            windowProperties[propName] = getPropertyDescriptor(window, propName)
            Object.defineProperty(window, propName, {
                get: function(){
                    throw Error("JavaScript Execution Inhibited")
                },
                set: function(){
                    throw Error("JavaScript Execution Inhibited")
                },
                configurable: true
            })
        } catch (err) {}
    }

    return function allowJSExecution(){
        for (var propName in window){
            if (!(propName in windowProperties)) {
                delete windowProperties[propName]
            }
        }

        for (var propName in windowProperties){
            try {
                Object.defineProperty(window, propName, windowProperties[propName])
            } catch (err) {}
        }
    }
}