HTMLドキュメントの特定の部分からJavaScriptを実行しないようにブラウザに指示することは可能ですか?
お気に入り:
<div script="false"> ...
追加のセキュリティ機能として役立つ可能性があります。必要なすべてのスクリプトは、ドキュメントの特定の部分にロードされます。ドキュメントの他の部分にスクリプトがあってはならず、スクリプトがある場合は実行しないでください。
HTMLドキュメントの特定の部分からJavaScriptを実行しないようにブラウザに指示することは可能ですか?
お気に入り:
<div script="false"> ...
追加のセキュリティ機能として役立つ可能性があります。必要なすべてのスクリプトは、ドキュメントの特定の部分にロードされます。ドキュメントの他の部分にスクリプトがあってはならず、スクリプトがある場合は実行しないでください。
script-src:"self"
、ドメインのスクリプトのみをページで実行することを許可するように指定します。興味がある場合は、CSPに関するMikeWestのこの記事を読んでください。
</div>
このDOM要素を閉じて<div>
、スクリプトが実行されていないものの兄弟となる新しい要素を開始することをどのように防止しますか?
回答:
はい、できます:-)答えは次のとおりです:コンテンツセキュリティポリシー(CSP)。
最近のほとんどのブラウザはこのフラグをサポートしています。このフラグは、信頼できる外部ファイルからJavaScriptコードをロードし、すべての内部JavaScriptコードを禁止するようにブラウザに指示します。唯一の欠点は、ページ全体でインラインJavaScriptを使用できないことです(単一のJavaScriptだけでなく<div>
)。異なるセキュリティポリシーを持つ外部ファイルからdivを動的に含めることで回避策がある可能性がありますが、それについてはよくわかりません。
ただし、外部JavaScriptファイルからすべてのJavaScriptをロードするようにサイトを変更できる場合は、このヘッダーを使用してインラインJavaScriptを完全に無効にすることができます。
これが例のある素晴らしいチュートリアルです:HTML5Rocksチュートリアル
このHTTPヘッダーフラグを送信するようにサーバーを構成できれば、世界はより良い場所になります!
イベント<script>
を使用して、によってロードされたJavaScriptをブロックできますbeforescriptexecute
。
<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
はHTML5.0で定義されていましたが、HTML5.1では削除されていることに注意してください。Firefoxはそれを実装した唯一の主要なブラウザです。
信頼できないHTMLの束をページに挿入する場合、その要素内でスクリプトをブロックしてもセキュリティが向上しないことに注意してください。信頼できないHTMLはサンドボックス化された要素を閉じる可能性があるため、スクリプトは外部に配置されて実行されます。
そして、これはのようなものをブロックしません<img onerror="javascript:alert('foo')" src="//" />
。
beforescriptexecute
イベントをサポートしていません。Firefoxで動作します。
beforescriptexecute
サポートされていないようで、ほとんどの主要なブラウザではサポートされません。 developer.mozilla.org/en-US/docs/Web/Events/beforescriptexecute
興味深い質問ですが、それは不可能だと思います。しかし、そうだとしても、それはハックのように聞こえます。
そのdivの内容が信頼できない場合は、HTTP応答で送信されてブラウザーにレンダリングされる前に、サーバー側でデータをエスケープする必要があります。
<script>
タグを削除して他のhtmlタグのみを許可する場合は、コンテンツからそれらを削除し、残りを残します。
XSS防止について調べてください。
https://www.owasp.org/index.php/XSS_%28Cross_Site_Scripting%29_Prevention_Cheat_Sheet
JavaScriptは「インライン」で実行されます。つまり、DOMに表示される順序で実行されます(そうでない場合は、別のスクリプトで定義された変数が初めて使用されたときに表示されるかどうかを確認できませんでした。 )。
つまり、理論的には、ページの先頭(つまり、最初の<script>
要素)に、DOMを調べて、<script>
内のすべての要素とイベントハンドラーを削除するスクリプトを作成できます<div>
。
しかし、現実はもっと複雑です。DOMとスクリプトのロードは非同期で行われます。これは、ブラウザーが、スクリプトがその前にあるDOMの部分(つまり、この例ではこれまでのヘッダー)を認識できることのみを保証することを意味します。それ以上の保証はありません(これはに関連していますdocument.write()
)。したがって、次のスクリプトタグが表示される場合と、表示されない場合があります。
onload
ドキュメントのイベントにラッチすることもできますが(これにより、DOM全体を確実に取得できます)、その時点で、悪意のあるコードがすでに実行されている可能性があります。他のスクリプトがDOMを操作し、そこにスクリプトを追加すると、事態はさらに悪化します。したがって、DOMのすべての変更もチェックする必要があります。
したがって、@ cowlsソリューション(サーバーでのフィルタリング)は、すべての状況で機能させることができる唯一のソリューションです。
ブラウザにJavaScriptコードを表示する場合:
JavaScriptとHTMLを使用すると、HTMLエンティティを使用してJavaScriptコードを表示し、このコードが実行されないようにする必要があります。ここに、HTMLエンティティのリストがあります。
サーバーサイドスクリプト言語(PHP、ASP.NETなど)を使用している場合は、おそらく、文字列をエスケープして特殊文字をHTMLエンティティに変換する関数があります。PHPでは、「htmlspecialchars()」または「htmlentities()」を使用します。後者はすべてのHTML文字をカバーします。
JavaScriptコードを適切に表示したい場合は、次のコードハイライターのいずれかを試してください。
私は理論を持っています:
noscript
タグで囲みます。script
て、タグ内のすべてのタグを破棄しnoscript
、その内容をアンラップします。概念実証の例:
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>
<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) {}
}
}
}