動画

2015年のF8以降、Jonathan GrossとBrent Dormanが、Facebookログインを統合する際のセキュリティを増強する方法を調査しています。

セキュリティのチェックリスト

Facebookログインを使用するすべてのアプリで、以下に挙げられていることは、最低限必要なことであると見なしてください。これ以外にアプリに独自の機能がある場合は、最大限の安全性を確保するための手段を検討する必要があります。セキュリティ保護されていないアプリは、利用者からの信頼を失い、使用されなくなってしまいます。

クライアント側やデコンパイル可能なコードにはApp Secretを含めない

サーバー間のグラフAPI呼び出しにはすべてApp Secretで署名する

クライアントでは一意の短期トークンを使用する

アプリで使用しているアクセストークンが、実際にアプリによって生成されたトークンであると信頼しない

ログインダイアログを使用する際には、stateパラメーターを使用する

可能であれば、公式のFacebook SDKを使用する

Facebookアプリ設定をロックダウンし、アプリの攻撃対象となる領域を制限する

HTTPSを使用する

App Secret

App Secretは、一部のログインフローでアクセストークンを生成するために使用されます。App Secret自体は、信頼されている利用者のみに使用を限定して、アプリの使用を保護することを目的としています。App Secretを使用するとアプリアクセストークンを簡単に作成できます。このトークンはアプリのユーザーに代わってAPIリクエストを行うため、App Secretが外部から不正アクセスされないようにすることが極めて重要です。

そのため、App Secretやアプリアクセストークンをどのコードにも決して含めてはなりません。

最適なセキュリティ保護を提供するには、アプリアクセストークンの使用をアプリのサーバー側に限定することをおすすめします。ネイティブアプリの場合は、アプリは独自のサーバーと通信し、サーバーがアプリアクセストークンを使用してFacebookにAPIをリクエストするように設定することをおすすめします。以上の理由から、アプリダッシュボードの詳細設定にある「アプリタイプ」がNative/Desktopに設定されている場合は、App Secretやアプリアクセストークンがネイティブアプリのバイナリに含まれていると想定され、アプリアクセストークンで署名された呼び出しは処理されません。APIの動作は、アクセストークンが提供されていない場合の動作となります。

appsecret_proofでセキュリティ保護されたサーバー側の呼び出し

FacebookのAPIへのサーバー間の呼び出しにappsecret_proofパラメーターで署名するよう求めると、マルウェアやスパム送信者への露出を制限することができます。app secret証明は、アクセストークンをSHA-256ハッシュ化したものであり、キーとしてapp secretを使用しています。このapp secretは、アプリダッシュボードで[設定] > [基本]と選択すると確認できます。

証明の生成

次のコードサンプルは、PHPで記述した呼び出しのコードです。

$appsecret_proof= hash_hmac('sha256', $access_token.'|'.time(), $app_secret); 

オペレーティングシステムとプログラミング言語によっては、タイムスタンプが浮動小数点数型で返される場合があります。必ず整数値に変換してからapp secret証明を生成してください。また、プログラミング言語によっては、ハッシュがダイジェストオブジェクトとして作成されます。ハッシュは必ず16進数オブジェクトとして表現してください。

証明の追加

結果は、appsecret_proofパラメーターとして追加します。その際には、appsecret_timeを、各呼び出しに対するapp secretハッシュ化の際に使ったタイムスタンプに設定します。

curl \
  -F 'access_token=ACCESS-TOKEN' \
  -F 'appsecret_proof=APP-SECRET-PROOF' \
  -F 'appsecret_time=APP-SECRET-TIME' \
  -F 'batch=[{"method":"GET", "relative_url":"me"},{"method":"GET", "relative_url":"me/accounts"}]' \
  https://graph.facebook.com

タイムスタンプが設定されたapp secret証明は、5分経過すると期限切れと見なされます。そのため、グラフAPI呼び出しを行うたびに、インラインで新しい証明を生成することをおすすめします。

証明の要求

アプリダッシュボードの[設定] > [詳細]セクションの[セキュリティ]セクションで、[app secretが必要]を有効にします。これが有効になると、appsecret_proofが含まれるAPI呼び出しのみが許可されます。

短期トークンとコードフローでセキュリティ保護されたクライアント側の呼び出し

構成によっては、アプリは複数のクライアント間で長期トークンを再利用します。このような構成は使用しないでください。代わりに、コードフローで生成される短期トークンを使用してください(アクセストークンに関するドキュメントをご覧ください)。

トークンのハイジャック

トークンがハイジャックされるしくみを理解するため、あるネイティブiOSアプリがAPI呼び出しを直接実行するのではなく、そのアプリが所有するサーバーとやり取りをし、iOS SDKを使用して生成されるトークンをサーバーに渡す、という例を使用して説明していきます。サーバーはそのトークンを使用してAPI呼び出しを行います。

サーバーがトークンの受け取りに使用するエンドポイントは外部から不正アクセスされる危険性があり、第三者によってアクセストークンがまったく別のアプリに渡されてしまうことも考えられます。これは明らかにセキュリティ面で問題があります。しかし、これから保護する方法はあります。アクセストークンが、そのトークンを使用するアプリから来たものと仮定せず、デバッグエンドポイントを使用してチェックすることによってです。

アクセストークンの有効性を定期的にチェック

Facebook SDKを使用しない場合、アクセストークンが有効かどうかを定期的にチェックしてください。アクセストークンには決められた有効期限がありますが、セキュリティ上の理由でトークンの期限が早めに切れることもあります。アプリでFacebook SDKを使用しない場合、定期的な(少なくとも毎日)トークンの有効性チェックを自分で実装することにより、アプリがセキュリティ上の理由で早めに期限が切れたトークンに依存しないようにすることは極めて重要です。

stateパラメーター

ウェブサイトでFacebookログインダイアログを使っている場合、stateパラメーターは、アプリをクロスサイトリクエストフォージェリ攻撃から守る一意の文字列になります。

制限モードの有効化

制限モードでは、リダイレクトのハイジャックを防ぎ、アプリを安全に保つことができます。すべてのアプリで制限モードを有効化する必要があります。

アプリダッシュボードで制限モードを有効にする前に、Facebookログインの設定で次の操作を行って、現在のリダイレクトトラフィックが引き続き機能していることを確認します。

  • ダイナミックリダイレクトURIを使用するアプリでは、stateパラメーターを使用してダイナミック情報を一部のリダイレクトURIにのみ返すようにします。次に、限定されたリダイレクトURIをそれぞれ[有効なOAuthリダイレクトURI]リストに追加します。

  • 限定された数のリダイレクトURIのみを使用するアプリでは、それぞれのURIを[有効なOAuthリダイレクトURI]リストに追加します。

  • Facebook JavaScript SDKのみを使用するアプリでは、リダイレクトトラフィックはすでに保護されています。追加の操作は必要ありません。

これらの操作の後には、制限モードを必ず有効にしてください。

制限モードのしくみ

制限モードでは、有効なOAuthリダイレクトURIリストとの完全一致を条件にすることによって、リダイレクトURIのハイジャックを防ぎます。例えば、リストにwww.example.comが含まれている場合、制限モードではwww.example.com/tokenは許可されません。有効なOAuthリダイレクトURIリストに存在しない余分なクエリパラメーターを含めることもできません。

HTTPSの使用

インターネットプロトコルには、HTTPではなく、暗号化できるHTTPSを使用します。HTTPSでは、送信されるデータが非公開になり、盗聴攻撃を防ぐことができます。また、広告の導入や悪意のあるコードによって、転送中にデータが改ざんされるのを防ぎます。

2018年10月6日から、すべてのアプリでHTTPSの使用が必須になります。

FacebookログインでJavaScript SDKを有効にする

[JavaScript SDKでログイン]トグルを[はい]にしてJavaScript SDKをログインに使用することを示した場合、SDKをホストするページのドメインは[JavaScript SDKに許可されたドメイン]リストのエントリーの1つと一致する必要があります。これにより、許可されたドメインのコールバックに対してのみ、アクセストークンが返されるようになります。Facebook JavaScript SDKを使用した認証アクションは、HTTPSページだけに対応しています。

2021年8月10日までに作成された既存のJSSDK統合では、このリストは現在の使用状況に基づいた値でバックフィルされます。これ以上の対応は必要ありません。

2021年8月10日より後に作成された新しい統合では、このリストに値を追加する必要があります。

アプリのJSSDKドメインフィールドに*.から始まるドメインが含まれている場合は、完全なドメインURLを入力してセキュリティを強化します。

リダイレクトURIのチェックのしくみ

オープンリダイレクト攻撃は、ログインリクエストに無許可のredirect_uriパラメーターを指定することで、アクセストークンなどのセンシティブな情報がクエリ文字列やリダイレクトURIのフラグメントを通じて漏洩する可能性を引き起こします。

このような攻撃を防止するため、カスタムウェブ統合の場合は、許可するリダイレクトURIをアプリの設定で指定してください。ログインリクエストの処理中に、redirect_uriパラメーターがこのリストのエントリーと照合されます。値が無視される任意のstateパラメーターを除いてすべてのパラメーターが含まれる、完全なURIが完全に一致する必要があります。

アプリ内ブラウザーとJavaScript SDK

JavaScript SDKは通常、ポップアップとコールバックに依存してログインを完了します。ポップアップを表示させない一部のアプリ内ブラウザーでは、失敗する可能性があります。この場合、SDKは自動で(アクセストークンとともに)ポップアップを呼び出したページにリダイレクトしようとします。そのページの完全なURIが[有効なOAuthリダイレクトURI]にリストされている場合にのみ、このリダイレクトを安全に行うことができます。

アプリ内ブラウザーの使用がウェブアプリにとって重要な場合は、ログインページのドメインを[許可されたドメイン]に、パスパラメーターとクエリパラメーターを含む完全なURIを[有効なOAuthリダイレクトURI]にそれぞれ追加する必要があります。アプリへのログインが発生するURIのバリエーションが多い場合は、FB.login()の呼び出しのオプションとしてfallback_redirect_uriを手動で指定できます。そのようにすると、[有効なOAuthリダイレクトURI]リストへの追加が必要なエントリーはその1件のみになります。

Facebookアプリ設定のロックダウン

アプリで使用していない認証フローをすべて有効または無効にして、攻撃対象となる領域を最小化します。

  • クライアントでは、クライアント生成のトークンやサーバー提供の長期トークンではなく、コード生成された短期アクセストークンを使用します。コード生成された短期アクセストークンフローの場合、アプリサーバー側でコードをトークンと交換する必要があります。これにより、ブラウザーでトークンを取得する方法よりもセキュリティが向上します。アプリのセキュリティを高めるには、可能な限りこのフローを使用してください。アプリでこのフローを有効にしておくだけで、利用者のコンピューター上で実行されるマルウェアはアクセストークンを取得して不正な操作を実行できなくなります。詳しくは、アクセストークンに関するドキュメントをご覧ください。

  • アプリで使用していないクライアントOAuthログインを無効にします。クライアントOAuthログインは、OAuthクライアントトークンフローを使用するための一般的なオン/オフスイッチです。FacebookログインSDKなど、アプリでクライアントOAuthフローを使用していないのであれば、このフローを無効にします。ただし、クライアントOAuthログインを無効にしている場合は、アクセストークンのアクセス許可をリクエストできません。この設定は、アプリダッシュボードの[製品] > [Facebookログイン] > [設定]セクションにあります。

  • ウェブOAuthフローを無効にするか、リダイレクト許可リストを指定します。ウェブOAuthログイン設定では、Facebookウェブログインダイアログを使用するどのOAuthクライアントでも、独自のウェブサイトにトークンを返す機能が有効になります。この設定は、アプリダッシュボードの[製品] > [Facebookログイン] > [設定]セクションにあります。カスタムのウェブログインフローを作成しない場合や、FacebookログインSDKをウェブで使用しない場合は、この設定を無効にします。

  • HTTPSの使用を必須にします。この設定により、OAuthリダイレクトにはHTTPSの使用が必須となり、アクセストークンを返すまたはアクセストークンが必要なすべてのFacebook JavaScript SDK呼び出しをHTTPSページからのみ実行することが必要になります。2018年3月以降に作成されたすべての新しいアプリには、デフォルトでこの設定が適用されます。既存のアプリでも、HTTPSのURLのみを使用するよう2018年10月6日までに移行を完了させてください。ほとんどの主要なクラウドアプリホストでは、アプリ用TLS証明書の自動設定が無料で提供されています。アプリを自己ホストしている場合、または利用しているホスティングサービスがデフォルトではHTTPSを提供していない場合は、Let's Encryptからドメインの証明書を無料で入手できます。

  • アプリで埋め込みブラウザーOAuthフローを使用していなければ、無効にします。一部のデスクトップ版とモバイル版のネイティブアプリでは、埋め込みウェブビュー内でOAuthクライアントフローを実行して利用者の認証を行います。アプリでこの認証を行わない場合は、アプリダッシュボードの[製品] > [Facebookログイン] > [設定]セクションでこの設定を無効にします。

  • アプリで使用していないモバイルシングルサインオンフローを無効にします。アプリでiOSログインやAndroidログインを使用しない場合は、[設定] > [基本]の[iOS]と[Android]セクションで、[シングルサインオン]の設定を無効にします。

アプリダッシュボードには、セキュリティ問題につながる恐れのある攻撃対象の領域をなくすために、次のような追加の設定が含まれています。

  • [基本] > [App Secret]。app secretが不正アクセスされた場合は、ここでリセットできます。
  • [基本] > [アプリドメイン]。アプリに代わってFacebookログインを実行する際に使用されるドメインとサブドメインをロックダウンするにはこの設定を使用します。
  • [詳細] > [アプリタイプ]。モバイルまたはデスクトップ向けのネイティブアプリを作成してapp secretを含める場合は、この設定をNative/Desktopに設定します。そうすることでデコンパイルやapp secretの盗難からアプリを保護します。
  • [詳細] > [サーバーIP許可リスト]。app secretを使用したグラフAPI呼び出しの実行元IPアドレスのリストを指定します。この範囲外のIPアドレスから実行される、app secretを使用したグラフAPI呼び出しは失敗します。ユーザーアクセストークンを使用した呼び出しはこの設定の影響を受けません。
  • [詳細] > [IP許可リスト設定を変更]。第三者によってこれらのアプリ設定が特定の範囲に変更されないように、IPアドレスをロックダウンします。施設内ブロードバンドのIP許可リストを設定します。IPアドレスが変わると、アプリ設定を編集できなくなります。
  • [詳細] > [お知らせメール設定を変更]。アプリダッシュボードで設定が変更された場合に、メールアドレス宛にお知らせを送信します。
  • [詳細] > [ストリーム投稿のURLのセキュリティ]。アプリが所有するドメインを指定していないURLの公開を停止します。アプリが他のサイトへのリンクを公開する場合など、状況によっては不要となります。