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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/25929338/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-28 05:14:00  来源:igfitidea点击:

Can I ask a browser to not run <script>s within an element?

javascripthtmlscript-tag

提问by Seppo Ervi?l?

Is it possible to tell browsers to not run JavaScript from specific parts of an HTML document?

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

Like:

喜欢:

<div script="false"> ...

It could be useful as an additional security feature. All the scripts I want are loaded in a specific part of the document. There should be no scripts in other parts of the document and if there are they should not be run.

它可以用作附加的安全功能。我想要的所有脚本都加载在文档的特定部分。文档的其他部分不应有脚本,如果有,则不应运行它们。

回答by Falco

YES, you can :-) The answer is: Content Security Policy(CSP).

是的,您可以 :-) 答案是:内容安全策略(CSP)。

Most modern browsers support this flag, which tells the browser only to load JavaScript code from a trusted external file and disallow all internal JavaScript code! The only downside is, you can not use any inline JavaScript in your whole page (not only for a single <div>). Although there could be a workaround by dynamically including the div from an external file with a different security policy, but I'm not sure about that.

大多数现代浏览器都支持这个标志,它告诉浏览器只从受信任的外部文件加载 JavaScript 代码,并禁止所有内部 JavaScript 代码!唯一的缺点是,您不能在整个页面中使用任何内联 JavaScript(不仅仅是单个<div>)。虽然可以通过动态包含来自具有不同安全策略的外部文件的 div 来解决,但我不确定这一点。

But if you can change your site to load all JavaScript from external JavaScript files then you can disable inline JavaScript altogether with this header!

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

Here is a nice tutorial with example: HTML5Rocks Tutorial

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

If you can configure the server to send this HTTP-Header flag the world will be a better place!

如果您可以将服务器配置为发送此 HTTP-Header 标志,世界将变得更美好!

回答by Oriol

You can block JavaScript loaded by <script>, using beforescriptexecuteevent:

您可以<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>

Note that beforescriptexecutewas defined in HTML 5.0 but has been removed in HTML 5.1. Firefox is the only major browser that implemented it.

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

In case you are inserting an untrusted bunch of HTML in your page, be aware blocking scripts inside that element won't provide more security, because the untrusted HTML can close the sandboxed element, and thus the script will be placed outside and run.

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

And this won't block things like <img onerror="javascript:alert('foo')" src="//" />.

这不会阻止诸如<img onerror="javascript:alert('foo')" src="//" />.

回答by cowls

Interesting question, I don't think it's possible. But even if it is, it sounds like it would be a hack.

有趣的问题,我认为这是不可能的。但即使是这样,听起来也像是黑客攻击。

If the contents of that div are untrusted, then you need to escape the data on the server side before it is sent in the HTTP response and rendered in the browser.

如果该 div 的内容不受信任,那么您需要在服务器端对数据进行转义,然后再将其发送到 HTTP 响应中并在浏览器中呈现。

If you only want to remove <script>tags and allow other html tags, then just strip them out of the content and leave the rest.

如果您只想删除<script>标签并允许其他 html 标签,则只需将它们从内容中删除并保留其余部分。

Look into XSS prevention.

研究 XSS 预防。

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

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

回答by Aaron Digulla

JavaScript is executed "inline", i.e. in the order in which it appears in the DOM (if that wasn't the case, you could never be sure that some variable defined in a different script was visible when you used it for the first time).

JavaScript 是“内联”执行的,即按照它在 DOM 中出现的顺序(如果不是这种情况,您永远无法确定在不同脚本中定义的某些变量在您第一次使用时是否可见) )。

So that means in theory you could have a script at the beginning of the page (i.e. first <script>element) which looks through the DOM and removed all <script>elements and event handlers inside of your <div>.

因此,在理论上意味着你可以拥有在页面的开头的脚本(即先<script>通过DOM元素)看起来并删除所有<script>你的内部元素和事件处理<div>

But the reality is more complex: DOM and script loading happens asynchronously. This means that the browser only guarantees that a script can see the part of the DOM which is beforeit (i.e. the header so far in our example). There are no guarantees for anything beyond (this is related to document.write()). So you might see the next script tag or maybe, you don't.

但实际情况更为复杂:DOM 和脚本加载是异步发生的。这意味着浏览器只保证脚本可以看到它之前的 DOM 部分(即我们示例中的标题)。没有任何其他保证(这与 相关document.write())。因此,您可能会看到下一个脚本标记,或者可能不会。

You could latch to the onloadevent of the document - which would make sure you got the whole DOM - but at that time, malicious code could have already executed. Things get worse when other scripts manipulate the DOM, adding scripts there. So you would have to check for every change of the DOM, too.

你可以锁定onload文档的事件——这将确保你获得整个 DOM——但在那个时候,恶意代码可能已经执行了。当其他脚本操作 DOM,在那里添加脚本时,事情会变得更糟。因此,您也必须检查 DOM 的每次更改。

So @cowls solution (filtering on the server) is the only solution which can be made to work in all situations.

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

回答by Wissam El-Kik

If you're looking to display JavaScript code in your browser:

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

Using JavaScript and HTML, you'll have to use HTML entitiesto display the JavaScript code and avoiding this code to be executed. Here you can find the list of HTML entities:

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

If you're using a server-side scripting language (PHP, ASP.NET, etc.), most probably, there's a function which would escape a string and convert the special characters into HTML entities. In PHP, you would use "htmlspecialchars()" or "htmlentities()". The latter covers all the HTML characters.

如果您使用的是服务器端脚本语言(PHP、ASP.NET 等),很可能有一个函数可以对字符串进行转义并将特殊字符转换为 HTML 实体。在 PHP 中,您将使用“htmlspecialchars()”或“htmlentities()”。后者涵盖了所有 HTML 字符。

If you're looking to display your JavaScript code in a nice way, then try one of the code highlighters:

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

回答by Salman A

I've got a theory:

我有一个理论:

  • Wrap the specific part of the document inside a noscripttag.
  • Use DOM functions to discard all scripttags inside the noscripttag then unwrap its contents.
  • 将文档的特定部分包裹在noscript标签内。
  • 使用 DOM 函数丢弃script标签内的所有标签,noscript然后解开其内容。

Proof of concept example:

概念证明示例:

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]);
    }
};
body { font: medium/1.5 monospace; }
p, h1 { margin: 0; }
<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>

回答by Matt Zeunert

If you want to re-enable script tags later on, my solution was to break the browser environment so that any script that runs will throw an error fairly early. However, it's not totally reliable, so you can't use it as a security feature.

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

If you try to access global properties Chrome will throw an exception.

如果您尝试访问全局属性,Chrome 将引发异常。

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

I'm overwriting all overwritable properties on window, but you could also expand it to break other functionality.

我正在覆盖 上的所有可覆盖属性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) {}
        }
    }
}