我是否可以要求浏览器不要在元素中运行 < script > s?

有没有可能告诉浏览器不要从 HTML 文档的特定部分运行 JavaScript?

比如:

<div script="false"> ...

它可以作为额外的安全特性。我想要的所有脚本都装载在文档的特定部分中。文档的其他部分不应该有脚本,如果有的话,就不应该运行。

18475 次浏览

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

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

如果您只想删除 <script>标记并允许其他 html 标记,那么只需将它们从内容中删除,留下其他标记即可。

研究 XSS 预防。

Https://www.owasp.org/index.php/xss_%28cross_site_scripting%29_prevention_cheat_sheet

JavaScript 是“内联”执行的,也就是按照它在 DOM 中出现的顺序执行(如果不是这样,那么当你第一次使用它的时候,你永远不能确定在不同的脚本中定义的某个变量是可见的)。

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

但实际情况更为复杂: DOM 和脚本加载是异步进行的。这意味着浏览器只能保证脚本能够看到 DOM 的 之前部分(例如,到目前为止我们的示例中的头部)。除此之外没有任何保证(这与 document.write()有关)。因此,您可能会看到下一个脚本标记,也可能不会看到。

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

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

如果你想在浏览器中显示 JavaScript 代码:

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

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

如果您希望以一种漂亮的方式显示 JavaScript 代码,那么可以尝试使用代码高亮显示器:

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

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

但是,如果您可以改变您的网站,以加载所有的 JavaScript 从外部 JavaScript 文件,然后您可以禁用内联 JavaScript 完全与此标题!

下面是一个很好的教程,例如: HTML5Rocks 教程

如果你能配置服务器发送这个 HTTP-Header 标志,世界将会变得更美好!

你可以使用 beforescriptexecute事件阻止由 <script>加载的 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="//" />这样的东西。

我有个想法:

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

概念证明例子:

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>

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

如果你尝试访问全局属性,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) {}
}
}
}