🔑

MozillaのGuidlineから学ぶWeb Security

2023/06/06に公開

はじめに

MDNから出ているWeb Secutiry Guidlineが簡潔かつ美しくまとまっています。
個人的にSecurityに苦手意識があるため、いくつかCheat Sheetから気になるTopicいくつか抽出してまとめました。
同様にSecurityに苦手意識がある人の助けになれば幸いです。

HTTP Strict Transport Security

HTTP Strict Transport Security(HSTS)は、HTTPヘッダーで、ユーザーエージェントが選択したスキームがHTTPであっても、特定のサイトにのみHTTPSで接続するように通知するものである。あるサイトに対してHSTSを設定したブラウザは、すべてのリクエストを透過的にHTTPSにアップグレードします。また、HSTSは、ユーザーがエラーページを回避する機能を無効にすることで、TLSおよび証明書関連のエラーをより厳密に扱うようにブラウザに指示します。

  • ブラウザにHTTPSを用いて通信するように指示する
    • RFC6797として仕様が明記されている
  • HTTPからHTTPSにRedirectすると中間者にたいして攻撃の好きを与えてしまう
    • サーバからResponse HeaderにStrict-Transport-Securityを付与することで、ブラウザが同様のサイトへHTTPで通信しようとしても自動的にHTTPSで通信するようにすることができる

Directives

  • max-age
    • どのくらいの期間HTTPSで通信を行うかを秒単位で設定する
    • 最低6ヶ月(15768000)に設定する必要がある
      • 2年(63072000)のような長い期間を推奨している
      • この値を設定すると、有効期限に達するまでサイトは HTTPS をサポートし続けなければならない
  • includeSubDomains
    • サブドメインへのRequestに対してもHTTPSでの通信を指定する
      • domain.mozilla.comでincludeSubDomainsを設定すると、host1.domain.mozilla.comとhost2.domain.mozilla.comに対しても設定することになる
      • HTTPSが有効になっていないサブドメインのサイトに対しての通信が無効になってしまうことに注意する
  • preload
    • ウェブサイトをHSTS preload listに含めることを可能にする
      • その結果、ブラウザまだHSTS Headerを受け取っていない初回のWebサイトへのアクセス時からHTTPSの通信を指定することができる
      • HSTS preload listに含まれるには、includeSubDomainsも設定されている必要があることに注意が必要

設定例

# 2年間はこのサイトへの接続はHTTPSのみとする(推奨)
Strict-Transport-Security: max-age=63072000

# 今後2年間、このサイトとサブドメインへの接続はHTTPSのみとし、プリロードリストにも含める。
Strict-Transport-Security: max-age=63072000; includeSubDomains; preload

もし設定がないと...

あなたが、空港で無料の Wi-Fi アクセスポイントにログインしてウェブの利用を開始し、オンラインバンキングサービスで残高の確認や取引を行ったとします。しかし不運にも、あなたが使用したアクセスポイントはハッカーのノートパソコンであり、そのハッカーはあなたの HTTP リクエストを傍受して、本物の銀行のサイトではなく偽のサイトへリダイレクトしたとします。こうなると、あなたの個人情報はハッカーにさらされてしまいます。
Strict Transport Security はこの問題を解決します。いったん銀行のウェブサイトへ HTTPS でアクセスすれば、そして銀行のウェブサイトが Strict Transport Security を利用していれば、ブラウザーは自動的に HTTPS のみを用いるよう理解して、ハッカーによるこの種の中間者攻撃の実行を防ぎます。

  • Directiveのpreloadまで含めて設定することで初回アクセス時からHTTPSの通信を強制することができる

Resource Loading

  • 一言でいうと、静的コンテンツやJavascriptの読み込みもHTTPSで行いましょう
  • HTTPSのページの中で通常の平文の HTTPで送られてくるコンテンツ(混在コンテンツ)を読み込むと、ブラウザがブロックすることで劣化したUIや警告をユーザに経験させてしまう
    • Javascriptなどの動的なリソースに限らず、画像などの静的なコンテンツを混在コンテンツを読み込む場合でも改ざんやフィッシングのリスクが残る

設定例

<!-- HTTPSは、JavaScriptリソースを読み込むための素晴らしい方法です -->
<script src="https://code.jquery.com/jquery-1.12.0.min.js"></script>

<!-- HTTPで読み込もうとするとブロックされ、混合コンテンツの警告が発生する -->
<script src="http://code.jquery.com/jquery-1.12.0.min.js"></script>

<!-- パッシブコンテンツがブロックされることはありませんが、混合コンテンツの警告が発生する -->
<img src="http://very.badssl.com/image.jpg">

受動的な混在コンテンツ

  • 脅威として、誤解を招くコンテンツが含まれているか、ユーザのクッキーが盗まれている可能性がある
  • HTTPで送信された画像に対して、攻撃者は別の不適切な画像やメッセージへと差し替えてユーザに表示させることが出来る
  • 攻撃者はユーザへ送信される画像を盗聴することで、ユーザの行動に関する情報を推測することが可能である
    • 画像ファイルの置かれている場所がウェブサイト中のある特定のページに固定されていることがよくある
      • もし攻撃者が特定の画像に対する HTTPリクエストを覗き見れば、ユーザが閲覧しているウェブページを特定することが可能となる

能動的な混在コンテンツ

  • HTTPSページのすべて、ないしは DOM の一部にアクセスできるコンテンツ
    • HTTPSページの動作を変更することができ、ユーザから機密情報を窃取することも可能
  • 脅威として、フィッシングや機密情報の漏えい、悪意あるサイトへのリダイレクトなどが想定される

中間者攻撃の攻撃者はまず HTTP のコンテンツへのリクエストを横取りすることが出来ます。 その後、攻撃者はレスポンスを改ざんして悪意ある JavaScript コードを含めることも可能です。悪意ある能動的なコンテンツは、ユーザーのログイン情報を窃取したり、ユーザーに関する機密情報を取得したり、ユーザのマシンにマルウェアのインストールを試みることが出来ます

Content Security Policy

  • Content Security Policy(CSP)は、サイト運営者がサイト上のリソースをどこから読み込むかを細かく制御できるようにするHTTPヘッダー
    • 主な利点は、安全なインラインJavascriptを使用できなくすることができること
      • インラインJavascriptとは、WebブラウザによってJavascriptとして解釈される不適切にエスケープされたユーザ入力のこと
      • インラインJavascriptを無効にすると、すべてのJavascriotは<script>タグから読み込む必要がある
    • CSPを使用してインラインJavascriptを無効にすることで、サイトに対するほぼ全てのXSS攻撃を効果的に排除できる
  • Javascriptや<style>タグやstyle属性を使用したインラインスタイルシートも読み込めないため、CSPを導入しやすくするために、サイトの設計には注意が必要である

設定例

# 安全でないinline/evalを防止し, HTTPSでのリソース(images, fonts, scripts, etc.)読み込みのみ許可する
# XSS対策にはなりませんので注意が必要
Content-Security-Policy: default-src https:

<!-- <meta>タグを使用した上記と同様の設定 -->
<meta http-equiv="Content-Security-Policy" content="default-src https:">
# 安全でないinline/evalを使用できないようにし、プラグイン(`<object>`, `<embed>` タグで読み込まれるプラグインコンテンツ、 `<applet>` タグで読み込まれる Java アプレット)の実以外を許可する
Content-Security-Policy: default-src *; object-src 'none'
# 安全でないinline/evalを使用できないようにし、同一オリジンからのリソース読み込みのみを許可する
# プラグインの実行は不可能
Content-Security-Policy: default-src 'self'; img-src 'self' https://i.imgur.com; object-src 'none'
# 安全でないinline/evalやプラグインを使用できないようにし、同一オリジンからのスクリプトやスタイルシート、Google Fontsの読み込みのみを許可する
# また同一オリジンとimgurからの画像の読み込みを許可する。サイトが目指すポリシーの方針
Content-Security-Policy: default-src 'none'; font-src https://fonts.gstatic.com;
			 img-src 'self' https://i.imgur.com; object-src 'none'; script-src 'self'; style-src 'self'
# インラインコードを多用する既存サイトの修正
# リソースがHTTPSでのみ読み込まれるようにし、プラグインを無効化したい。
Content-Security-Policy: default-src https: 'unsafe-eval' 'unsafe-inline'; object-src 'none'

# 上記のポリシーはまだ実施せず、発生したであろう違反を報告するだけでよい。
Content-Security-Policy-Report-Only: default-src https:; report-uri /csp-violation-report-endpoint/
# あらゆるリソースのロードを無効化し、フレームを無効にする。
Content-Security-Policy: default-src 'none'; frame-ancestors 'none'

Cookies

  • すべてのCookieは、そのアクセスが可能な限り制限されるように作成されるべき
    • XSS脆弱性による被害を最小化するのに役立つ

Directives

  • Secure
    • すべてのCookieにSecureフラグを設定し、HTTPSでのみ送信されるようにする必要がある
  • HttpOnly
    • JavascriptからCookieにアクセスできないようにする
  • Domain
    • 他のドメインでアクセスする必要がある場合にのみ設定し、可能な限り制限されたドメインからのアクセスに設定する必要がある
  • Path
    • Cookieが有効なPath
    • Path=/の場合、ドメインの全てのpathでCookieが使用できる

設定例

# このホストでのみアクセス可能なセッション識別子クッキーで、ユーザーがブラウザを閉じたときに消去される
Set-Cookie: MOZSESSIONID=980e5da39d4b472b9f504cac9; Path=/; Secure; HttpOnly
# すべてのmozilla.orgサイトのセッション識別子で、__Secure-接頭辞を使って30日で期限切れとなる
# このクッキーはクロスオリジンでは送信されないが、他のサイトからMozillaのサイトへ移動する際に送信さる
Set-Cookie: __Secure-MOZSESSIONID=7307d70a86bd4ab5a00499762; Max-Age=2592000; Domain=mozilla.org; Path=/; Secure; HttpOnly; SameSite=Lax
# ユーザーがToSを受け入れた(利用規約に同意した)ときに、Javascriptでアクセス可能な現在のホストの長期保存型クッキーを設定する
# このクッキーは、リンクをクリックするなどして、他のサイトからあなたの送信に移動するときに送信されます
Set-Cookie: __Host-ACCEPTEDTOS=true; Expires=Fri, 31 Dec 9999 23:59:59 GMT; Path=/; Secure; SameSite=Lax
# bugzilla.mozilla.orgのような安全なサイトで使用されるセッション識別子
# クロスオリジンリクエストからは送信されず、他のサイトからbugzilla.mozilla.org に移動する際にも送信されない
# 他のCSRF対策と併用することで、CSRF攻撃からサイトを守る非常に強力な方法となる
Set-Cookie: __Host-BMOSESSIONID=YnVnemlsbGE=; Max-Age=2592000; Path=/; Secure; HttpOnly; SameSite=Strict

Cross-origin Resource Sharing

  • 特に必要でない限り、存在しないほうがよい
    • 使用例としては、JavaScript/CSSライブラリや公開APIエンドポイントのホスティングを提供するコンテンツデリバリーネットワーク(CDN)などがある
    • もし存在するのであれば、適切な機能のために必要なだけのオリジンやリソースをロックダウンする必要がある
      • 例えば、サーバーがウェブサイトと、リモートウェブサイトのXMLHttpRequestアクセスを目的としたAPIの両方を提供している場合、APIリソースのみがAccess-Control-Allow-Originヘッダーを返すべき
      • これを行わないと外国のオリジンが該当のオリジンのどのページの内容も読むことができるようになる
  • 正直このsecurity guidlineだけでは情報がすくないため詳細はこちらを参照
    https://developer.mozilla.org/ja/docs/Web/HTTP/CORS

CSRF Prevention

  • Cross-site request forgeries(クロスサイト・リクエスト・フォージェリー)は、信頼できるユーザーからWebサイトへ不正なコマンドを送信する攻撃の一種
  • Origin/Referrer checkingやchallenge-response systems(CAPTCHAなど)など、さまざまな緩和策がある
  • CSRF緩和の最も一般的で透明性の高い方法は、anti-CSRF tokensを使用すること
    • anti-CSRF tokensは、すべての破壊的な変更に対して、秘密の・ユニークな・予測不可能なトークンの存在を要求することによって、CSRF攻撃を防止する
    • これらのトークンは、ユーザーセッション全体に対して設定することも、定期的にローテーションすることも、リクエストごとに一意に作成することも可能
    • SameSiteクッキーはCSRF攻撃に対する最良の防御策だが、まだすべてのブラウザで完全にサポートされているわけではない

設定例

<!-- A secret anti-CSRF token, included in the form to delete an account -->
<input type="hidden" name="csrftoken" value="1df93e1eafa42012f9a8aff062eeb1db0380b">
# JavascriptがX headerとしてtokenを送る必要があるため、サーバサイドがanti-CSRF cookieをセットする
Set-Cookie: CSRFTOKEN=1df93e1eafa42012f9a8aff062eeb1db0380b; Path=/; Secure; SameSite=Strict
// クライアントサイドでXMLHttpRequestへX headerにanti-CSRF tokenを付与してリクエストする
var token = readCookie(CSRFTOKEN);                   // read the cookie
httpRequest.setRequestHeader('X-CSRF-Token', token); // add it as an X-CSRF-Token header

X-Frame-Options

  • X-Frame-OptionsはHTTPヘッダーで、サイトがiframe内でどのようにフレーム化されるかを制御することができる

クリックジャッキングは、悪意のあるサイトがユーザーを騙して、一見あなたのサイトにないように見えても、あなたのサイト上のリンクをクリックさせるという実用的な攻撃です。このため、新しいウェブサイトではX-Frame-Optionsヘッダーの使用が必須であり、既存のウェブサイトでもできるだけ早くX-Frame-Optionsのサポートを追加することが期待されています。

Directives

  • DENY
    • iframeサイトへのアクセスを許可しない(推奨)
  • SAMEORIGIN
    • サイト自体をiframe化できるようにする

設定例

# X-Frame-OptionsとCSPでサイトのフレーム化を阻止する。
Content-Security-Policy: frame-ancestors 'none'
X-Frame-Options: DENY
# 自分のサイトがフレーム化することだけを許可する
Content-Security-Policy: frame-ancestors 'self'
X-Frame-Options: SAMEORIGIN
# framer.mozilla.orgにのみフレームを許可する
# CSP2+をサポートしていないブラウザからのフレームをブロックすることに注意が必要
Content-Security-Policy: frame-ancestors https://framer.mozilla.org
X-Frame-Options: DENY

CSP2+とは、Content Security Policy (CSP) のバージョン2以降の機能を指す

Reference

https://infosec.mozilla.org/guidelines/web_security
https://developer.mozilla.org/ja/docs/Web/HTTP/Headers/Strict-Transport-Security

Discussion