kouの技術的メモ

学習した内容の定着やアウトプット用に開設しました

セキュリティ用語

XSS(クロスサイトスプリクティング)

ウェブアプリケーションの中には、検索のキーワードの表示画面や個人情報登録時の確認画面、掲示 板、ウェブのログ統計画面等、利用者からの入力内容や HTTP ヘッダの情報を処理し、ウェブページとし て出力するものがあります。ここで、ウェブページへの出力処理に問題がある場合、そのウェブページに スクリプト等を埋め込まれてしまいます。この問題を「クロスサイト・スクリプティング脆弱性」と呼び、こ の問題を悪用した攻撃手法を、「クロスサイト・スクリプティング攻撃」と言う。

古い情報ではありますがIPAによると

クロスサイト・スクリプティング脆弱性の届出件数は、他の脆弱性に比べて多くなっています。この脆 弱性については、届出受付開始から 2014 年第 4 四半期までに、ウェブサイトの届出件数の約 5 割に相 当する届出を受けています。

との事なので非常に被害の多い攻撃法と言えます。

被害の例

  • ブラウザが保存している Cookie を取得される
    • Cookie にセッション ID が格納されている場合、利用者へのなりすましにつながる(いわゆるセッションハイジャック
    • Cookie に個人情報等が格納されている場合、その情報が漏えいする
  • 任意の Cookie をブラウザに保存させられる
    • セッション ID が利用者に送り込まれ、「セッション ID の固定化」 攻撃に悪用される

対策

  • ウェブページに出力する全ての要素に対して、エスケープ処理を施す。

    • ウェブページを構成する要素として、ウェブページの本文や HTML タグの属性値等に相当する全て の出力要素にエスケープ処理を行います。エスケープ処理には、ウェブページの表示に影響する特別 な記号文字(「<」、「>」、「&」等)を、HTML エンティティ(「<」、「>」、「&」等)に置換する方法が あります。また、HTML タグを出力する場合は、その属性値を必ず「"」(ダブルクォート)で括るようにし ます。そして、「"」で括られた属性値に含まれる「"」を、HTML エンティティ「"」にエスケープします。 脆弱性防止の観点からエスケープ処理が必須となるのは、外部からウェブアプリケーションに渡さ れる「入力値」の文字列や、データベースやファイルから読み込んだ文字列、その他、何らかの文字列 を演算によって生成した文字列等です
  • URL を出力するときは、「http://」や 「https://」で始まる URL のみを許可する

    • URL には、「http://」や「https://」から始まるものだけでなく、「javascript:」の形式で始まるもの もあります。ウェブページに出力するリンク先や画像の URL が、外部からの入力に依存する形で動的 に生成される場合、その URL にスクリプトが含まれていると、クロスサイト・スクリプティング攻撃が可 能となる場合があります。たとえば、利用者から入力されたリンク先の URL を「<a href ="リンク先の URL">」の形式でウェブページに出力するウェブアプリケーションは、リンク先の URL に「javascript:」 等から始まる文字列を指定された場合に、スクリプトを埋め込まれてしまう可能性があります。リンク先 の URL には「http://」や「https://」から始まる文字列のみを許可する、「ホワイトリスト方式」で実装 する様にします。
  • 入力された HTML テキストから、スクリプトに該当する文字列を排除する。

    • 入力された HTML テキストに含まれる、スクリプトに該当する文字列を抽出し、排除します。抽出した文字列の排除方法には、無害な文字列へ置換することが推奨されます。たとえば、「<script>」や「javascript:」を無害な文字列へ置換する場合、「<xscript>」「xjavascript:」のように、その文字列に適当な文字を付加します。他の排除方法として、文字列の削除が挙げられますが、削除した結果が危険な文字列を形成してしまう可能性があるため、一般的に推奨されません。
  • HTTP レスポンスヘッダの Content-Type フィールドに文字コード(charset)を 指定する。

  • HTTP のレスポンスヘッダの Content-Type フィールドには、「 Content-Type: text/html; charset=UTF-8」のように、文字コード(charset)を指定する。 一部のブラウザにおいては、HTML テキストの冒頭部分等に特定の文字列が含まれていると、必ず特定の文字コードとして処理されるという挙動が知られています。 Content-Type フィールドで文字コードの指定を省略した場合、攻撃者が、この挙動を悪用して、故 意に特定の文字コードをブラウザに選択させるような文字列を埋め込んだ上、その文字コードで解釈 した場合にスクリプトのタグとなるような文字列を埋め込む可能性があります。 たとえば、具体的な例として、HTML テキストに、 「+ADw-script+AD4-alert(+ACI-test+ACI-)+ADsAPA-/script+AD4-」という文字列が埋め込まれた 場合が考えられます。この場合、一部のブラウザはこれを「UTF-7」の文字コードエンコードされた文 字列として識別します。これが UTF-7 として画面に表示されると 「<script>alert('test');</script>」として扱われるため、スクリプトが実行されてしまいます。
  • Cookie 情報の漏えい対策として、発行する Cookie に HttpOnly 属性を加える
  • 「HttpOnly」は、Cookie に設定できる属性のひとつで、これが設定された Cookie は、HTML テキスト 内のスクリプトからのアクセスが禁止されます。これにより、ウェブサイトにクロスサイト・スクリプティン グから守れます

CSRF

Cross Site Request Forgeriesクロスサイト・リクエスト・フォージェリ。

XSSと似ているが異なるものとしてCSRFがあります。 XSSがブラウザ側で不正なスクリプトを用いて不正を行うものなのに対して、CSRFCSRF脆弱性を利用してサーバ側に不正な攻撃用リクエストを投げる攻撃です。

CSRF攻撃の例
  1. ユーザAがサイトXにログインしている(つまりユーザAはサイトXのcookieセッション情報を持っている)
  2. ユーザAは罠用URLが施された別の攻撃用サイトのURLをクリックしてしまう。
  3. 攻撃用サイトのクリックにより、サイトXのユーザAの登録個人情報を書き換える不正情報がPostされる。
  4. ユーザAはすでにログインしているため、サイトXサーバにcookie情報が正しいと認識されPostが成功する。 5.登録個人情報の書き換えが成功してしまう。

保持しているcookieはリクエスト先のサーバが発行元であれば、リクエスト元が正規のものであろうが、別のサイトだろうがそのサイトで生成されたcookie情報を送ってしまうので、上記の攻撃が成立してしまう。

被害の例

ログイン後の利用者のみが利用可能なサービスの悪用や編集可能な情報の改ざん、新規登録 不正な送金、利用者が意図しない商品購入、利用者が意図しない退会処理 等

各種設定の不正な変更(管理者画面、パスワード等)、掲示板への不適切な書き込み

対策

  • 処理を実行するページを POST メソッドでアクセスするようにし、「hidden パラメータ」に秘密トークンが挿入されるようして実行ページではその値が正しい場合のみ処理を実行する。
    • CSRFが成功するのは、cookieだけでは誰のリクエストなのか判断ができない為なので、ログイン時cookieのセッションID以外の第2の識別情報(CSRFトークン)を擬似乱数生成器を用いて生成、これを重要な処理の際にサーバ側の情報と比較し、一致しなければ処理を実行しない様にする。
    • このCSRFトークンはリクエストヘッダやリクエストボディに仕込むとよい。xssなどによりcookie情報が流出した場合、意味がなくなるため
    • 下記項目でも書くがCORSの設定では防げない。CORSによるフィルタリングはクライアント側で結果を取得できないだけなので、サーバへの攻撃リクエスト自体は成功してしまう為。
    • ちなみにRuby On Railsの場合は、Railsが提供するform_withやform_forなどのヘルパーを使うと、自動でセキュリティトークン(authenticity_token)を仕込んでくれる

同一生成元ポリシーとCORS

同一生成元ポリシー(Same-Origin Policy, SOP)

CSRFなどのセキュリティ攻撃を防止するためにブラウザに備わっている仕組みで、異なるオリジンのリソースへのアクセスに制約をかけるもの。 同一生成元ポリシーによりWebページを生成したドメイン以外へのHTTPリクエストはできない。 異なるオリジンの場合あくまリクエストでして帰ってきたレスポンスをブラウザで読めなくするものなので、サーバへのリクエスト自体は成功してしまうので、CSRFは防げない。

ブラウザがリクエストを異なるオリジンのサーバーに投げる際にHTTPレスポンスヘッダーに以下の様な情報を乗せて送る。 Origin: http://hoge.com

因みにブラウザで実行されたJavaScriptからAPIサーバにアクセスする場合、ブラウザ側のオリジンはHTMLやCSS、JSを読み込んだフロントエンド側サーバのオリジンとなる。

この制約はCORS(Cross-Origin Resource Sharing) と呼ばれる仕組みを利用することで一部解除することができる。

オリジンとは

スキーム + ホスト + ポート の組み合わせを オリジン(Origin)という スキーム + ホスト + ポートのどれかが違うことをオリジンが異なると表現します。

例えば以下のURLの場合はそれぞれこの様に対応します。

http://hoge:80/directry1

  • http
    • スキーム
  • hoge
    • ホスト
  • 80
    • ポート番号

以下は同一オリジンになります。 http://hoge:80/directry2

以下は異なるオリジンになります。 http://fuga:80/directry1 http://hoge:8080/directry1

CORS

Cross-Origin Resource Sharingオリジン間リソース共有

同一生成元ポリシーのアクセス制約を一部解除し、異なるオリジン間でリソースを共有するための仕組み。

SPAの場合は、フロントエンド側のhtml,css,Javascriptを生成したオリジンとAPI側のオリジンが異なることが多い。

サーバ側でHTTPレスポンスヘッダにAccess-Control-Allow-Origin:「フロント側オリジン」を付与してあげることでアクセス制約がなくなる。

例えば、異なるオリジンにXHRやFetch API、axiosでアクセスする場合、

例えばサイトAから他のオリジンのリソースにアクセスしたい場合、ブラウザはリクエストヘッダに以下の様にアクセス元のオリジン情報を付加します。

Origin: http://site-a.example.com

これに対し、site-b 側で、site-a へのアクセスを許可する場合、下記の様なレスポンスヘッダを返します。

Site-B → Site-A

Access-Control-Allow-Origin: http://site-a.example.com

参考元サイト: http://www.tohoho-web.com/ex/cors.html