Webアプリケーションのセキュリティ基礎
■第4話:クロスサイトスクリプティング (XSS) とクロスサイトリクエストフォージェリ (CSRF)
(最終更新日:2023.10.15)

(絵が小さい場合はスマホを横に)
「セッションが盗られる」
前回の認証とセッション管理、前々回のSQLインジェクション対策、加えてセキュアな通信を行うことで、
ユーザーは自分だけの情報を、使用しているサービスから安全に得ることができる。
ただし、サービス提供側の対策が不十分だと、これでも安全にWebサイトを利用できないことがある。
XSSにより、ユーザー固有のセッション情報が盗られることがあるからだ。
今回は、そのようなサービス提供側のWebサイトの脆弱性をついた別の攻撃として、XSSとCSRFについて説明する。
1.XSSの概要と種類
クロスサイトスクリプティング(XSS)自体は、攻撃者がターゲットのウェブサイトに悪意のあるスクリプトを注入することで、
ユーザーが意図しない動作を起こさせる攻撃手法である。主な目的としては、ターゲットとなるサービス利用ユーザーのセッションを乗っ取ることだ。
この攻撃は、ウェブアプリケーションがユーザーからの入力を適切に検証またはエスケープしない場合に発生する。
具体的な攻撃方法としては、攻撃対象のサービスのForm入力で下記のようなコードを入れる。
適切なエスケープ処理(<や>などの文字の無効化)がされていないと、
悪意のあるJavaScriptが実行されて、意図しない命令がされてしまう。
ここではアラートを出すだけだが、3話で説明したログイン管理のセッションを攻撃者に送る(つまり盗まれる)といった命令もできる。
2つ目のコードはエスケープのタイミングがデコード後だった時の脆弱性をついた攻撃で、こちらも悪意のあるスクリプトを実行できる。
XSSによる攻撃方法
XSSによる攻撃例
■XSSの種類
XSSの種類としては、大きく分けて3種類ある。反射型XSSと持続型XSS、DOM-based XSSだ。
反射型XSSは、ユーザーがクリックするリンクなどの形で悪意のあるスクリプトを埋め込むものだ。(例えば掲示板のリンク)
被害者がそのリンクをクリックすると、スクリプトは即座に実行される。
持続型XSSは、悪意のあるスクリプトがウェブサイトのデータベースに永続的に保存されるものだ。
これにより、そのページを訪れるすべてのユーザーが攻撃を受ける。
DOM-based XSSは、DOM(Document Object Model)を直接変更して実行される。
これは、クライアントサイドのスクリプトが悪意のある入力を正しく取り扱わない場合に発生する。
■XSSの対策
①XSSを防ぐ方法は、デコード前にスクリプトの実行可能性のある特殊な文字を、安全な文字に変換(エスケープ)することである。
安全な文字とは、&lt;などと言った特殊文字に変換することである。表示上は変わらないが、スクリプトとしては実行されなくなる。
②これに加えて、Cookieなどの機密情報を保存するものはJavaScriptで操作できない設定にするということも有効である。
XSSを行っても、Cookieからセッション情報を取ることができない。
③また、セキュリティヘッダーで実行に制限をかけるというのも有効である。
セキュリティヘッダーは、ウェブサーバーやウェブアプリケーションがブラウザに対して送信するHTTPレスポンスヘッダーの一部で、
ウェブサイトのセキュリティを強化するための指示や設定を含む。
Content-Security-Policyを利用することで、外部ドメインからのスクリプト、スタイルの読み込みを禁止することができる。
①と②を確実に実装すれば、基本的には大丈夫だろう。①に関しては、大抵のWebフレームワークでは元々実装されている。
2.CSRFの概要
クロスサイトリクエストフォージェリ(CSRF)は、攻撃者がユーザーのブラウザを利用して、
そのユーザーが認証済みのウェブアプリケーションに対して意図しないリクエストを送信させる攻撃である。
この説明だけではイメージがつかないと思うので、具体例を出して説明する。
①事前の状況
Aliceは、あるウェブサイト(例: bank.com)でインターネットバンキングのサービスを利用しています。
Aliceは現在、bank.comにログインしていて、セッションクッキーがブラウザに保存されています。
②攻撃の準備
攻撃者Bobは、Aliceがアクセスする可能性のある別のウェブサイト(例: malicious.com)に、次のような悪意のあるコードを仕込みます。
③攻撃の状況
Aliceが同ブラウザの別のタブでmalicious.comを訪れると、上記のコードにより、ブラウザはbank.comへのリクエストを行います。
このとき、Aliceのブラウザに保存されているbank.comのセッションクッキーが付与されるため、
このリクエストはAlice自身が実行したものとしてbank.comに認識されます。
④攻撃の結果
もしbank.comがこのようなGETリクエストでの送金操作を許可している場合(実際には良い実践ではありませんが)、
Aliceの知らない間にBobへの送金が実行されることになります。
ちなみに、例ではGETリクエストの場合を取り上げたが、下記のようなPOSTリクエストの場合でも同様に実行できる。
サイトに訪れただけで自動実行されるので、タチが悪い。
POSTでのCSRF攻撃例
3.CSRFの防御策
CSRFの防御策としては、先ほど挙げた攻撃例のように、別サイトからのGETやPOSTリクエストを受け取らないということが挙げられる。
具体的には、Access-Control-Allow-Originを自分のドメインだけに設定する(Access-Control-Allow-Origin: https://bank.com)ことである。
ただし、これでは不十分である。
例えば、昔あった攻撃例だと、同一SNS内のメールや掲示板のリンクを踏むと、
意図していない投稿が自分の投稿としてPOSTされてしまうということがあった。
そのWebサービス内に悪意のあるリンクを付与されると、同じように攻撃できてしまう。
この対策として、CSRFトークンの導入が最も一般的な防御策となる。
フォームの各リクエストに一意のトークンを含め、サーバー側でそのトークンを検証することで、リクエストが正当であることを確認できる。
具体的な方法としては、フォームのページを訪れた際にCSRFトークンをサーバー側で発行する。
これをユーザーのブラウザのCookieに保存し、フォームのinputにも同様のトークンを埋め込むのを同時に行う。
送信された先で、Cookieの値とinputの値の一致を検証することで、確かにそのページからのリクエストであることが保証される。
ここで大事なのは、XSS対策と合わせることである。CookieのHttpOnlyを有効にしていることで、
偽のページから偽のCookie値と偽のinputで照合させることも出来ないし、
ユーザー内にあるCookie値を読み取り、それをinputに埋め込んで照合させることもできないということである。
CSRF攻撃への対策
4.まとめ
今回、XSS対策とCSRF対策について説明した。
大事なのは、XSS対策とCSRF対策を両方合わせて実装するということである。
XSS対策が不十分だと、CSRF攻撃への脆弱性をも招いてしまう。
最近のWebフレームワークであれば、この辺りの機能は最初から実装されているが、中身を知っていないと応用が効かない。
たとえば、新しい技術を取り入れる際や独自のSQL文を使う場合などは、フレームワークで守られていない状態になる。
HTTPヘッダーでドメインを固定するなどセキュリティヘッダを適切に設定する、HttpOnlyを含めCookieを適切な設定にする、
サニタイジングやエスケープ処理を行う、プレースホルダを使うなど、各セキュリティ対策の仕組みと意味を理解するよう努めよう。
▼参考図書、サイト
安全なウェブサイトの作り方
情報処理推進機構
Cross Site Request Forgery protection
django公式サイト