web-dev-qa-db-ja.com

要素内で<script>を実行しないようにブラウザーに要求できますか?

HTMLドキュメントの特定の部分からJavaScriptを実行しないようにブラウザに指示することは可能ですか?

のような:

<div script="false"> ...

追加のセキュリティ機能として役立ちます。必要なすべてのスクリプトは、ドキュメントの特定の部分に読み込まれます。ドキュメントの他の部分にスクリプトが存在しないようにし、存在する場合は実行しないでください。

81
Seppo Erviälä

はい、できます:-)答えは:コンテンツセキュリティポリシー(CSP)。

最新のブラウザはこのフラグをサポートしています 。これは、信頼できる外部ファイルからJavaScriptコードをロードするだけで、すべての内部JavaScriptコードを許可しないようブラウザに指示します!唯一の欠点は、ページ全体でインラインJavaScriptを使用できないことです(単一の<div>)。別のセキュリティポリシーを持つ外部ファイルからdivを動的に含めることで回避策がありますが、それについてはわかりません。

ただし、外部JavaScriptファイルからすべてのJavaScriptをロードするようにサイトを変更できる場合、このヘッダーでインラインJavaScriptを完全に無効にできます!

以下に例を示した素晴らしいチュートリアルを示します。 HTML5Rocks Tutorial

このHTTPヘッダーフラグを送信するようにサーバーを構成できる場合、世界はより良い場所になります!

90
Falco

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は、Firefoxを実装した唯一の主要なブラウザです。

信頼できないHTMLをページに挿入する場合、その要素内のブロックスクリプトはセキュリティを強化しないことに注意してください。信頼できないHTMLはサンドボックス化された要素を閉じることができるため、スクリプトは外部に配置されて実行されます。

そして、これは<img onerror="javascript:alert('foo')" src="//" />のようなものをブロックしません。

13
Oriol

興味深い質問ですが、それは可能だとは思いません。しかし、たとえそうであっても、ハックのように聞こえます。

そのdivのコンテンツが信頼できない場合、HTTP応答で送信され、ブラウザでレンダリングされる前に、サーバー側でデータをエスケープする必要があります。

<script>タグのみを削除し、他のhtmlタグを許可する場合は、コンテンツからそれらを削除して残りを残します。

XSS防止を調べてください。

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

8
cowls

JavaScriptは「インライン」で実行されます。つまり、DOMに表示される順序で実行されます(そうでない場合は、初めて使用したときに別のスクリプトで定義された変数が表示されるとは限りません。 )。

つまり、理論的には、DOMを調べ、<script>内の<script>要素とイベントハンドラーをすべて削除するスクリプトをページの先頭(つまり、最初の<div>要素)に持つことができるということです。

しかし、現実はもっと複雑です。DOMとスクリプトの読み込みは非同期に行われます。これは、ブラウザーがスクリプトがbefore it(つまり、これまでの例ではヘッダー)であるDOMの一部のみを表示できることを保証することを意味します。それ以上の保証はありません(これはdocument.write()に関連しています)。したがって、次のスクリプトタグが表示される場合もあれば、表示されない場合もあります。

ドキュメントのonloadイベントにラッチできます-これにより、DOM全体を取得できますが、その時点で、悪意のあるコードが既に実行されている可能性があります。他のスクリプトがDOMを操作し、そこにスクリプトを追加すると事態は悪化します。そのため、DOMのすべての変更も確認する必要があります。

したがって、@ cowlsソリューション(サーバーでのフィルタリング)は、すべての状況で機能する唯一のソリューションです。

7
Aaron Digulla

私は理論を持っています:

  • ドキュメントの特定の部分を noscript タグで囲みます。
  • DOM関数を使用して、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>
1
Salman A

ブラウザにJavaScriptコードを表示する場合:

JavaScriptとHTMLを使用する場合、 HTMLエンティティ を使用してJavaScriptコードを表示し、このコードの実行を回避する必要があります。ここで、HTMLエンティティのリストを見つけることができます。

サーバー側のスクリプト言語(PHP、ASP.NETなど)を使用している場合、おそらく文字列をエスケープし、特殊文字をHTMLエンティティに変換する関数があります。 PHPでは、「htmlspecialchars()」または「htmlentities()」を使用します。後者はすべてのHTML文字をカバーしています。

JavaScriptコードを適切な方法で表示する場合は、コードハイライターのいずれかを試してください。

1
Wissam El-Kik

後でスクリプトタグを再度有効にする場合、私の解決策は、実行中のスクリプトがかなり早くエラーをスローするようにブラウザー環境を壊すことでした。ただし、完全に信頼できるわけではないため、セキュリティ機能として使用することはできません。

グローバルプロパティにアクセスしようとすると、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) {}
        }
    }
}
0
Matt Zeunert