次の方法で共有


WinHTTP の概要

このトピックでは、Windows HTTP サービス (WinHTTP) 機能を Microsoft Game Development Kit (GDK) タイトルに使用する方法を説明します。 これは、PC および Xbox 本体の Microsoft Game Development Kit (GDK) タイトルで使用できる下位レベルの HTTP クライアント API です。 これを使用して、通常の HTTP および WebSocket サービス エンドポイントを作成できます。

これは下位レベルであるため、タイトルの安全で堅牢な通信を実現できるようにするには、その他の考慮事項や実装すべき手順があります。 タイトルの実装は、すべての 通信セキュリティのベスト プラクティス (NDA トピック)認可が必須です に従うことをお勧めします。

WinHTTP のバージョン間の違い

一般的に、Microsoft Game Development Kit (GDK) タイトルは、Win32 アプリケーションの WinHTTP と同じ方法で WinHTTP とやり取りします。

Microsoft Game Development Kit (GDK) タイトル向けに開発する場合、WinHTTP にはフラット C/C++ API のみを使用できます。 これは、HTTP 機能をすべて、この HTTP クライアント API で構築する必要があることを意味しています。

Xbox 本体のプロジェクトに WinHTTP を追加する

コンソールの、ソース ファイルで #include <winhttp.h> を使用します。 Winhttp.lib に直接リンクするのではなく XGamePlatform.lib にリンクする必要があります。 WINAPI_PARTITION_GAMES API ファミリの下にある API のみが、Microsoft Game Development Kit (GDK) タイトルで動作します。 Windows PC では、Winhttp.lib へのリンクを続行する必要があります。

WinHTTP を Microsoft Game Development Kit (GDK) タイトルに統合する方法の例については、SimpleWinHttp のサンプルを参照してください。 これは、WinHttpManager クラスを含む、独自の WinHTTP 実装のための強固で完全に準拠した出発点を提供します。 これは、単純な非同期 API サーフェスを公開します。

ネットワークの初期化と WinHTTP

Microsoft Game Development Kit (GDK) タイトルでは、WinHttpOpen を初めて呼び出す前に、ネットワーク スタックが初期化されていることを確認する必要があります。 タイトルの起動処理中に WinHttpOpen があまりにも早く呼び出された場合、WinHttpOpen やそれ以降の WinHTTP 呼び出しが失敗したり、非決定的な方法でクラッシュする可能性があります。 ネットワークが初期化済みと宣言される前は、要求が成功したように見えても実際には失敗している場合や、その逆の場合が発生する可能性があります。 ネットワーク スタックの準備ができていることを確認する方法の詳細については、「ネットワークの初期化と接続」を参照してください。

タイトルの一時停止/再開と WinHTTP

タイトルの一時停止通知を受け取ったら、タイトルはすべての WinHTTP ハンドルを閉じるプロセスを開始する必要があります。 WinHTTP ハンドルのクリーンアップは非同期です。 したがって、ハンドルは次の順序で閉じる必要があります。すべての要求ハンドル、すべての接続ハンドル、すべてのセッションハンドルの順です。 WinHTTP ハンドルのクリーンアップが非同期であるのは、通知スレッドの安全性を保証するためです。 非同期でも、WinHTTP ハンドルのクリーンアップは一期間遅延されません。 これにより、1 秒間の延期期間タイムアウト内に簡単に収まります。

再開時には、タイトルは「ネットワークの初期化と WinHTTP」で説明したのと同じ手順に従って、ネットワークが準備完了状態に戻るのを待ってから WinHTTP の使用を続行する必要があります。 一時停止イベントと再開イベントの間に長い時間が経過したために、WinHTTP API が確定的な状態に戻る前にネットワークがもう一度安定することが必要な場合があります。

メモリと同時実行に関する考慮事項

WinHTTP 内の非同期状態が正しく動作するようし、メモリバジェット内に収まるようにするには、同時 WinHTTP 要求の数は常に 8 未満に保つ必要があります。 この制限は、Xbox サービス API と XCurl からの呼び出しを含む、タイトル ランタイム内のすべての同時操作に適用されます。

WinSock のメモリに関する考慮事項 の拡張として、データを受信するときは、データをからユーザーモードプロセスに転送するために、常に WinHttpReadData の保留バッファがあることを確認する (またはWinHttpQueryDataAvailable 呼び出しからのコールバックを待機している) 必要があります。 カーネル モードのメモリ プールを可能な限り迅速に実行し、HTTP 操作によって消費されるカーネル メモリの量を最小限に抑えます。

WinHttpQueryHeaders ゲッター関数には一時的なメモリ割り当てが必要です。 内部使用のために lpdwBufferLength パラメーターに等しいサイズのスクラッチ バッファーを割り当てます (そして関数が戻る前にそれを解放します)。 このため、WINHTTP_NO_OUTPUT_BUFFER 二重呼び出しパターンを使用して、スクラッチ バッファーのサイズを最小限に抑え、一度に行う WinHttpQueryHeaders への同時呼び出しの数を制限して、システムの不安定性につながる可能性のある過度のシステム メモリ使用を回避する必要があります。 ヘッダーのデフォルトの最大サイズは、WINHTTP_OPTION_MAX_RESPONSE_HEADER_SIZE WinHTTP オプションで指定されている 64KB であることに注意してください。

WinHttpOpen に関する考慮事項

フラグ

次の表に示すフラグを WinHttpOpen に渡す必要があります。

パラメーター
dwAccessType WINHTTP_ACCESS_TYPE_AUTOMATIC_PROXY
pszProxyW WINHTTP_NO_PROXY_NAME
pszProxyBypassW WINHTTP_NO_PROXY_BYPASS
dwFlags WINHTTP_FLAG_SECURE_DEFAULTS

WINHTTP_ACCESS_TYPE_AUTOMATIC_PROXYWINHTTP_NO_PROXY_NAMEWINHTTP_NO_PROXY_BYPASS を組み合わせることで、Microsoft Game Development Kit (GDK) プラットフォームは、Fiddler などのプロキシと他のエッジケース ネットワーク環境を自動的に処理できます。

WINHTTP_FLAG_SECURE_DEFAULTS フラグは、推奨されるセキュリティで保護された接続動作を設定することで、Microsoft Game Development Kit (GDK) タイトルがセキュリティのベスト プラクティスに準拠するのをサポートする、特別に設計された新しいフラグです。 Xbox One 本体で利用でき、今後の Windows OS 更新プログラムで Windows PC 上でも利用できるようになります。 既存の Windows OS バージョンで WINHTTP_FLAG_SECURE_DEFAULTS を渡そうとすると、パラメーターが無効になります。 このフラグには重大な副次的影響があります。このフラグには WINHTTP_FLAG_ASYNC フラグが暗黙のうちに含まれているため、WinHTTP を非同期モードに強制します。 このフラグをサポートしていない Windows PC OS のバージョンでは、代わりに WINHTTP_FLAG_ASYNC を渡して、残りの WinHTTP 実装の違いを最小限にする必要があります。

注意

WINHTTP_FLAG_SECURE_DEFAULTS フラグには、WinHttpOpenRequest に渡される一致する WINHTTP_FLAG_SECURE フラグが必要であり、暗号化されていない HTTP リクエストをブロックします。 内部デバッグおよびテスト用の開発キットでは、追加の WinHTTP セッションハンドルを作成し、WINHTTP_FLAG_ASYNC フラグをWinHttpOpen に指定できます。 これにより、WINHTTP_FLAG_SECURE フラグを WinHttpOpenRequest に指定しないことで、開発中に暗号化されていない HTTP リクエストを作成できるようになります。 タイトルが RETAIL に表示するリクエストの動作と一致させるために、デバッグ以外のトラフィックには WINHTTP_FLAG_SECURE_DEFAULTS で開いたセッション ハンドルを引き続き使用する必要があります。

WINHTTP_OPTION_SECURE_PROTOCOLS

WinHttpOpen で新しいセッション ハンドルを作成した後は、オプション WINHTTP_OPTION_SECURE_PROTOCOLS を指定して WinHttpSetOption を呼び出し、このセッション ハンドルが使用される一致する URL に対して XNetworkingQuerySecurityInformationForUrlUtf16Async を呼び出すことによって取得された対応する XNetworkingSecurityInformation::enabledHttpSecurityProtocolFlags を渡す必要があります。 また、 TLS/SSL ハンドシェイクの検証 ステップで使用するために、XNetworkingSecurityInformation 構造をコンテキストオブジェクトに保存する必要があります。

セッション ハンドルをキャッシュする

WinHttpOpen を使用して作成される HTTP セッション ハンドルは、メモリ コストが高く、最初の HTTP 要求を遅らせる大きな起動コストが発生します。 これらのコストを回避するため、できるだけタイトル内で HTTP セッション ハンドルをキャッシュすることをお勧めします。

ただし、セッション ハンドルの WINHTTP_OPTION_SECURE_PROTOCOLS オプションを変更することはできません。 したがって、異なるセキュア プロトコル フラグごとに異なるセッション ハンドルが使用されるよう、WinHTTP セッション ハンドルにマップされる XNetworkingSecurityInformation::enabledHttpSecurityProtocolFlags の値のキャッシュを保持する必要があります。

タイトルで保持するキャッシュは、一時停止通知を受け取ったらクリアし、再開時には (ネットワークが初期化されるまで待った後) 最初から再構築する必要があります。

WinHttpConnect に関する考慮事項

セッション ハンドルとは異なり、WinHttpConnect によって作成される接続ハンドルは、キャッシュしないようにする必要があります。 新しい要求や再試行のたびに、新しいハンドルを作成する必要があります。 WinHTTP 接続ハンドルは、その名前に反して、基になるサーバー伝送制御プロトコル (TCP) 接続とは関係ありません。 WinHTTP では、セッション ハンドルを使用して基になるサーバー接続の有効期間が管理され、可能であれば、新しい接続ハンドルには開かれているサーバー接続が自動的に再利用されます。

URL の正規化

WinHTTP では、すべての URL が、a から z、A から Z、0 から 9 の US-ASCII 文字に正規化されることが想定されています。 正規化の詳細については、「Uniform Resource Locators (URLs) in WinHTTP (WinHTTP での Uniform Resource Locator (URL))」を参照してください。 タイトルが使用するURLは、可能な限り正規化された形でハード コーディングすることをお勧めします。 これにより、WinHttpCrackUrlWinHttpCreateUrl 関数を使用してURLを動的に正規化する際に発生するメモリの確保やパフォーマンスの問題を回避できます。

URL の分割

WinHTTP は、パスとオブジェクトが WinHttpOpenRequest に渡される一方で、null 文字で終端するホスト名の文字列を WinHttpConnect に渡す必要があります。 つまりタイトルでは、一部の場所ではホスト名とパスが連結された完全な URL を渡す必要があり、他の場所ではホスト名またはパスのみを渡す必要があります。 WinHttpCrackUrlWinHttpCreateUrl を使用して URL を動的に連結または分割する必要がないように、両方をタイトル内にハード コーディングすることをお勧めします。

WinHttpOpenRequest に関する考慮事項

WinHTTP 接続ハンドルと同様に、WinHttpOpenRequest 関数によって作成される WinHTTP 要求ハンドルもキャッシュしないようにしてください。 新しい要求や再試行のたびに、新しいハンドルを作成する必要があります。

セキュリティに関するベスト プラクティスとして、タイトルは、WinHttpOpenRequest 関数を呼び出すときは常に dwFlags パラメーターの WINHTTP_FLAG_SECURE フラグを渡す必要があります。

Xbox サービス トークンの取得と適用

Microsoft Game Development Kit (GDK) タイトルには、トークンが自動的には挿入されません。 代わりに、タイトルは Microsoft Game Development Kit (GDK) の XUser API を使用して、Xbox サービスの認証トークンと署名を取得する必要があります。 タイトルはユーザーを獲得したら、XUserGetTokenAndSignatureUtf16Async を呼び出して、各要求に対してトークンと署名の文字列を取得する必要があります。 その後、これらの 2 つの文字列を WinHttpAddRequestHeadersExWinHttpSendRequest、または WinHttpAddRequestHeaders の呼び出しにヘッダーとして渡す必要があります。

正しい署名を生成するには、XUserGetTokenAndSignatureUtf16Async は、タイトルがすべての見出しと本文全体を送付することを想定します。 大きな body を持つ POST または PUT の場合、タイトルは、パートナー センター で設定された body のサブセットを渡すことができます。 詳細については、「Web サービス (NDA トピック)認可が必須です」をご覧ください。 現時点では、Xbox ネットワークはこの構成を取得するためのメカニズムを提供していません。 クライアントは値をハードコードするか、カスタムの、タイトル固有のエンドポイントを通じて値を取得する必要があります。

XUserGetTokenAndSignatureUtf16Async は、必要なすべてのキャッシュを内部的に実行するので、再試行を含む HTTP を試みるたびに呼び出す必要があります。 タイトルが HTTP 要求に対して HTTP 応答状態コード "401 権限がありません" を受信した場合は、要求を再試行し、Xbox サービス認証トークンの更新を強制的に実行する必要があります。 これを行うには、XUserGetTokenAndSignatureUtf16Async で新しいトークンを取得し、XUserGetTokenAndSignatureOptions:: ForceRefresh 列挙値を渡します。

タイトルに XUserGetTokenAndSignatureUtf16Asyncの呼び出しによって取得された XUserGetTokenAndSignatureUtf16Data が含まれる場合、タイトルは XUserGetTokenAndSignatureUtf16Data::Token ならびに XUserGetTokenAndSignatureUtf16Data::Signature を変換して、WinHTTP に渡すため HTTP ヘッダーにする必要があります。 新しい WinHTTP API、WinHttpAddRequestHeadersEx は、Microsoft Game Development Kit (GDK) タイトルの複雑性を低減することを目的として追加されました。 この新しい API を使用する方法の例を次に示します。 この新しい API は、Xbox One 本体で利用できます。また、今後の Windows OS 更新プログラムで Windows PC でも利用できるようになります。 コンソールでは、余分な割り当てと文字列の形式の変更を回避するため、WinHttpAddRequestHeadersEx を使用することをお勧めします。

HRESULT
AddTokenAndSignatureDataToHttpRequest(
   XUserGetTokenAndSignatureUtf16Data* userTokenAndSignatureData,
   HINTERNET requestHandle
   )
{
   WINHTTP_EXTENDED_HEADER winhttpHeader[2];
   winhttpHeader[0].pwszName = L"Authorization";
   winhttpHeader[0].pwszValue = userTokenAndSignatureData->token;
   winhttpHeader[1].pwszName = L"Signature";
   winhttpHeader[1].pwszValue = userTokenAndSignatureData->signature;
   return HRESULT_FROM_WIN32(WinHttpAddRequestHeadersEx(
       m_handshakeRequest,
       WINHTTP_ADDREQ_FLAG_ADD,
       WINHTTP_EXTENDED_HEADER_FLAG_UNICODE,
       0,
       tokenAndSignature->signatureCount ? 2 : 1,
       winhttpHeader));
}

注意

デバイスまたはサインイン アカウントは、設定されているサンドボックスにアクセスできる必要があります。 それ以外の場合、XUserGetTokenAndSignatureUtf16Data は失敗します。

Xbox ネットワーク セキュリティ承認リスト (NSAL) の使用

Xbox ネットワークでは、クライアントが Web サービスへの安全かつ認証された接続を確立できるようにするために、NSAL を使用します。 タイトルは、パートナー センターでのタイトル構成の一部として NSAL の内容を管理します。 詳細については、「パートナー センターで Web サービスをセットアップする (NDA トピック)認可が必須です」を参照してください。 NSAL の構成はタイトルごとに自動的にダウンロードされ、適切な Xbox サービス トークンの生成と、タイトル固有のエンドポイントに対する証明書のピン留めの実行の両方に使用されます。

WinHTTP 非同期状態マシンに関する考慮事項

WinHTTP 非同期状態マシンは、本体でも Windows PC と同じです。 コールバック関数を 1 つ以上の通知に登録するには、WinHttpSetStatusCallback 関数を使用します。 WinHTTP は比較的情報量が多く、実行されていることについて透過的であるため、デバッグの場合は dwNotificationFlags パラメーターに WINHTTP_CALLBACK_FLAG_ALL_NOTIFICATIONS フラグを使用することをお勧めします。 ほとんどの通知については、自ら何もする必要はありませんが、データをログに記録すると、根本原因となる問題の解決に役立ちます。

WinHTTP では、通知に 1 つのスレッドが使用されます。 タイトルは、プロセス内のすべての HTTP 要求の進行を妨げないよう、可能な限り、通知関数をブロックしないようにしてください。 サービスされていない通知は、カーネル モードのメモリを増やし、クラッシュにつながる可能性もあります。

WinHTTP では、送信バッファーや受信バッファーはコピーされず、対応する完了コールバックまでこれらのバッファーを割り当てられた状態にしておく必要があります。 WinHttpSendRequest を呼び出し、対応する WINHTTP_CALLBACK_STATUS_SENDREQUEST_COMPLETE 通知を受け取るまで、送信バッファーを割り当てたまま有効な状態にしてください。 同様に、WinHttpReadData を呼び出すたびに、対応する WINHTTP_CALLBACK_STATUS_READ_COMPLETE 通知を受け取るまで、受信バッファーを割り当てたまま有効な状態にしてしてください。 また、スタックの枯渇につながる可能性のある再帰の問題を回避するため、使用する受信バッファーのサイズは 8 KB 以上にすることをお勧めします。

タイトルは、非同期WinHttpQueryDataAvailable/WinHttpReadDataサイクルを継続し、WinHTTP コールバックを一定期間ブロックしないことにより、WinHTTP バッファーが正しく空になるようにする必要もあります。

トランスポート層セキュリティ (TLS)/Secure Sockets Layer (SSL) ハンドシェイクの検証

セキュリティに関するベスト プラクティスとして、タイトルで TLS/SSL ハンドシェイクの追加の検証を実行し、TLS 1.2 のみを使用する必要があります。

追加の検証は、WINHTTP_CALLBACK_STATUS_SENDING_REQUEST 通知内で実行されます。 この通知内で、XNetworkingVerifyServerCertificate 関数を呼び出して、以前の対応する XNetworkingQuerySecurityInformationForUrlUtf16Asyncの呼び出しから取得された、 XNetworkingSecurityInformation 構造を渡す必要があります。 証明書チェーンが無効な場合、この関数は失敗します。 コールバックが完了する前に直ちに WinHTTP ハンドルを閉じて、漏洩したサーバとの間でデータが転送されないようにしてください。

証明書チェーンを検証するだけでなく、コンソールの Fiddler 機能を使用するには、XNetworkingVerifyServerCertificate の機能が必要です。

WinHTTP のデバッグ

Fiddler は、WinHTTP トラフィックを表示およびデバッグするための便利なツールです。 Fiddler でタイトルのトラフィックをキャプチャするには、WINHTTP_ACCESS_TYPE_AUTOMATIC_PROXYWINHTTP_NO_PROXY_NAMEWINHTTP_NO_PROXY_BYPASS フラグを WinHttpOpen に渡す必要があります。 また、WINHTTP_CALLBACK_STATUS_SENDING_REQUEST 通知のコールバック内で XNetworkingVerifyServerCertificate に呼び出す必要があります。

注意

HTTP モニターは Microsoft Game Development Kit (GDK) タイトルでは動作しません。

関連項目

Windows HTTP サービス (WinHTTP)

XSAPI C の概要 (セキュリティで保護されたリンク)

XUser

パートナー センターで Web サービスをセットアップする (NDA トピック)認可が必須です

Xbox One 本体上の Fiddler

通信セキュリティのベスト プラクティスの概要 (NDA トピック)認可が必須です