web-dev-qa-db-ja.com

OAuth2クロスサイトリクエストフォージェリ、および状態パラメーター

http://tools.ietf.org/html/draft-ietf-oauth-v2-30#section-10.12 は言う:

クライアントはCSRF保護を実装する必要があります[...]通常、リダイレクトURIエンドポイントに送信されるリクエストに、リクエストをユーザーエージェントの認証済み状態にバインドする値(たとえば、セッションCookieのハッシュ[... ]

ただし、実装についてはあまり触れていません。それはCSRFがどのように機能するかについていくつかの光を置くだけです:

クライアントのリダイレクトURIに対するCSRF攻撃により、攻撃者は独自の認証コードまたはアクセストークンを挿入できます。これにより、クライアントは被害者ではなく、攻撃者の保護されたリソースに関連付けられたアクセストークンを使用する可能性があります(被害者の銀行口座情報を攻撃者によって制御されている保護されたリソース)

しかし、「むしろ」という言葉の使用は、この発言を価値のないものにします。

GAEで「状態」を実装する方法を考えています(Webapp2を使用)。ハッカーがOAuth2に対してCSRFを使用する方法から始めるのが最も簡単です。私はこの問題について1つだけ良い記事を見つけました: "Cross Site Request Forgery and OAuth2"

残念ながら、このブログ投稿はよく書かれていますが、OAuth2の説明以外に情報はあまりありません。例は機能せず、Springも知りません。それでも、興味深い推奨事項が1つ見つかりました:OAuth2プロバイダーに接続するサーバーは、ランダムなセッションキーとして「状態」を保存する必要があります(たとえば、「this_is_the_random_state」: "this_doesn't_matter")であり、静的キーの下の値ではありません(例: "state": "random_state_string")。


私の質問は、「状態」の正気な実装は何ですか?

  • ランダムに生成された状態をハッシュする必要がありますか、それとも同じ値を保存してOAuth2プロバイダーに送信できますか?
  • セッションバックエンドが安全なCookieかサーバー側のストレージテクノロジー(GAE Memcacheやデータベースなど)の場合、違いはありますか?
  • 状態をキーとして保存する必要がありますか?
  • 状態には有効期間がありますか、それともセッション(存在する場合)のライフタイムは十分ですか?
39

この問題を単純化します。 Cross-Site Request Forgery および Clikjacking 攻撃は、被害者のブラウザに意に反してアクションを実行させる可能性があるため、有用です。

OAuth v2 RFC での10.12. Cross-Site Request Forgeryおよび10.13. Clickjackingの言及は、基本的に同じ懸念事項です。攻撃者が被害者のブラウザを強制的に認証できる場合、被害者のブラウザに他のアクションを実行させるのに役立つ手順です。

   in a clickjacking attack, an attacker registers a legitimate client
   and then constructs a malicious site in which it loads the
   authorization server's authorization endpoint web page in a
   transparent iframe overlaid on top of a set of dummy buttons, which
   are carefully constructed to be placed directly under important
   buttons on the authorization page.  When an end-user clicks a
   misleading visible button, the end-user is actually clicking an
   invisible button on the authorization page (such as an "Authorize"
   button).  This allows an attacker to trick a resource owner into
   granting its client access without their knowledge.

出典: 10.13。クリックジャッキング

たとえば、Stack OverflowはOAuthを使用し、この攻撃に対して脆弱です。StackOverflowにアクセスし、現在OAuthプロバイダーにログインしている場合、 StackOverflowにログインします。そのため、攻撃者はiframe内にStack Oveflowをロードすることにより、被害者に自動的にログインできます。StackOverflowにもCSRFの脆弱性がある場合( そしてそれがありました! )、攻撃者は被害者のブラウザを自動的に認証し、stackoverflow.comに対してCSRF(Session Riding)、クリックジャッキング、またはXSS攻撃をChained Attack

14
rook

この攻撃のしくみを見てみましょう。

攻撃

  1. client'sのWebサイトにアクセスし、そのクライアントにOAuthを使用してservice providerにアクセスすることを承認するプロセスを開始します

  2. クライアントがサービスプロバイダーに、私の代わりにアクセスをリクエストする許可を求めます。これは許可されます

  3. サービスプロバイダーのWebサイトにリダイレクトされます。アクセスを許可するために、通常はユーザー名/パスワードを入力します。

  4. 代わりに、私はこのリクエストをトラップ/防止し、そのURLを保存します

  5. どういうわけか、代わりにそのURLにアクセスしてもらいます。自分のアカウントでサービスプロバイダーにログインしている場合、資格情報を使用して認証コード

  6. 認証コードはアクセストークンと交換されます

  7. これで、クライアントのmyアカウントに、yourアカウントへのアクセスが許可されましたサービスプロバイダー

では、stateパラメータを使用してこれを防ぐにはどうすればよいですか?

防止

  1. クライアントは、元のユーザーのアカウント(たとえば、ユーザーのセッションキーのハッシュ)に何らかの形で基づいた値を作成する必要があります。 uniqueであり、元のユーザーに関するいくつかのプライベート情報を使用して生成されている限り、それは何であってもかまいません。

  2. この値は、上記のステップ3からのリダイレクトでサービスプロバイダーに渡されます。

  3. 保存したURL(上記の手順5)にアクセスします

  4. 認証コードが発行され、yourセッションでクライアントに送り返されますstateパラメータとともに

  5. クライアントは、yourセッション情報に基づいてstate値を生成し、それを送り返されたstate値と比較します認可リクエストからサービスプロバイダーへ。この値はリクエストのstateパラメータと一致しません。そのstate値はmyセッションに基づいて生成されたためです情報なので、拒否されます。

あなたの質問

  • ランダムに生成された状態をハッシュする必要がありますか、それとも同じ値を保存してOAuth2プロバイダーに送信できますか?

ポイントは、攻撃者が特定のユーザーに固有の状態値を生成できないようにすることです。それは推測できないはずです。

  • セッションバックエンドがセキュアCookieまたはサーバー側ストレージ(GAE Memcacheまたはデータベース内)の場合、違いはありますか?

これは重要ではないと思います(あなたを正しく理解していれば)

  • 推奨されるように状態をキーとして保存する必要がありますか?

どういう意味かわかりません。

  • 状態に有効期間、またはセッション(存在する場合)の存続期間は十分ですか?

はい、状態には有効期限があります。必ずしもセッションに関連付ける必要はありませんが、関連付けることができます。

43
Wayne Burkett

OAuth2の状態パラメーターの重要性 から取得:

これは、OAuth 2の「状態」オブジェクトが関係する場所です。認証エンドポイントにPOSTするときに常に推測不可能な状態を送信することにより、クライアントアプリケーションは、アクセスコードが取得したことを確認できます。承認サーバーからのリクエストは、他のクライアントアプリケーションではなく、承認サーバーからのリクエストに応答します。

例:

https://example.com/as/authorization?client_id=client1&response_type=code&scope=openid &state=7tvPJiv8StrAqo9IQE9xsJaDso4

このようなCSRF攻撃の防止に状態パラメーターが役立つようにするには、OAuthサーバーへのすべての要求に、クライアントがそれ自体を認証するために使用できる状態パラメーターを含める必要があります。状態パラメーターを送信するとき、 OAuth仕様では、Authorization Serverがそれをクライアントに逐語的に返す必要があることを規定しています。これは、クライアントのコールバックURLに追加することによって行われます。クライアントはこの状態を受け取り、検証可能な状態のリダイレクトのみを受け入れます。これがメモリに保持されているディクショナリであるか、再計算可能な値であるかは、クライアントプログラマ次第です。

これを実装する方法を決定するとき、1つの提案は、簡単に検証できる変数(クライアントIDやセッションCookieなど)とともに秘密鍵を使用して、ハッシュ値を計算することです。これにより、秘密鍵がないと推測が困難なバイト値になります。このようなHMACを計算した後、base-64でエンコードし、OAuthサーバーに状態パラメーターとして渡します。別の提案は、現在の日付と時刻をハッシュすることです。これには、アプリケーションで時間を節約する必要があります。それを検証するため、または有効期間のスライドを許可するための送信の例(例:TOTPの使用)

Hersは単純なPythonの例で、datetimeを使用して2番目の提案を使用しています。

def generate_state_parameter(client_id, private_key):
    date = datetime.datetime.today()
    raw_state = str(date) + client_id
    hashed = hmac.new(private_key, raw_state, sha1) state = base64.b64encode(hashed.digest())
    return (state, date)
4
Aydin K.