Content Security Policyと
Webサービスのセキュリティ対策

Yu Watanabe(@yuw27b)
2016.09.10 NDS 第49回勉強会

自己紹介

ECサイト運営
[東京]
非常勤エンジニア+フリーランス
[新潟]


最近のお仕事

SPA+API+DBなWebサービスの制作
  • データからグラフを描画するサービス
  • データやファイルを送ってもらってデータベースを作るサービス
技術面
  • JavaScript[Backbone.js/React.js/Node.js]
  • Ruby、PHP
  • MySQL、Neo4j、RDF

サービスのサーバ設定・管理

HTML+CSS+JavaScriptのコーディング

・・・などをやっています。

今日のテーマ

Webサービスのセキュリティ対策


  • JavaScriptでHTMLを吐き出したり、フォームデータを扱ったり
  • Cookieを使う
  • サーバとAjaxでやりとり

というようなWebサービスのセキュリティについて、実際にやったことをお話します。

また、Content Security Policyの仕様について気になっていた点を整理しました。

サーバでやったこと


クリックジャッキング対策


HTTPヘッダにX-Frame-Options:SAMEORIGINを追加

外部のサイトから、自サイトのコンテンツをiframeで読み込みことができなくなります。
参考:https://developer.mozilla.org/ja/docs/Web/HTTP/X-Frame-Options

現在この仕様を策定しているのはIETFでRFC7034として公開されています。
Content security policyとの併用が好ましいとされており、さらに将来的にはCSPに内包される予定のようです。

Cookie関連でやったこと


  • "Secure"を指定してSSL環境でのみCookieを発行する
  • "httponly"を指定してJavaScriptからのCookieの読み取りを許可しない

Content Security Policy [CSP]


JavaScript、CSS、画像、フォント、XHRなど(*)のコンテンツの外部からの読み込みを制御することができます。

例:
default-src 'self';
script-src 'self' 'unsafe-eval';
style-src 'self' 'unsafe-inline';
font-src 'self' https://fonts.gstatic.com;
img-src 'self' https://i.creativecommons.org https://licensebuttons.net;

  • デフォルトでは外部からは何も読み込みません・インラインでの実行もできません
  • JavaScriptのevalの使用を許可します
  • CSSは外部からは読み込みません・HTML内のstyleの記述は許可します
  • フォントは外部から読み込みません・「https://fonts.gstatic.com」からの読み込みは例外として許可します(ホワイトリスト)
  • 画像は外部から読み込みません・列記したドメインからの読み込みは例外として許可します

*オーディオやビデオなども含まれます。

設定すると、HTTPヘッダーに以下のように追加されます:

Internet Explorer(10, 11)は、CSPに対応していないので、代わりにX-Content-Security-Policyを使用します。
仕様にはほぼ互換性があるので、同じ指定を2回書くことになります。

仕様


CSPはW3Cで仕様策定が行われています。

推奨設定


default-src 'self';

「unsafe-eval」、「unsafe-inline」はどちらも、XSSの可能性があるので注意、となっています。

現実

  • HTML内にちょっとしたCSSを書き出すJSライブラリはたくさんある
  • JSテンプレートエンジンには「eval」を使用したものが多い(Handlebarsあたりは大丈夫みたいです)
  • Google AnalyticsのJSコードを</body>直前に貼りつけたら「unsafe-inline」にひっかかる・・・
    「analytics.js」のようなファイルに保存して「<script></script>」で読み込めばOKです。ちょっと面倒ですが・・・
  • CDNからライブラリを読み込むごとに、ホワイトリストに追加

結果として、けっこう長いコードができあがり、果たしてこれで安全なのかと不安になります。

CSPは長い!


本当にこれで安全?


Googleのエンジニアチームが2016年に発表した論文より:

  • Googleの検索用インデックスに登録されている約1000億サイトから、1,680,867のホストに指定されていた26,011種類のCSP policyを分析
  • その結果、94.68%のポリシーはスクリプトの実行阻止に効果がなく、99.34%のホストでXSSの危険はなくなっていなかった。
  • ホワイトリストに危険なドメインが含まれているケースもあり、75.81%のポリシーでホワイトリスト経由の攻撃が可能だった。

簡潔にまとめるとCSP Lv2からのnonce・hashとCSP Lv3からの「strict-dynamic」の指定が有効

結局どうすれば・・・?


※個人的見解です

  • 「完璧な設定」はおそらく存在しません。新しい攻撃手法も出てくるかもしれません。
    仕様もどんどん追加されている状態なので、Level 1では不十分なのは明白なのでしょう。
  • とはいえ、「script-src 'self';」だけでも、「うっかりエスケープ忘れた!」くらいは防げます。
  • 基本的にはJavaScriptのインライン実行とevalは回避、外部リソースはURLをホワイトリストに入れるのがいいと思います!
    現実と折り合いをつけるのはちょっと大変ですが・・・
  • 何もやらないよりは少しでもやったほうがいい!
  • 現在不十分なところはまだまだ仕様策定中なので、将来の仕様やブラウザの対応状況のチェックは必要。 (これが面倒なのは承知なので、こんな資料を作った手前、ブログに書くくらいはしたいと思っています。)
  • CSPだけでなく、基本的なパーミッション設定やHTTPSなども確実に!

END