SRIによるlocalStorageコードセキュリティの強化


前回のSubresource Integraty(SRI)について紹介した記事の最後に、現在広く使われている「JSコードをローカルlocalStorageにキャッシュする」という案には大きなセキュリティ上の危険性があるという質問をしました.WebサイトにXSSが表示されると、localStorageにキャッシュされているコードを改ざんするために使用される可能性があります.その後、XSSが修復されても、localStorageのコードは改ざんされ、機能し続けます.本文は次にこの話題を討論する.
JS/CSSコードをローカルにキャッシュする用途は、このブログで繰り返していますが、ここではくどくどしません.このセキュリティ上の危険性の根源は、ほとんどのWebアプリケーションがlocalStorageからキャッシュコードを取得した後、検出メカニズムがなく、直接実行されることです.一方、localStorageはページをまたいでおり、同ドメインの下のどのページにもXSSの脆弱性があれば、攻撃者が往来localStorageで悪意のあるコードを書き込むことができる.
次のいくつかの概略コードは、問題の所在をより明確に見ることができます.
  <!--      -->
<script id="code">/*       */</script>

<script>html2ls('my_code', document.getElementById('code').innerHTML)</script>

<script>
function html2ls(ls_name, code) {
    localStorage[ls_name] = code;
}
</script>
  <!--       -->
<script>ls2html('my_code')</script>

<script>
function ls2html(ls_name) {
    var script = document.createElement('script');
    script.innerHTML = localStorage[ls_name]; //   :/*       */
    document.head.appendChild(script);
}
</script>
  <!--     XSS     -->
<img src="" onerror="localStorage['my_code']+=';alert(0);'" />
  <!--   N     -->
<script>ls2html('my_code')</script>

<script>
function ls2html(ls_name) {
    var script = document.createElement('script');
    script.innerHTML = localStorage[ls_name]; //   :/*       */;alert(0)
    document.head.appendChild(script);
}
</script>

Web loader , loader localStorage , , 。

, : , ls2html でチェックします.ただし、ブラウザで を するには、 きなJSを する があります.ls2htmlをできるだけ く できるように(localStorageからCSSを み るのもそれに するため)、このJSはページの に されなければならず、ページのパフォーマンスに きな を ぼす.また, で した アルゴリズムは, きなテキストを する にもあまり ではない.
の では、SRIポリシーを して、ブラウザが チェーンリソースの とコンテンツが するかどうかを に できることを りました. しいコードを する がなく、ブラウザに み まれたアルゴリズムもより になります.
SRIは チェーンリソースにのみ するため、localStorageから したコードを チェーン に する があります.この を するには、data URIsとBlob URLの2つのスキームがあります.
コードをdata URIs の チェーンに し、SRIを にします.

  var code = 'alert("hello world!");';

var script = document.createElement('script');
script.crossOrigin = 'anonymous';
script.integrity = 'sha256-0URT8NZXh/hI7oaypQXNjC07bwnLB52GAjvNiCaN7Gc=';
script.src = 'data:application/x-javascript,' + encodeURIComponent(code);

document.head.appendChild(script);

Blob URL SRI:

  var code = 'alert("hello world!");';

var blob = new Blob([code], {type: "application/x-javascript"});
var blobUrl = URL.createObjectURL(blob);

var script = document.createElement('script');
script.crossOrigin = 'anonymous';
script.integrity = 'sha256-0URT8NZXh/hI7oaypQXNjC07bwnLB52GAjvNiCaN7Gc=';
script.src = blobUrl;

document.head.appendChild(script);

SRI Chrome Firefox , :

Chrome 46.0.2490.33 beta Firefox 44.0a1 (2015-09-23)
data URIs( SRI)
Blob URL( SRI)
data URIs(SRI + ) CORS
Blob URL(SRI + )
data URIs(SRI + ) CORS
Blob URL(SRI + ) Integrity

  1. SRI , ;
  2. Firefox , SRI ,data URIs Blob URL ;
  3. Chrome , SRI ,data URIs CORS ;
  4. Chrome , SRI ,Blob URL integrity ;

  5. の は が んでいることがわかります. のコードを し、2 のアクセス に を し、 メカニズムを します.
      <!--       -->
    <script>ls2html('my_code', 'sha256-xxxx')</script>
    
    <script>
    function ls2html(ls_name, integrity) {
        var script = document.createElement('script');
        var code = localStorage[ls_name];
    
        if (-1 == (navigator.userAgent || '').toLowerCase().indexOf('firefox') && window.URL && window.Blob) {
            var blob = new Blob([code], {type: "application/x-javascript"});
            var blobUrl = URL.createObjectURL(blob);
    
            script.crossOrigin = 'anonymous';
            script.integrity = integrity;
            script.src = blogUrl;
    
            script.onerror = function() { alert('localStorage      !') };
        } else {
            script.innerHTML = code;
        }
    
        document.head.appendChild(script);
    }
    </script>
    

    , 。 CSP , script-src blob: . のブログでは、このlocalStorageコードのセキュリティ を しています.ブラウザ・コンソールを き、 のコードを してページをリフレッシュします.

      localStorage.all_js += ';alert(0);'
    

    Chrome 45+, alert(0) 。 localStorage , 。

    Chrome Firefox , [email protected] 。 Chrome 。

    NodeJS , SRI integrity , cryptoモジュールでいいです.

      var crypto = require('crypto');
    
    function getIntegrity(content, algorithm) {
        algorithm = algorithm || 'sha256';
    
        var result = algorithm + '-' + crypto
                .createHash(algorithm)
                .update(content)
                .digest("base64");
    
        return result;
    }
    

    , Content Security Policy Level 2(CSP2) , , , 。 。

    : https://imququ.com/post/enhance-security-for-ls-code.html,