パートナーが登録したドメインでのみ使用できるAPIを公開しています。そのコンテンツは部分的に公開されています(ただし、私たちが知っているドメインでのみ表示されることが望ましい)が、ほとんどの場合はユーザーに対して非公開です。そう:
このAPIキーは確かに誰にでも表示され、他の方法でパートナーを認証することはなく、REFERERは必要ありません。それでも、それは安全です:
私たちget-csrf-token.js?apiKey=abc123
が要求されたとき:
abc123
データベースでキーを検索し、そのキーの有効なドメインのリストを取得します。
CSRF検証Cookieを探します。存在しない場合は、安全なランダム値を生成して、HTTPのみのセッションCookieに入れます。Cookieが存在した場合は、既存のランダムな値を取得します。
APIキーからCSRFトークンを作成し、Cookieからランダムな値を作成して署名します。(サーバー上にトークンのリストを保持するのではなく、値に署名します。どちらの値も署名されたトークンで読み取ることができますが、問題ありません。)
キャッシュされないように応答を設定し、Cookieを追加して、次のようなスクリプトを返します。
var apiConfig = apiConfig || {};
if(document.domain === 'expected-domain.com'
|| document.domain === 'www.expected-domain.com') {
apiConfig.csrfToken = 'API key, random value, signature';
// Invoke a callback if the partner wants us to
if(typeof apiConfig.fnInit !== 'undefined') {
apiConfig.fnInit();
}
} else {
alert('This site is not authorised for this API key.');
}
ノート:
上記はサーバー側のスクリプトがリクエストを偽造することを防ぎませんが、ブラウザからリクエストされた場合にドメインが一致することを保証するだけです。
JavaScriptの同じ生成元ポリシーにより、ブラウザーがXHR(Ajax)を使用してJavaScriptソースをロードして検査できないことが保証されます。代わりに、通常のブラウザーは<script src="https://our-api.com/get-csrf-token.js?apiKey=abc123">
(または動的に同等の)を使用してのみそれをロードでき、コードを実行します。もちろん、サーバーはクロスオリジンリソースシェアリングも、生成されたJavaScriptのJSONPもサポートしないでください。
ブラウザスクリプトはdocument.domain
、上記のスクリプトをロードする前にの値を変更できます。しかし、同一生成元ポリシーは、のみで、ドメインを短縮することができます取り除く書き換えのように、接頭辞subdomain.example.com
だけにexample.com
、またはmyblog.wordpress.com
にwordpress.com
、あるいは一部のブラウザでbbc.co.uk
しますco.uk
。
JavaScriptファイルがサーバー側のスクリプトを使用してフェッチされた場合、サーバーもCookieを取得します。ただし、サードパーティのサーバーは、ユーザーのブラウザにそのCookieをドメインに関連付けることはできません。したがって、サーバー側スクリプトを使用してフェッチされたCSRFトークンと検証Cookieは、ブラウザーではなく、後続のサーバー側呼び出しでのみ使用できます。ただし、このようなサーバー側の呼び出しにはユーザーCookieが含まれないため、パブリックデータのみをフェッチできます。これは、サーバー側のスクリプトがパートナーのWebサイトから直接こすり取ることができる同じデータです。
ユーザーがログインしたら、ユーザーCookieを好きなように設定します。(ユーザーは、JavaScriptが要求される前にすでにログインしている可能性があります。)
サーバーへの後続のすべてのAPI要求(GETおよびJSONP要求を含む)には、CSRFトークン、CSRF検証Cookie、および(ログオンしている場合は)ユーザーCookieを含める必要があります。これでサーバーは、リクエストが信頼できるかどうかを判断できます。
有効なCSRFトークンの存在により、ブラウザーによってロードされた場合、JavaScriptが予期されたドメインからロードされたことが保証されます。
検証Cookieのない CSRFトークンの存在は、偽造を示します。
CSRFトークンとCSRF検証Cookieの両方が存在しても、何も保証されません。これは、偽造されたサーバー側の要求か、ブラウザーからの有効な要求のいずれかである可能性があります。(サポートされていないドメインからのブラウザからのリクエストではない可能性があります。)
ユーザーCookieの存在は、ユーザーがログオンしていることを保証しますが、ユーザーが特定のパートナーのメンバーであること、またはユーザーが正しいWebサイトを表示していることを保証しません。
CSRF検証CookieのないユーザーCookieの存在は、偽造を示します。
ユーザーCookieの存在により、現在のリクエストがブラウザを介して行われることが保証されます。(ユーザーが不明なWebサイトに資格情報を入力しないと仮定し、ユーザーが独自の資格情報を使用してサーバー側の要求を行うことを気にしないと想定します。)CSRF検証Cookie もある場合、そのCSRF検証Cookieはまた、ブラウザを使用して受信しました。次に、我々は次の場合にも有効な署名でCSRFトークンを持っている、とCSRF検証Cookie内の乱数はそのCSRFトークン内の乱数と一致し、そのトークンのJavaScriptも、CSRF Cookieが設定された非常に同じ以前のリクエスト中に受信されたため、ブラウザも使用されました。これはまた、トークンが設定される前に上記のJavaScriptコードが実行されたことを意味し、その時点で、ドメインは指定されたAPIキーに対して有効でした。
つまり、サーバーは署名済みトークンのAPIキーを安全に使用できるようになります。
いずれかの時点でサーバーが要求を信頼しない場合、403 Forbiddenが返されます。ウィジェットは、ユーザーに警告を表示することでそれに対応できます。
署名付きCSRFトークンと比較するため、CSRF検証Cookieに署名する必要はありません。Cookieに署名しないと、各HTTPリクエストが短くなり、サーバーの検証が少し速くなります。
生成されたCSRFトークンは無期限に有効ですが、検証Cookieとの組み合わせでのみ有効であるため、ブラウザーが閉じられるまで効果的です。
トークンの署名の有効期間を制限できます。ユーザーがログアウトしたときに、OWASPの推奨を満たすために、 CSRF検証Cookieを削除できます。また、複数のパートナー間でユーザーごとの乱数を共有しないようにするには、APIキーをCookie名に追加します。しかし、それでも、新しいトークンが要求されたときにCSRF検証Cookieを簡単に更新することはできません。ユーザーが複数のウィンドウで同じサイトを閲覧し、単一のCookieを共有している可能性があるためです(更新すると、すべてのウィンドウで更新され、その後他のウィンドウのJavaScriptトークンは、その単一のCookieと一致しなくなります)。
OAuthを使用している人は、JavaScriptのアイデアを得たOAuthとクライアント側ウィジェットも参照してください。以下のためにサーバー側の私たちは、ドメインを制限するために、JavaScriptコードに頼ることができないAPIの使用は、私たちは、秘密鍵の代わりに、パブリックAPIキーを使用しています。