XSS
XSSの本質は、悪意のあるコードがフィルタリングされずにウェブサイトの正常なコードに混ざってしまうことです。ブラウザは、どのスクリプトが信頼に足るものかを見分けることができず、悪意のあるスクリプトが実行されてしまいます。
- ユーザーからのUGC情報
- 第三者からのリンク
- URL
- POST
- Referer
- Cookie
XSS攻撃の危険性
- マシンログインアカウント、インターネットバンキングアカウント、あらゆる種類の管理者アカウントなど、あらゆる種類のユーザーアカウントを盗みます。
- 機密性の高い企業データの読み取り、改ざん、追加、削除を含む企業データの管理
- 企業にとって重要な商業的価値のある情報の窃盗
- 不正な転送
- 強制メール
- ウェブサイトのハッキング
- 被害者のマシンを操作して、他のウェブサイトに攻撃を仕掛ける手口。
XSS脆弱性の分類
攻撃のソースによって、XSS攻撃は蓄積型、反射型、DOM型に分類されます。
保存されたXSS
保存された XSS の攻撃手順:
- 攻撃者は悪意のあるコードを標的のウェブサイトのデータベースに送信します。
- ユーザーが標的のウェブサイトを開くと、ウェブサーバーはデータベースから悪意のあるコードを取得し、HTMLにつなぎ合わせてブラウザに返します。
- ユーザーのブラウザーはそのレスポンスを受信し、実行するために解析し、悪意のあるコードが混ざって実行されます。
- 悪意のあるコードがユーザーデータを盗み出し、攻撃者のウェブサイトに送信したり、ユーザーの振る舞いになりすまして標的のウェブサイトのインターフェースを呼び出し、攻撃者が指定した操作を実行したりします。
この攻撃は、フォーラムの投稿、製品レビュー、プライベートなユーザーメッセージなど、ユーザーが保存したデータを含むウェブサイトの機能でよく見られます。
反射型XSS
Reflective XSS 攻撃のステップ:
- 攻撃者は、悪意のあるコードを含む特別なURLを作成します。
- ユーザーが悪意のあるコードを含むURLを開くと、ウェブサーバーはURLから悪意のあるコードを取り出し、HTMLにつなぎ合わせてブラウザに返します。
- ユーザーのブラウザーはそのレスポンスを受信し、実行するために解析し、悪意のあるコードが混ざって実行されます。
- 悪意のあるコードがユーザーデータを盗み出し、攻撃者のウェブサイトに送信したり、ユーザーの振る舞いになりすまして標的のウェブサイトのインターフェースを呼び出し、攻撃者が指定した操作を実行したりします。
Reflective XSSとStored XSSの違いは、Stored XSSがデータベースに悪意のあるコードを持つのに対し、Reflective XSSはURLに悪意のあるコードを持つことです。
反射型 XSS 脆弱性は、サイト検索やリダイレクトなど、URL を介してパラメータを渡す機能でよく見つかります。
攻撃が機能するためには、ユーザーが積極的に悪意のあるURLを開く必要があるため、攻撃者は多くの場合、ユーザーを騙してクリックさせるために様々な手口を組み合わせています。
リフレクト XSS は POST コンテンツによっても引き起こされますが、発動条件が厳しいため、非常にまれです。
DOM タイプ XSS
DOM ベースの XSS 攻撃の手順:
- 攻撃者は、悪意のあるコードを含む特別なURLを作成します。
- ユーザーが悪意のあるコードを含むURLを開きます。
- ユーザーのブラウザはレスポンスを受信し、それを実行するために解析し、フロントエンドのJavaScriptはURL内の悪意のあるコードをフェッチして実行します。
- 悪意のあるコードがユーザーデータを盗み出し、攻撃者のウェブサイトに送信したり、ユーザーの振る舞いになりすまして標的のウェブサイトのインターフェースを呼び出し、攻撃者が指定した操作を実行したりします。
DOM型XSSと前2つのXSSの違い:DOM型XSS攻撃では、悪意のあるコードの抽出と実行がブラウザ側で行われるため、フロントエンドJavaScript自体のセキュリティ脆弱性であるのに対し、他の2つのXSSはサーバ側のセキュリティ脆弱性に属します。
予防
- 入力フィルタリング。完全にXSS攻撃を回避することはできませんが、また、不確実性と面倒なコードの問題を大量に導入し、明確な入力タイプは、数字、URL、電話番号、メールアドレスなどのコンテンツは、入力フィルタリングはまだ必要です。
- 純粋なフロントエンド・レンダリング:
- ブラウザはまず、ビジネス関連のデータを含まない静的なHTMLを読み込みます。
- その後、ブラウザはHTML内のJavaScriptを実行します。
- JavaScriptは、Ajaxを介してビジネスデータをロードし、ページ上でそれを更新するためにDOM APIを呼び出します。
- HTMLを完全にエスケープしてください。
- 文字列をスプライスするときは、信頼できないデータをスプライスしないように注意してください。
- 入力コンテンツの長さ制御。
- 厳格な CSP は、XSS 対策において以下のような役割を果たします:
- 複雑な攻撃ロジックを防ぐため、エキゾチックなコードのロードを禁止します。
- ドメイン外への送信を無効にすることで、ウェブサイトが攻撃された後でも、ユーザーデータがドメイン外に漏れることはありません。
- インラインスクリプトの実行を無効にします。
- 不正なスクリプトの実行を無効にします。
- エスカレーションを適切に使用することで、XSS をタイムリーに検出し、問題を可能な限り迅速に修正することができます。
CSRF
CSRFとは
CSRF(クロスサイト・リクエスト・フォージェリ):攻撃者は被害者を第三者のウェブサイトに誘導し、攻撃されたウェブサイトにリクエストを送信します。攻撃者は、被害者が攻撃されたウェブサイトで既に取得した登録認証情報を使用して、攻撃されたウェブサイトで操作を実行するためにユーザーになりすますという目的を達成するために、バックグラウンドでユーザー認証をバイパスします。
以下は典型的なCSRF攻撃の流れです:
- 被害者はa.comにログインし、aウェブサイトのログイン認証情報(クッキー)を保持します。
- 攻撃者は被害者をb.comに誘導
- b.comは被害者のクッキーを持ち、b.comにリクエストを送信します。
- a.comはリクエストを受信し、リクエストを検証し、被害者であることを確認した後にリクエストを実行します。
- 攻撃は完了し、攻撃者は被害者の知らないうちに被害者になりすまし、a.comを攻撃しました。
CSRF 攻撃の一般的なタイプ
- GETCSRFの種類
GET タイプの CSRF 利用は非常に単純で、HTTP リクエストが必要なだけです:
<img src="http://./?=&;=er" >
[http://./?=&;=&;=er](tp://./?=&;=&;=er)
被害者がこのimgを含むページにアクセスすると、ブラウザは自動的に.bank.exampleにHTTPリクエストを送信し、被害者のログイン情報を含むクロスドメインリクエストを受信します。
- POSTCSRFの種類
このタイプのCSRFの利用は、通常、次のような自動送信フォームで使用されます:
<form action="http://./aw" method=POST>
<input type="hidden" name="account" value="xiaoming" />
<input type="hidden" name="amount" value="10000" />
<input type="hidden" name="for" value="hacker" />
</form>
<script> document.forms[0].submit(); </script>
このページにアクセスした後、フォームは自動的に送信されます。これは、ユーザがPOST操作を完了したことをシミュレートしているのと同じです。
POST タイプの攻撃は通常 GET タイプの攻撃よりも少し厳しいですが、それでも複雑ではありません。個人のウェブサイト、ブログ、ハッカーがページをアップロードするサイトであれば、どのようなものでも攻撃される可能性があります。
- リンクタイプ CSRF
リンクタイプの CSRF は、ユーザがページを開いて攻撃される他の 2 つのタイプに比べて一般的ではありません。このタイプは通常、フォーラムに投稿されたイメージや、ユーザーを罠に誘い込むための広告の形に埋め込まれた悪意のあるリンクで、攻撃者は通常、より大げさな言葉を使うなどしてユーザーをおびき寄せ、クリックさせます:
<a href="http://.//.?=&;=er" taget="_blank">
重いニュースだ!
<a/>
ユーザは信頼できるウェブサイトAにログインしており、ログイン状態を保存しているため、ユーザが上記のPHPページを積極的に訪問する限り、攻撃は成功します。
CSRF
- 攻撃は通常、攻撃を受けるウェブサイトではなく、第三者のウェブサイトで開始されます。攻撃されたサイトは、攻撃の発生を防ぐことができません。
- この攻撃は、攻撃されたサイト上で被害者のログイン認証情報を使用して被害者になりすまし、データを盗む代わりにアクションを送信します。
- 攻撃者は被害者のログイン認証情報にアクセスすることはできませんが、単に被害者に「なりすます」だけです。
- クロスサイトリクエストは、イメージ URL、ハイパーリンク、CORS、フォーム送信など、様々な方法で行われます。リクエストの中には、サードパーティのフォーラムや記事に直接埋め込まれるものもあり、追跡が難しくなります。
保護戦略
CSRFは通常、サードパーティのウェブサイトから仕掛けられるため、攻撃されたウェブサイトは攻撃の発生を防ぐことはできませんが、自社のウェブサイトのCSRF対策を強化することで、セキュリティを向上させることができます。
CSRFの2つの特徴は上記の通りです:
- CSRFはサードパーティのドメインで発生します。
- CSRF攻撃者はクッキーのような情報を得ることはできません。
保護戦略は、特にこの2点に対処するために、以下のように策定することができます:
不明な外部ドメインへのアクセスをブロック
同一生成元検出
Samesite Cookie
このドメインでしか入手できない情報の添付が必要です。
CSRF Token
二重クッキーの検証
さまざまな保護方法については、以下で詳しく説明します:
同一生成元ポリシー
HTTP プロトコルでは、すべての非同期リクエストはソースドメインをマークするために 2 つの Header を持ちます:
- Origin Header
- Referer Header
これら二つのヘッダは、ブラウザがリクエストを開始するときにほとんどの場合自動的に提供され、フロントエンドがコンテンツ用にカスタマイズすることはできません。 サーバはこれら二つのヘッダのドメイン名を解決することで、 リクエストの送信元ドメインを決定することができます。
Referer ヘッダの値はブラウザによって提供され、HTTP プロトコルには明確な要件がありますが、Referer の具体的な実装はブラウザによって異なり、ブラウザ自体にセキュリティの脆弱性がないという保証はありません。Referer の値を検証する方法は、第三者によるセキュリティ保証に頼ることになり、理論的にはあまり安全ではありません。場合によっては、攻撃者は自分のリクエストの Referer 値を隠したり、変更したりすることもできます。
リファラーポリシーを設定するには、3つの方法があります:
- CSP の設定
- ページヘッダーにメタタグを追加
- aタグにreferrerpolicy属性を追加
このほかにもいろいろありますが、一つだけわかっていることは、攻撃者は自分のリクエストの中にRefererを隠すことができるということです:
<img src="http://./?=&;=er" referrerpolicy="no-referrer">
このリクエストによって開始された攻撃はRefererを持ちません。
また、次のような場合にもRefererが利用できないか、信頼できません:
1.IE6、ジャンプのインターフェイスのwindow.location.href=urlの使用の下で7は、Refererが失われます。
2.IE6,7でwindow.openを使用している場合、Refererが欠落します。
3.HTTPSページがHTTPページにジャンプし、すべてのブラウザRefererが失われます。
4.Flashをクリックして他のサイトにアクセスする場合、Refererの状況はより厄介で、信頼性が低くなります。
CSRF Token
1.CSRFトークンをページに出力します。
まず第一に、ユーザーがページを開いたときに、サーバーは、データを暗号化するために暗号化アルゴリズムを介して、このユーザー、トークンを生成する必要があり、一般的なトークンは、ランダムな文字列とタイムスタンプの組み合わせが含まれ、それはトークンが送信するときにクッキーに配置することができないことは明らかである、それ以外の場合は、攻撃者によってなりすまされます。したがって、安全にするためにトークンは、サーバーのセッションに存在するのが最善であり、その後、各ページのロードでは、トークンを追加するすべてのDOMのaとフォームタグのために、全体のDOMツリーを横断するJSを使用します。これは、リクエストのほとんどを解決することができますが、ページがロードされた後にHTMLコードの動的生成のために、このメソッドは動作しませんし、まだプログラマが手動でコードを追加する必要があります。プログラマはコーディング時に手動でトークンを追加する必要があります。
2.ページによって提出されたリクエストは、このトークンを運びます。
GETリクエストの場合、トークンはリクエストアドレスに付加され、URLは http://?=ue POSTリクエストの場合、トークンはフォームの末尾に付加されます:
<input type=”hidden” name=”csrftoken” value=”tokenvalue”/>
これはトークンをパラメータとしてリクエストに追加します。
3.サーバーはトークンが正しいことを確認します。
ユーザがクライアントからトークンを取得し、それを再びサーバに送信すると、サーバはトークンの有効性を判断する必要があります。検証プロセスは、まずトークンを復号化し、暗号化された文字列とタイムスタンプを比較します。
分散バリデーション
大規模なウェブサイトでは、CSRF トークンを格納するためにセッションを使用することは大きなプレッシャーになります。単一のサーバ・セッションへのアクセスは同じです。しかし、最近の大規模な Web サイトでは、通常、サーバは複数あり、数十台から数百台、あるいは、異なる地方にある複数のサーバルームにある場合もあり、ユーザが開始した HTTP リクエストは通常、Ngnix などのロードバランサを経由して、特定のサーバにルーティングされます。セッションはデフォルトで 1 台のサーバのメモリに保存されるため、分散環境では、同じユーザが送信した複数の HTTP リクエストが連続して異なるサーバに落ち、結果として同じセッションが異なるサーバに保存される可能性があります。同じユーザーによって送信された HTTP リクエストが連続して異なるサーバーに落ちる可能性があり、その結果、後から開始された HTTP リクエストがサーバーのセッションデータに格納されている HTTP リクエストを取得できなくなり、分散環境でのセッションメカニズムが機能しなくなります。のようなパブリックなストレージスペースに格納する必要があります。
セッション・ストレージを使用するため、CSRF トークンの読み取りと検証は比較的大きな複雑さとパフォーマンスの問題を引き起こします。トークンのこの方法は、ランダムに生成された文字列ではなく、計算された結果です。保存されたトークンを読み取ることなく、検証でこの方法では、もう一度だけ計算します。
このようなTokenの値は通常、UserID、タイムスタンプ、および乱数を使用した暗号化によって生成されます。これにより、Token が分散サービス間で一貫していることが保証され、Token が簡単にクラックされないことも保証されます。
トークンが正常に復号化されると、サーバは解析された値にアクセスすることができます。トークンに含まれるUserIDとタイムスタンプは、UserIDを現在ログインしているUserIDと比較し、タイムスタンプを現在時刻と比較して、有効性を検証するために使用されます。
まとめ
トークンは、より効果的なCSRFの保護方法であり、限り、ページがXSSの脆弱性がトークンをリークしていないとして、CSRF攻撃のインターフェイスが成功することはできません。
しかし、このメソッドの実装では、より複雑です、あなたは各ページのトークンを記述する必要があります、各フォームとAjaxリクエストは、このトークンを運ぶ、各インターフェイスのバックエンドが検証され、ページのトークンとリクエストのトークンが一致していることを確認します。これは、この保護戦略は、統一されたインターセプト処理上の一般的なインターセプトにすることはできませんし、各ページとインターフェイスの必要性は、対応する出力と検証を追加します。このアプローチは、膨大な作業量であり、見逃すことがあります
二重クッキーの検証
CSRF トークンをセッションに保存するのは面倒で、すべてのインタフェースを共通のインターセプ トで統一的に扱うことはできません。
CSRF 攻撃がユーザのクッキーに到達できないという事実を利用して、Ajax とフォーム・リクエストにクッキーの値を運ぶよう要求することができます。
ダブルクッキーは、以下のプロセスを使用します:
- フロントエンドがバックエンドにリクエストを行うと、クッキーは取り出され、URLのパラメータに追加されます。
- バックエンドのインターフェースは、クッキーのフィールドがURLパラメータのフィールドと一致しているかどうかを検証し、一致していなければ拒否します。
この方法は CSRF トークンよりもずっと単純です。フロントエンドとバックエンドの傍受方法によって直接自動化できます。バックエンドの検証もより便利で、Token をクエリして保存する必要がなく、リクエストのフィールドを比較するだけです。
もちろん、この方法は大規模には適用されませんし、大規模なウェブサイトでのセキュリティは、例で説明した理由により、CSRFトークンほど高くはありません。
クロスドメインの場合、フロントエンドはクッキーのフィールドを取得できないので、次のことが起こりました:
- ユーザがウェブサイトwww.a.com、バックエンドのapiドメイン名がapi.a.comである場合、フロントエンドはwww.a.com下、api.a.comのクッキーを取得することができず、二重のクッキー認証を完了することができません。
- そのため、この認証クッキーは、すべてのサブドメインがアクセスできるように、a.comの下にシードされなければなりませんでした。
- どのサブドメインでも、a.com配下のクッキーを変更できます。
- サブドメインはXSS攻撃に対して脆弱です。このサブドメインの下には盗む価値のある情報はありませんが。しかし、攻撃者は a.com の下のクッキーを修正しました。
- 攻撃者は自分の設定したクッキーを直接使って、XSS で攻撃されたユーザに CSRF 攻撃を仕掛け、www.a.com下。
まとめ
二重クッキーによるCSRF防御の利点:
- セッションを使用する必要がなく、適用範囲が広く、実装が簡単です。
- トークンはクライアントに保存され、サーバーにストレスを与えません。
- トークンと比較すると、実装コストが低く、フロントエンドとバックエンドの遮断チェックで統一することができ、むしろ1つのインターフェイスとページを追加する必要があります。
欠点:
- クッキーにフィールドが追加されました。
- サブドメインの分離が困難。
- クッキーの送信のセキュリティを確保するために、この防衛の使用は、サイト全体のHTTPSの方法を確保することが最善である、あなたはHTTPSの使用をカットしていない場合、この方法も危険にさらされます。
Samesite Cookie
ウェブサイトが悪用されるのを防ぐ
先に述べたのは、攻撃されたウェブサイトをどのように保護するかということです。攻撃を防ぐ代わりに、CSRF 攻撃がやってくる可能性があります:
- 攻撃者自身のウェブサイト
- ファイルアップロードの脆弱性があるサイト
- 第三者のフォーラムなどのユーザーコンテンツ。
ハッカー自身から攻撃されるウェブサイトには、防御策はありません。しかし、それ以外のケースでは、自分のウェブサイトが攻撃源として悪用されるのを防ぐにはどうすればいいのでしょうか?
- 予期せぬアップロードを防ぐため、すべてのアップロードインターフェースを厳密に管理します。
X-Content-Type-Options: nosniff
ヘッダーの追加 ハッカーが HTML コンテンツを含むリソースをアップロードし、ウェブページとして解析されるのを防ぎます。- ユーザーがアップロードしたイメージは、ダンプまたは検証してください。ユーザーが記入したイメージリンクを直接使用しないでください。
- 他のユーザーが記入したリンクを開く際には、現在のユーザーにその危険性を知らせる必要があります。