他人のサイトを見て、javascriptを勉強している、弓削田です。
Googleサイトを見ていると、scriptタグに、nonceという属性がついているのがあったので、調べてみたら、
ワンタイムコードを発行してそれをscriptタグと連携することで、そのワンタイムコードが書かれていないscriptタグは実行ができないというモノでした。
このnonce属性は、セキュアなメリットもある一方で、デメリットもあるので、その注意点と、簡単なソースコード、JSaas(JavascriptのSaas)というwebサービスを数多く作ってきた経験から判断してみたいと思います。
nonce属性の搭載サンプル
scriptタグのnonceセットは、
サーバー側のapacheやnginxなどで出力するレスポンスヘッダに書き込むパターンと、
phpでhtml出力をする時のheaderに書き込むパターンと、
htmlのmetaタグに書き込むパターン
この3種類ありますが、今回は、最も導入がしやすそうなmetaタグに書き込んで試してみます。
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no">
<meta charset="utf-8">
<title>nonce</title>
<style>
</style>
</head>
<body>
<div id="a"></div>
<script>document.getElementById("a").innerHTML = "test-a";</script>
<div id="b"></div>
<script nonce="{{nonce}}">document.getElementById("b").innerHTML = "test-b";</script>
</body>
</html>
<?php
$key = random_bytes(20);
$nonce_code = base64_encode($key);
$source = file_get_contents("./index.html");
$source = str_replace("{{key}}" , $key , $source);
$source = str_replace("{{nonce}}" , $nonce_code , $source);
echo $source;
上記2つのファイルをサーバー(または、ローカルPHP環境)に配置して、index.phpを表示すると、
"test-b"
とだけ表示されているのがわかります。
本来"test-a"というスクリプトも実行されていますが、こちらはnonce属性が無いため、実行されていないのがわかります。
ブラウザコンソールのログをみてみると、
Refused to execute inline script because it violates the following Content Security Policy directive: "script-src 'nonce-SDNX3jv+evDjcYEp1nX3GX08c8k='". Either the 'unsafe-inline' keyword, a hash ('sha256-AsBDePwR00/5X4ajQrs/lRISK6Bbtqgjxu9O0OJxGJQ='), or a nonce ('nonce-...') is required to enable inline execution.
「nonceポリシーがあるので、scriptタグが実行できんかったよ!」と言っているようです。(テキトー訳)
nonce属性の設置ポイント
このポリシーを定義してしまうと、nonce属性で正常にサーバーから吐き出されるワンタイムコードが表記されなければ、実行ができないので、上記のサンプルのように、簡易に実行したいコードなども実行されなくなってしまいます。
かなりクローズドな構成のwebサイトでは有効ですが、nonce属性が付けられないscriptタグがどうしても必要な場合は、ポリシーを設定しないほうがいいでしょう。
ちなみに、Saas製品などのscriptタグを貼りたい時は、各種のタグそれぞれに、nonce属性を付けてあげると、そのscriptタグは実行できるようになりますが、そのサービスがscriptライブラリなどを読み込む処理の場合に、それらにnonce属性がついていない場合は、実行がされなくなるので、コレ、結構ひっかかるケースが多そうですね。
デメリットについて
基本的に、webサイト側での対応になるので、フィッシングサイト対応などはできないようです。
また、metaタグに書くので、ワンタイムコードが丸見えというのも指摘されそうですが、そもそも、nonce属性にコードを書いているので、伏せる必要もないし、サーバー側に記述して、修正や取り外しなどが簡易に行えなくするよりも、
metaタグをコメントアウトすると、手軽にデバッグできるようにしたほうが、サイト運用に向いていると思うんですよね。
先述しましたが、読み込み型の外部ライブラリサービスなどを使う時は、script読み込みが発生する場合は、おそらく殆どの場合が使えないし、nonce属性をつけてもらう仕様にしてもらうことは、おそらく不可能なんじゃないかと思うので、
この機能を入れて安心しないほうがいいでしょうね。
でも、xssが悩ましいのであれば、そもそも、そうした外部スクリプトを排除する意味でもnonceは有効になるのかもしれませんね。
余談
metaタグや、php-headerで"Content-Security-Policy"を出力する際に、nonce値をそのまま表記するのではなく、"nonce-"というプレフィックスを文字列の先頭につけないと、正常に動作しなかったので、この点少し時間を取られてしまいました。
あと、ワンタイムコードは、今回はbase64エンコード値を使っていますが、特に何の文字列であっても問題はないようです。
そして、今回javascriptのタグのみでやりましたが、このnonce属性は、imgタグや、css、など、HTMLのオブジェクト指向的なメディア要素や外部プログラムには、だいたい対応できるようです。
xssなどにお困りの場合のwebサイト対応にいかがでしょうか?
0 件のコメント:
コメントを投稿