Webアプリ開発者のためのHTML5セキュリティ入門

35,318 views

Published on

Enterprise x HTML5 Web Application Conference 2014の発表資料です。

Published in: Technology
0 Comments
155 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
35,318
On SlideShare
0
From Embeds
0
Number of Embeds
3,464
Actions
Shares
0
Downloads
293
Comments
0
Likes
155
Embeds 0
No embeds

No notes for slide

Webアプリ開発者のためのHTML5セキュリティ入門

  1. 1. Webアプリ開発者のための HTML5 セキュリティ入門 Enterprise x HTML5 Web Application Conference 2014 2014年2月28日@明星大学
  2. 2. 西村 宗晃 a.k.a. nishimunea html5j Webプラットフォーム部 部員 FxOS コードリーディング 部員 Gecko勉強会 主催 1
  3. 3. html5j Webプラットフォーム部 • HTMLやJavaScriptでアプリを開発できるOSが増えてきている • Webの広まりは急速で新しい技術が続々と誕生している WebやOS固有の技術をみんなで共有して 色んな端末向けのアプリをサックリ公開できたらいいよね! 第一回目の勉強会を近日開催予定です 2
  4. 4. 本日お話する内容 サーバと非同期で通信する際の注意点 データを保存する際の注意点 Content Security Policyの適用方法 3
  5. 5. 従来のウェブサイト • ページ遷移の都度、UIを含む全てのデータをサーバから同期的に受信 • サーバとの通信時間が利用者の体感速度に影響 サーバ クライアント ページを要求 (同期型) ページを生成 ページを要求 (同期型) ページを生成 4
  6. 6. 現在のウェブサイト • UIなどのデータをクライアントに保存し、ローカルでページを生成 • 必要なデータのみをサーバに非同期で要求し、通信のボトルネックを軽減 サーバ クライアント ページを要求 (同期型) データを保存 必要なデータのみを要求 (非同期型) ページを生成 5
  7. 7. サーバと非同期で通信する際の注意点 6
  8. 8. XMLHttpRequest Level 2 10+ 7 4+ 4+ 5+
  9. 9. 次のようなサイトを例に説明します • UIなどの静的リソースはWebサーバ(example.jp)から取得 • その他のデータはAPサーバ(api.example.jp)から非同期で取得 Webサーバ ページを要求 example.jp 8 APサーバ http://example.jp/ データを要求(非同期) api.example.jp
  10. 10. 従来のAjaxの制限 • 従来のAjax(XMLHttpRequest)は異なるオリジンと通信できなかった • ページの生成元(http://example.jp)以外にはリクエストを送れなかった Webサーバ ページを要求 APサーバ http://example.jp/ データを要求(非同期) 通信不可 example.jp 9 api.example.jp ※オリジンとはあるページやリクエスト、データの生成元(または供給元)のことで、 スキーム名+ホスト名+ポート番号の組み合わせで表される。
  11. 11. このためJSONPが使われるようになった • JSONのデータをスクリプトファイルとしてロード • <script>のsrc属性にはクロスオリジンの制限が適用されない点を利用 Webサーバ ページを要求 example.jp 10 http://example.jp/ <script src> APサーバ データをスクリプトファイルとしてロード api.example.jp
  12. 12. しかしJSONPは脆弱性を作りこみやすかった • オリジンの制限が無いのでどのサイトからでもデータを取得できる • しかもJSONPのリクエストには自動的にCookie(セッション情報)が付く 罠サイト APサーバ http://wana.jp/ JSONPをロード (リクエストにCookieが付く) ワナ 罠サイトを開く 認証済みの利用者のデータが 盗まれてしまう wana.jp 11 api.example.jp ※JSONPの注意点は他にもあります。詳しくは以下のページをご覧ください http://a.atmarkit.co.jp/ait/articles/0908/10/news087.html
  13. 13. そこでCORSという仕組みが作られた • CORS:安全にクロスオリジン通信をするための仕組み • AjaxもXMLHttpRequest Level 2(XHR2)としてCORSに対応 Webサーバ ページを要求 Origin: http://example.jp APサーバ http://example.jp/ (このリクエストはexample.jpのページから発行されました) データをリクエスト Access-Control-Allow-Origin: http://example.jp example.jp 12 (example.jpからのリクエストのみを許可します) api.example.jp ※CORSはCross Origin Resource Sharingの略
  14. 14. CORSによってCookieの送信も制限される • クライアントとサーバの両方で明示的にCookieの送信許可を行う • 送信を許可しないとXHR2のリクエストにCookieは付かない Webサーバ ページを要求 XMLHttpRequest.withCredential=trueAPサーバ http://example.jp/ (このリクエストにCookieを付けることを許可します) データをリクエスト Access-Control-Allow-Credentials: true example.jp 13 (Cookie付きのリクエストを許可します) api.example.jp ※CORSには上記以外にも様々な仕様があります。詳しくは以下のページをご覧ください https://developer.mozilla.org/ja/docs/HTTP_access_control
  15. 15. 不正なサイトからのリクエストを拒否するには Originヘッダでは不正なサイトからのリクエストを判別できない • 同一オリジンのXHRにはOriginヘッダが付かない • FORMからの送信やURL直接指定によるリクエストとの区別もできない XHRであることを示すカスタムヘッダをリクエストに付加する (カスタムヘッダを用いて正規のXHRであることを判別する) 14
  16. 16. カスタムヘッダには推測できない値を指定する • XHR以外のリクエストにカスタムヘッダを付ける方法がある - 参考:mala’s Gists/https://gist.github.com/mala/8857629 • 攻撃者が推測できない値をカスタムヘッダに指定して対処 - 例:セッション固有トークンを使用する X-CSRF-Token: C90rqt588bq5uivdm1qs… 15 攻撃者が推測できない値を設定する
  17. 17. セッション固有トークン • セッションID毎に異なるトークン(乱数)をXHRのリクエストヘッダに付加 • 攻撃者はトークンを推測できないので正規のリクエストを真似できない サーバ APサーバ Web Storageに トークンを保存 事前にトークンを送信 カスタムヘッダにトークンを 付けてXHRを送信 X-CSRF-Token: C90rqt58… Cookie: SESSION=M5k492c3… 16 SESSION トークン M5k492c3… C90rqt58… Ju1gkhv7… Sthf2o5s… SESSIONとトークンがマッチ する場合のみXHRを受け入れる ※Web Storageにトークンを保存する際はこの後で紹介する注意点をあわせてご一読ください
  18. 18. XHR2の使用例 XHR2を送信するJavaScript XHRのリクエストを判別する ためのカスタムヘッダを付ける xhr.open("GET", "http://api.example.jp/xhr/"); var xhr = new XMLHttpRequest(); xhr2.setRequestHeader("X-CSRF-Token", "C90rqt58…"); xhr2.withCredentials = "true"; // only when using Cookie xhr.send(); Cookieを送信することを指定 HTTPリクエストヘッダ (XHR2送信時) GET http://api.example.jp/xhr HTTP/1.1 X-CSRF-Token: C90rqt58… Origin: http://example.jp Cookie: SESSION=M5k492c3… 17 リクエストにOriginヘッダが付加される
  19. 19. XHR2の使用例 HTTPレスポンスヘッダ (api.example.jpが返却) HTTP/1.1 200 OK Access-Control-Allow-Origin: http://example.jp Access-Control-Allow-Credentials: true リクエストを許可する オリジンを指定する リクエストにCookieを付けることを許可する 18
  20. 20. XHR2を受信する際の注意点(サーバ側) カスタムヘッダの値が有効か? NO YES 拒否 (XHR以外) Originヘッダが付いているか? NO YES 許可(同一オリジン) アクセスを許可しているOriginか? YES 19 許可(正規オリジン) NO 拒否(不正オリジン) • カスタムヘッダの値を確認する(必須) - 値が有効でない場合はXHR以外のリクエストと 見なしてリクエストを拒否
  21. 21. XHR2を受信する際の注意点(サーバ側) カスタムヘッダの値が有効か? NO YES • カスタムヘッダの値を確認する(必須) - 値が有効でない場合はXHR以外のリクエストと 見なしてリクエストを拒否 拒否 (XHR以外) • Originヘッダの有無を確認する(推奨) Originヘッダが付いているか? NO YES 許可(同一オリジン) アクセスを許可しているOriginか? YES 20 許可(正規オリジン) NO 拒否(不正オリジン) - 無い場合は同一オリジンからのXHRと見なして リクエストを許可
  22. 22. XHR2を受信する際の注意点(サーバ側) カスタムヘッダの値が有効か? NO YES • カスタムヘッダの値を確認する(必須) - 値が有効でない場合はXHR以外のリクエストと 見なしてリクエストを拒否 拒否 (XHR以外) • Originヘッダの有無を確認する(推奨) Originヘッダが付いているか? NO YES 許可(同一オリジン) アクセスを許可しているOriginか? YES 21 許可(正規オリジン) NO 拒否(不正オリジン) - 無い場合は同一オリジンからのXHRと見なして リクエストを許可 • Originヘッダの値を確認する(推奨) - 許可しないオリジンであればリクエストを拒否 - Access-Control-Allow-Originヘッダには リクエスト元のオリジンのみを指定する → 許可するオリジンを列挙しない
  23. 23. The WebSocket API 10+ 22 16+ 11+ 6+
  24. 24. WebSocket • XHR2より低通信コスト&サーバPush可能であるため注目を集めている • ws:とwss:というスキームを使用(wss:はhttps:に相当) Webサーバ ページを要求 example.jp 23 APサーバ http://example.jp/ ws://api.example.jpに接続 api.example.jp
  25. 25. WebSocketの使用例 http://example.jp/index.html (WebSocketを接続) var ws = new WebSocket("ws://api.example.jp"); WebSocketの接続を確立 ws.send("msg"); HTTPリクエストヘッダ (WebSocket接続時) GET http://api.example.jp/ HTTP/1.1 Upgrade: websocket Connection: Upgrade Host: api.example.jp リクエストにはOriginヘッダが付く Sec-WebSocket-Key: tJiswgrSqUJu7h5X1W1PKg== Origin: http://example.jp 24
  26. 26. WebSocketにはオリジンの制限が無い • どのサイトからでもWebSocketの接続ができる • しかも接続時には自動的にCookie(セッション情報)が付く 罠サイト APサーバ http://wana.jp/ ws://api.example.jpに接続 (リクエストにCookieが付く) ワナ 罠サイトを開く 認証済みのWebSocketを使って 罠サイトとサーバが自由に通信できる wana.jp 25 api.example.jp
  27. 27. WebSocket使用時の注意点 • サーバは接続時にOriginヘッダを検証する - 意図しないオリジンからの接続を拒否するため - Originヘッダの検証時はホスト名を完全一致で比較する • クライアントから送られたデータは必ずサーバ側で検証する - ブラウザ以外のクライアントによるOriginの偽装や正規オリジンのXSS脆弱性により サーバに不正なデータが送られる可能性があるため • wss:の使用を検討する - ws:の通信は暗号化されないので情報が第三者に漏えいする可能性がある 26
  28. 28. サーバでOriginヘッダを検証する際の注意点 • ホスト名は完全一致で比較する - 脆弱な例: Originに期待するホスト名が含まれていることを確認 if(strpos($_SERVER['HTTP_ORIGIN'], 'example.jp')!== false){ do_process(); example.jp.waru.jpからのリクエストを許可してしまう - 安全な例: Originヘッダの値と期待するホスト名を完全一致で比較 $url = parse_url($_SERVER['HTTP_ORIGIN']); if ($url['host'] === 'example.jp'){ do_process(); 27
  29. 29. JavaScript Object Notation (JSON) 8+ 28 4+ 3.5+ 4+
  30. 30. JSONに起因する脆弱性 • JSONがブラウザにHTMLとして解釈されることによる脆弱性 - HTMLタグをデータに含んだJSONがHTMLとして解釈される {"key":"<script>alert(1)</script>"} スクリプトが実行される可能性がある • JSONがIEにvbscriptとして実行されることによる脆弱性 - 実行時に呼ばれるエラーハンドラを通じて外部にデータを盗み出す方法がある - 参考:葉っぱ日記/http://d.hatena.ne.jp/hasegawayosuke/20130517/ • JSONに含まれるデータの取り扱いミスによる脆弱性 - evalでJSONをスクリプトとして解釈することによる不正コード実行 - JSONのデータをHTMLに出力することによるXSS 29
  31. 31. JSONを出力する際の注意点(サーバ側) • Content-Typeレスポンスヘッダを適切に設定する - MIME種別と文字コードの両方を正しく指定する Content-Type: application/json; charset=utf-8 - HTMLタグを含んだJSONがHTMLとして開かれることを防ぐため • ブラウザによるMIME種別の自動判別を無効化する - レスポンスヘッダにX-Content-Type-Options: nosniffを指定する - IEがContent-Typeを無視してJSONをHTMLやvbscriptとして開くことを防ぐため http://api.example.jp/json.php/index.html PATH_INFOに含まれる.htmlを IEが誤解釈してHTMLとして開く 30
  32. 32. JSONを処理する際の注意点(クライアント側) • JSONの解析にevalを使用しない - JSON.parseを使用する - JSONに含まれる不正なスクリプトを実行してしまう恐れがあるため {"token":""+alert(1)+""} 31
  33. 33. JSONを処理する際の注意点(クライアント側) • JSONの値をそのままHTMLとして出力しない - テキストノードとして出力する document.getElementById('foo').textContent = json.data; - HTMLタグのエスケープは不具合を生みやすいので極力使用を避ける → クライアントとサーバのどちらでエスケープするかが明確である場合のみ使用すべき → 例えば既にエスケープされているデータをクライアントで二重エスケープしてしまう Puzzle &amp; Dragons Puzzle &amp;amp; Dragons 画面表示「Puzzle &amp; Dragons」 32
  34. 34. JSONを処理する際の注意点(クライアント側) • JSONに含まれる値をそのままHTMLとして出力しない - やむ無くHTMLとして出力する場合はHTMLエンティティエスケープを行う function escape_html( s ){ return s.replace( /&/g, "&amp;" ) .replace( /</g, "&lt;" ) .replace( />/g, "&gt; " ) .replace( /"/g, "&quot;" ) HTMLの構文として意味を持つ & < > “ ‘ をエスケープする .replace( /'/g, "'" ); } document.writeln( escape_html(json.data) ); ※HTML5ではシングルクォート(‘)の文字参照に&apos;が割り当てられているが、IE8が解釈しないので'を使用する 33
  35. 35. JSONを処理する際の注意点(クライアント側) • 信頼できない値をイベントハンドラ属性に出力しない - 不正なスクリプトを実行する可能性がある document.writeln('<a href=# onclick="'+json.func+'">Send</a>'); - 不正なコードかどうかを検証することも難しい 34
  36. 36. JSONを処理する際の注意点(クライアント側) • URLとして使用する際はhttp:とhttps:スキーム以外を許可しない - JSONに含まれるURLがhttp://またはhttps://で始まることを確認する if( json.url.match( /^https?:¥/¥// ) ){ location.href = json.url; } 参考:「HTML5 を利用したWeb アプリケーションのセキュリティ問題に関する調査報告書」JPCERT 著 - URLの検証コードをブラックリスト方式で実装しない if( json.url.match( /^javascript:/ ) ){ return; } 35 Java script:alert(1); を許可してしまう ※他にもjAvAsCrIpT:など様々な回避方法がある ※JSONに含まれるURLへリダイレクトする際はオープンリダイレクトの脆弱性にも注意してください(詳細は下記) http://utf-8.jp/public /20131114/owasp.pptx
  37. 37. データを保存する際の注意点 36
  38. 38. Web Storage 8+ 37 4+ 3.5+ 4+
  39. 39. クライアントにデータを保存する技術が発達 • • • • • Offline Web Application File API: Writer Indexed Database API Web Storage Cookie これまでサーバ側やCookieに保存していたデータを Web Storageに保存する際に注意すべき点は? 38
  40. 40. Web StorageとCookieの比較 Web Storage Cookie オリジン単位 (scheme+host+port) domainとpath単位 +secure属性 禁止できない 禁止できる (httponly属性) サーバへの送信 明示的に送信しない限り 送られない HTTPリクエストの都度 自動的に送信される データの有効期限 無期限(LocalStorage)・ ウィンドウが閉じるまで (SessionStorage) 任意の期限をサーバから指定 アクセス制御の単位 JSからのアクセス 39
  41. 41. アクセス制御の単位について説明します Web Storage Cookie オリジン単位 (scheme+host+port) domainとpath単位 +secure属性 禁止できない 禁止できる (httponly属性) サーバへの送信 明示的に送信しない限り 送られない HTTPリクエストの都度 自動的に送信される データの有効期限 無期限(LocalStorage)・ ウィンドウが閉じるまで (SessionStorage) 任意の期限をサーバから指定 アクセス制御の単位 JSからのアクセス 40
  42. 42. アクセス制御の単位(Web Storage) • 同一生成元ポリシーに基づくアクセス制御 example.jp - scheme + host + port の組み合わせが同じ ホストからのみアクセスが許可される アクセス可能 http://a.example.jp - IEはscheme+hostでアクセス制御する(portを見ない) - IE8は同じhost内でデータを共有する(schemeも見ない) • http://a.example.jpのデータに対して 次のホストはアクセスできない https://a.example.jp - http://a.example.jp:8080 - https://a.example.jp - http://example.jp http://b.example.jp 41 ※この他にSessionStorageのデータは他のウィンドウと共有されないという特徴もあります(詳細は下記) https://developer.mozilla.org/ja/docs/DOM/Storage
  43. 43. アクセス制御の単位(Cookie) example.jp • a.example.jpは次のdomainに対する Cookieを発行できる - a.example.jp (デフォルト) - example.jp http://a.example.jp https://a.example.jp http://b.example.jp 42
  44. 44. アクセス制御の単位(Cookie) • a.example.jpは次のdomainに対する Cookieを発行できる example.jp アクセス可能 http://a.example.jp https://a.example.jp http://b.example.jp 43 - a.example.jp (デフォルト) - example.jp • Cookieはhttp:とhttps:で共有される
  45. 45. アクセス制御の単位(Cookie) • a.example.jpは次のdomainに対する Cookieを発行できる example.jp - a.example.jp (デフォルト) - example.jp http://a.example.jp アクセス可能 https://a.example.jp http://b.example.jp 44 • Cookieはhttp:とhttps:で共有される • Cookieにsecure属性を指定した場合、 https通信時のみサーバへ送信される - https://a.example.jp のみで利用できる
  46. 46. アクセス制御の単位(Cookie) example.jp アクセス可能 • a.example.jpは次のdomainに対する Cookieを発行できる - a.example.jp (デフォルト) - example.jp http://a.example.jp https://a.example.jp http://b.example.jp • Cookieはhttp:とhttps:で共有される • Cookieにsecure属性を指定した場合、 https通信時のみサーバへ送信される - https://a.example.jp のみで利用できる • example.jpのCookieはexample.jp 内の全てのサブドメインから利用できる - b.example.jpからもアクセスできる 45
  47. 47. Web Storageを使用する際の注意点 • 永続性の必要ないデータはSessionStorageに保存する - データの消し忘れによるリスクを軽減できる • LocalStorageのデータの消し忘れに注意する - 例えば利用者がサーバからログアウトした際は忘れずにデータを削除する • サーバとのセッション情報はCookieに保存する - CookieはJSからのアクセス禁止やサーバからの強制削除が可能であるため • XSS脆弱性の対策をしっかりやる - XSSによって攻撃者に全てのデータを盗まれる可能性があるため - CSP(後述)の適用によりXSSのリスクを軽減する 46
  48. 48. Cookieを使用する際の注意点 • domainを指定しない - 同じドメイン内の他のサイトを通じてデータが漏えいする可能性があるため • secure属性の使用を検討する - 特にhttpsのみで提供しているサイトはsecure属性の適用を必須とする • セッション情報を含むCookieにはhttponly属性を付ける - XSSでセッション情報が盗まれるリスクを軽減できるため • 有効期限はなるべく短めに設定する - サービスの利便性とビジネスリスクのバランスを考慮した上で決める - 利用者がログアウトした際はサーバから強制削除する 47
  49. 49. ついでにデータの保存に関する注意点 • 必要の無いデータは保存しない - クレジットカードのセキュリティコード - 利用者のパスワード → ID連携の利用、HASHをかけてサーバに保存 • ビジネスリスクのあるデータはサーバ側で管理し、 クライアントには送信しない - 利用者のクレジットカード番号 → 下4桁の開示も極力避ける - 利用者の権限や資格に関する情報(購入済みフラグ、管理者フラグ) - クライアント側のデータには暗号化などの保護が行われないためデータの漏えいや 改ざんのリスクがあることを意識する 48
  50. 50. Content Security Policyの適用方法 49
  51. 51. Content Security Policy 10+ 50 14+ 4+ 6+
  52. 52. ブラウザのセキュリティモデル • 最近のブラウザは一般的な攻撃に対する様々な保護機能を備えている • HTTPレスポンスヘッダを通じてWebサーバからそれらの機能を制御できる Webサーバ HTTPリクエスト HTTPレスポンス HTTPレスポンスヘッダで ブラウザの防御機能を制御 51 • • • • • XSSフィルタ フレーム内でのページ表示制限 HTTPSの強制使用(HSTS) 公開鍵ピンニング(HPKP) Content-Security-Policy
  53. 53. セキュリティ関連のHTTPレスポンスヘッダ ヘッダ名 X-XSS-Protection ブラウザの反射型XSS防止機能を有効/無効化する X-Frame-Options ブラウザにフレーム内でのページ表示可否を指定する Strict-Transport-Security ブラウザにHTTPSの使用を強制する Public-Key-Pins 指定したSSL証明書以外によるHTTPS通信を遮断する Content-Security-Policy 一般的な攻撃に対するブラウザの保護機能を有効化する Content-Disposition ブラウザに送信したコンテンツの取り扱い方法を指示する X-Content-Type-Options ブラウザによるコンテント種別の自動判別を無効化する X-Download-Options 52 用途 IEのダウンロードダイアログの「開く」や「保存」を無効化
  54. 54. 今日はContent-Security-Policyを紹介します ヘッダ名 X-XSS-Protection ブラウザの反射型XSS防止機能を有効/無効化する X-Frame-Options ブラウザにフレーム内でのページ表示可否を指定する Strict-Transport-Security ブラウザにHTTPSの使用を強制する Public-Key-Pins 指定したSSL証明書以外によるHTTPS通信を遮断する Content-Security-Policy 一般的な攻撃に対するブラウザの保護機能を有効化する Content-Disposition ブラウザに送信したコンテンツの取り扱い方法を指示する X-Content-Type-Options ブラウザによるコンテント種別の自動判別を無効化する X-Download-Options 53 用途 IEのダウンロードダイアログの「開く」や「保存」を無効化
  55. 55. Content-Security-Policy(CSP)とは • 一般的な攻撃の被害を軽減するために作られた保護機能 - 現行(CSP1.0)はXSSの軽減を目的とする - 次版(CSP1.1)ではクリックジャッキングなども対象となる予定 • HTTPレスポンスヘッダにセキュリティポリシーを定義 - 通信を許可するオリジンなどをポリシーとしてヘッダに記載する - 2種類のHTTPレスポンスヘッダが使用できる - Content-Security-Policy - ポリシーに違反する処理を無効化 - Content-Security-Policy-Report-Only - 無効化はせず、サイトの管理者に違反レポートのみを送信 54
  56. 56. CSPヘッダの名前はブラウザごとに異なる • 将来的にはContent-Security-Policyに統一される見込み • 現時点では以下の3種類を全て付けておくのが無難 ヘッダ名 IE Content-Security-Policy Content-Security-Policy-Report-Only X-Content-Security-Policy X-Content-Security-Policy-Report-Only X-WebKit-CSP X-WebKit-CSP-Report-Only 55 Chrome Firefox 25+ 10+ 23+ Safari 7+ 4+ 14+ 6
  57. 57. ポリシーの定義に使用するディレクティブ ディレクティブ名 default-src 明示的な指定の無い全コンテンツ script-src スクリプトファイル <script>, Worker, SharedWorker, XSLT object-src プラグイン <object>, <embed>, <applet> style-src スタイルシート img-src 画像ファイル media-src メディアファイル <video>, <audio>, <source>, <track> frame-src フレームコンテンツ <iframe>, <frame> font-src Webフォント cssの@font-face connect-src 56 ポリシーの適用対象 影響を受ける要素の例 サーバとの非同期通信 WebSocket, EventSource, XMLHttpRequest.open <link rel="stylesheet">, document.styleSheets, cssの@import <img>, <link rel="shortcut icon">, cssのurl()や image()
  58. 58. ポリシーの書き方 • まずはdefault-srcに'none'を指定 - 初期値は '*' で、全ての通信元を許可するため default-src 'none'; • コンテンツの種別ごとにアクセスを許可するオリジンを記載 - 例:自身のサイトのJavaScriptの使用+jQueryをCDNで利用する場合 default-src 'none'; script-src 'self' http://code.jquery.com; 57
  59. 59. CSPによるインラインスクリプトの実行制限 • default-srcやscript-srcを指定すると、HTMLファイル内の インラインスクリプトの実行が禁止される - scriptタグ内のスクリプト記述 <div><script>document.writeln("hello");</script></div> 実行できない - javascript: URLによるスクリプト記述 <a href="javascript:show_popup();">Click Here</a> 実行できない - HTMLタグのイベントハンドラ属性 <input id="email" onclick="show_popup('hello')"> 58 実行できない
  60. 60. CSPによるインラインスクリプトの実行制限 • HTMLとJSファイルを分離するための改修が必要となる - scriptタグ内のスクリプト記述 <div><script src="hello.js"></script></div> HTMLとJSのファイルを分離 - HTMLタグのイベントハンドラ属性 <input id="email" data-arg="hello"> JSに渡す引数をdata属性で指定 var email = document.getElementById('email'); email.onclick = function(){ show_popup(email.getAttribute("data-arg")); } 59 JSファイル内でイベントハンドラを設定
  61. 61. CSPによるインラインスクリプトの実行制限 • script-srcにunsafe-inlineを指定することにより、インライン スクリプトの実行制限を外すことができる - HTMLとJSの分離には時間を要するため、unsafe-inlineを指定した状態でCSPをデプロイし、 それから分離作業を進める 60
  62. 62. CSPによるevalの実行制限 • default-srcやscript-srcを指定すると、evalに代表される 文字列→JSコードへの変換を伴う関数の実行が禁止される - eval関数 eval("2 + 2"); 実行できない - Functionコンストラクタ var multiply = new Function("x", "y", "return x * y"); 実行できない - setIntervalやsetTimeout (第一引数に文字列を指定した場合) setInterval("alert('hello')", 1000); 61 実行できない
  63. 63. CSPによるevalの実行制限 • script-srcにunsafe-evalを指定することにより、文字列から コードを生成する関数の使用制限を外すことができる - unsafe-inlineと同様に、unsafe-evalを指定してCSPをデプロイした後、 計画を立てて順にevalの廃止を進める - 主要なJavaScript MVCフレームワークの多くもunsafe-evalの指定が必須 62
  64. 64. ポリシー違反のレポートについて • CSPヘッダにreport-uriを指定 - report-uriに違反レポートを受信するURL(同一オリジン)を指定する report-uri http://example.jp/report.php; - csp-reportというJSON形式のレポートがPOSTで送信される • 違反レポートの誤検知をフィルターする必要がある - 表示中のページにJavaScriptやCSSを挿入するブラウザ拡張があるため → 例えばFirefoxアドオンのFirebugを使用すると大量の違反レポートが送られる - レポートの傾向から誤検知を取り除く仕組みを構築すべき 63
  65. 65. CSPを使用する際の注意点 • Content-Security-Policy-Report-Onlyで運用開始する - 稼働しているシステムに影響を与えないようにする • default-src 'none' を指定するところからスタート - それからコンテンツ種別ごとに許可するオリジンを指定する - 初めのうちはunsafe-inlineとunsafe-evalを許容しても良い • 違反レポートの誤検知をフィルタリングする仕組みを用意する - 誤検知を取り除き、攻撃の兆候を見逃さないようにする 64
  66. 66. まとめ 65
  67. 67. 本日ご紹介した注意点 XMLHttpRequest Level 2 • カスタムヘッダにユニークな値が含まれていることを確認する • Originヘッダの有無、ある場合は許可するオリジンであることを確認する • Access-Control-Allow-Originに許可する全てのオリジンを列挙しない WebSocket • 接続時にOriginヘッダの値を完全一致で確認する • クライアントから送られたデータは必ずサーバ側で検証する • wss:の使用を検討する 66
  68. 68. 本日ご紹介した注意点 JSON • Content-Typeを正しく指定する • X-Content-Type-Options: nosniffを指定する • evalではなくJSON.Parseで解析する • HTMLに値を出力する際はテキストノードとして出力する • http:とhttps:以外のURLを許可しない 67
  69. 69. 本日ご紹介した注意点 Web Storage • 永続性が必要無いならSessionStorageを使用する • LocalStorageのデータの消し忘れに注意する • セッション情報はWeb StorageではなくCookieに保存する • XSS脆弱性の対策をしっかりやる Cookie • domainを指定しない • httponly属性とsecure属性を付ける • 有効期限はなるべく短くする 68
  70. 70. 本日ご紹介した注意点 データの保存全般 • 必要の無いデータを保存しない • ビジネスリスクのあるデータはサーバに保存し、クライアントに出力しない Content-Security-Policy (CSP) • Content-Security-Policy-Report-Onlyで運用開始する • default-src 'none' を指定する • 違反レポートの誤検知をフィルタリングする仕組みを用意する 69
  71. 71. ご清聴ありがとうございました 謝辞 本資料は株式会社セキュアスカイ・テクノロジーの新井様、坂本様に 技術レビューをして頂きました。心より感謝いたします。 70

×