知らない人のために:CSRF攻撃は、ユーザーのブラウザ(オープンセッションと保存されたCookie)を使用して、悪意のあるデータを含むリクエストを送信します。 これらは、サーバーエクスプロイトではありません。 ユーザーがアクセスできるターゲットサイトに保存されているデータにのみ影響します。
ただし、リラックスしないでください。 CSRFを使用すると、ユーザープロファイルにスパムリンクを追加することから、管理者権限を使用してページを削除したりバックドアを追加したりするなど、多くの不正なトリックを行うことができます。 一般に、このような攻撃により、認証とアクセス権を必要とするすべてにアクセスできます。
しかし、Django開発者は眠っていません。 彼らのおかげで、DjangoはCSRFMミドルウェアを長い間持っていましたが、あまり良くありませんでした。 しかし、議論されていることをよりよく理解するために、まずCSRF攻撃がどのように行われるかを見てみましょう。
CSRF攻撃の構造
CSRF攻撃は、攻撃者が容認できる任意のコンテンツを使用して、ユーザーのブラウザが攻撃対象サイトにリクエスト(GETまたはPOST、ターゲットに応じて)を強制的に送信するように設計されています。
たとえば、送金を行えるフォームがあるオンラインバンキングシステムを想像してください。 アリス(銀行口座番号00000001)にお金を送りたいです。 サイトのフォームに記入して、送信します。 ブラウザは次のリクエストを行います(はい、これは無効なHTTPであることは知っていますが、本質を示したいだけです)。
POST /banking/transfer/ HTTP/1.1
Host: www.andrewsbank.com
amount=100&recipient=00000001
次に、想像してください。セッションを終了せず(多くの人がタブを閉じるか、別のサイトに移動します)、悪意のあるサイトに切り替えます。 その上に大きな「続行」ボタンがあります。 ただし、すべてがそれほど単純ではありません。
<form action = "http://www.andrewsbank.com/banking/transfer/" method = "POST" >
<input type = "hidden" name = "amount" value = "100" />
<input type = "hidden" name = "recipient" value = "00000002" />
<input type = "submit" value = "" />
</form>
ご覧のとおり、この一見無害なボタンは、100個の従来型ユニットをボブ氏(番号00000002)に送信します。
これはそれほど難しい攻撃ではありませんが、銀行もあまり良くありません(アリスに貯金を別の銀行に移すよう勧めます)。 それでも、この例がこれらのタイプの攻撃が何であり、何ができるかを理解するのに十分であることを願っています(実際、このような攻撃は銀行システムで最初に発見されました)。
インターネットには、CSRF攻撃専用のリソースがいっぱいです。 さらに詳細が必要な場合は、ウィキペディアの記事から始めることができます。 ジェフアトウッドの良い記事もあります。
CSRF保護
では、CSRF攻撃からどのように身を守るのでしょうか? これは、次の原則に基づいています。すべての要求がサイトの実際のフォームからのものであることを確認する必要があります。
これを行うには、ユーザーセッションに関連付けられた各フォーム(またはセキュリティ専門家が言うようにnonce )のトークンを作成し、REFERERヘッダーを確認します。 トークンをセッションにバインドする必要があります。そうしないと、攻撃サイトがサイトにリクエストを送信してトークンを取得できます。
セッションをチェックして、トークンが比較的最近発行されたことを確認した場合、これはユーザーからの実際のリクエストであると十分に自信を持って言うことができます。 新しいタイプの攻撃が絶えず出現するため(たとえば、悪意のあるWebサイトがページをiframeに読み込み、ユーザーに1つのボタンのみを表示する(「削除」など))ため、情報セキュリティの分野で100%確信することはできませんが、何もないよりはましです。
DjangoとCSRF
前述のCSRFMミドルウェアに戻ります。 Django 1.1に同梱されているバージョンは次のように機能しました。結果のHTMLを取得し、すべてのフォームの通常の検索に渡し、トークンを含む<input>を追加して、着信POSTリクエストに対してチェックしました。
この方法が単にあまり良くないという事実に加えて、大きな問題は、トークンが外部サイトに行ったものを含む絶対にすべてのフォームに追加されたことでした。 有効なトークンで武装したこれらの外部サイトは、あなたのサイトで攻撃を成功させる可能性があります。
他の問題もありました。 たとえば、ミドルウェアはグローバルなものであるため、SessionMiddlewareに接続する必要があり、1つのアプリケーションに対してのみCSRF保護をアクティブにできませんでした。
何が変わった?
Django 1.2では、CSRFMiddlewareは一部のレギュラーに満足していません。さらに、レギュラーはもはや存在しませんが、多くの新機能があります。
新しい保護では、保護するすべてのフォームに
{% csrf_token %}
を手動で追加する必要があります。 これは、各新規フォームを作成する際にこれを覚えておく必要があることを意味しますが、外部リソースに有効なトークンを送信しないようになりました。
さらに、新しい保護をグローバルに含める必要はありません。 特定のビューにセキュリティを提供するために使用できる新しい
django.views.decorators.csrf.csrf_protect
デコレータが追加され
django.views.decorators.csrf.csrf_protect
。 もちろん、このデコレータはすべてのDjangoアプリケーションで使用されています。つまり、CSRFMiddlewareに接続し忘れた場合でも、管理パネルが保護されるようになりました。
また、CSRF保護は、以前のようにcontribアプリケーションではなく、Djangoコアの一部になりました。 これは、自動エスケープなどのCSRF攻撃に対する保護が優れたWebフレームワークの不可欠な部分であると考えているためです。
最後に、新しい防御では、jungセッションに依存するのではなく、独自のcookieを使用します。したがって、署名付きcookieなど、ユーザーセッションの状態を保存する独自のメカニズムを使用すると、機能します。
欠点
あらゆる種類の魔法の解決策には欠点があります。 新しい保護も例外ではありません。
まず、サイトのサブドメインからの攻撃からCookieが利用できるため、保護されません。 そこからトークンを引き出して、ドメインに送信できます。 明らかな解決策は、見かけほど簡単ではないかもしれませんが、サブドメインにマルウェアがないことを確認することです。
第二に、この保護はカスタムテンプレートレンダラーでは機能しません。 これらを使用する場合、HTMLにトークンを手動で埋め込む必要があります。
django.middleware.csrf.get_token()
は
django.middleware.csrf.get_token()
メソッドを使用できます。
おわりに
CSRFは複雑な問題であり、Djangoではまだ完全には解決されていません(おそらく解決されません)。 ただし、自動エスケープの場合と同様に、目標はプッシュ元となる強固な基盤を提供することです。 新しいCSRF保護は、良い前進です。 今、あなたはそれを使い始めなければなりません!