SO_REUSEADDRとSO_EXCLUSIVEADDRUSEの使用

セキュリティで保護された高レベルのネットワーク インフラストラクチャの開発は、ほとんどのネットワーク アプリケーション開発者にとって優先事項です。 ただし、ソケットのセキュリティは、完全にセキュリティで保護されたソリューションを検討する際に非常に重要であるにもかかわらず、見落とされることが多いです。 ソケット セキュリティは、特に、別のアプリケーション プロセスによって以前にバインドされたのと同じポートにバインドされるプロセスを処理します。 以前は、ネットワーク アプリケーションが別のアプリケーションのポートを "乗っ取る" 可能性があり、"サービス拒否" 攻撃やデータ盗難につながる可能性があります。

一般に、ソケット セキュリティはサーバー側のプロセスに適用されます。 具体的には、ソケット セキュリティは、接続を受け入れ、IP データグラム トラフィックを受信するすべてのネットワーク アプリケーションに適用されます。 通常、これらのアプリケーションは既知のポートにバインドされ、悪意のあるネットワーク コードの一般的なターゲットです。

クライアント アプリケーションは、このような攻撃の対象になる可能性は低くなります。影響を受けにくいためではなく、ほとんどのクライアントが静的な "サービス" ポートではなく "エフェメラル" ローカル ポートにバインドされるためです。 クライアント ネットワーク アプリケーションは、魅力的なアーキテクチャ上の理由がない限り、常にエフェメラル ポートにバインドする必要があります (バインド関数を呼び出すときに name パラメーターによって指される SOCKADDR 構造体でポート 0 を指定します)。 エフェメラル ローカル ポートは、ポート 49151 より大きいポートで構成されます。 専用サービス用のほとんどのサーバー アプリケーションは、ポート 49151 以下の既知の予約ポートにバインドされます。 そのため、ほとんどのアプリケーションでは、通常、クライアント アプリケーションとサーバー アプリケーション間のバインド要求の競合はありません。

このセクションでは、さまざまな Microsoft Windows プラットフォームの既定のセキュリティ レベルと、特定のソケット オプション ネットワーク アプリケーションのセキュリティに与える影響と影響SO_REUSEADDR SO_EXCLUSIVEADDRUSE について説明します。 拡張ソケット セキュリティと呼ばれる追加機能は、Windows Server 2003 以降で使用できます。 これらのソケット オプションと強化されたソケット セキュリティの可用性は、次の表に示すように、Microsoft オペレーティング システムのバージョンによって異なります。

プラットフォーム SO_REUSEADDR SO_EXCLUSIVEADDRUSE ソケットセキュリティの強化
Windows 95 利用可能 利用不可 利用不可
Windows 98 利用可能 利用不可 利用不可
Windows Me 利用可能 利用不可 利用不可
Windows NT 4.0 利用可能 Service Pack 4 以降で使用可能 利用不可
Windows 2000 利用可能 利用可能 利用不可
Windows XP 利用可能 利用可能 利用不可
Windows Server 2003 利用可能 利用可能 利用可能
Windows Vista 利用可能 利用可能 利用可能
Windows Server 2008 利用可能 利用可能 利用可能
Windows 7 およびそれ以降 利用可能 利用可能 利用可能

SO_REUSEADDRの使用

SO_REUSEADDR ソケット オプションを使用すると、ソケットは別のソケットで使用されているポートに強制的にバインドできます。 2 番目のソケットは、optname パラメーターを SO_REUSEADDR に設定し、optval パラメーターを TRUE のブール値に設定して setsockopt を呼び出してから、元のソケットと同じポートで bind を呼び出します。 2 番目のソケットが正常にバインドされると、そのポートにバインドされているすべてのソケットの動作が不確定になります。 たとえば、同じポート上のすべてのソケットが TCP サービスを提供する場合、ポート経由の受信 TCP 接続要求が正しいソケットによって処理されることを保証することはできません。動作は非決定論的です。 悪意のあるプログラムは 、SO_REUSEADDR を使用して、標準のネットワーク プロトコル サービスに既に使用されているソケットを強制的にバインドして、それらのサービスへのアクセスを拒否することができます。 このオプションを使用するために特別な特権は必要ありません。

サーバー アプリケーションが同じポートにバインドする前に、クライアント アプリケーションがポートにバインドすると、問題が発生する可能性があります。 SO_REUSEADDR ソケット オプションを使用してサーバー アプリケーションを強制的に同じポートにバインドする場合、そのポートにバインドされているすべてのソケットの動作は不確定になります。

この非決定論的動作の例外は、マルチキャスト ソケットです。 2 つのソケットが同じインターフェイスとポートにバインドされ、同じマルチキャスト グループのメンバーである場合、データは任意に選択されたソケットではなく、両方のソケットに配信されます。

SO_EXCLUSIVEADDRUSEの使用

SO_EXCLUSIVEADDRUSE ソケット オプションが導入される前は、ネットワーク アプリケーション開発者が、ネットワーク アプリケーションが独自のソケットがバインドされているポートに悪意のあるプログラムがバインドされるのを防ぐためにできることはほとんどありませんでした。 このセキュリティの問題に対処するために、Windows ソケットでは SO_EXCLUSIVEADDRUSE ソケット オプションが導入されました。このオプションは、Service Pack 4 (SP4) 以降Windows NT 4.0 で使用できるようになりました。

SO_EXCLUSIVEADDRUSE ソケット オプションは、Windows XP 以前の Administrators セキュリティ グループのメンバーのみが使用できます。 この要件が Windows Server 2003 以降で変更された理由については、この記事の後半で説明します。

SO_EXCLUSIVEADDRUSE オプションは、ソケットがバインドされる前に optname パラメーターを SO_EXCLUSIVEADDRUSE に設定し、optval パラメーターを TRUE のブール値に設定して setsockopt 関数を呼び出すことによって設定されます。 オプションを設定すると、後続の バインド 呼び出しの動作は、各 バインド 呼び出しで指定されたネットワーク アドレスによって異なります。

次の表は、2 番目のソケットが特定のソケット オプションを使用して最初のソケットによって以前にバインドされたアドレスにバインドしようとしたときに、Windows XP 以前で発生する動作を示しています。

注意

次の表の "ワイルドカード" は、指定されたプロトコルのワイルドカード アドレスを示しています (IPv4 の場合は "0.0.0.0"、IPv6 の場合は "::" など)。 "Specific" は、インターフェイスに割り当てられた特定の IP アドレスを示します。 表のセルは、バインドが成功した ("成功") か、エラーが返されるか ( WSAEADDRINUSE エラーの場合は "INUSE") かを示します。 WSAEACCES エラーの場合は "ACCESS" です)。

最初の バインド 呼び出し 2 回目の バインド 呼び出し
Default SO_REUSEADDR SO_EXCLUSIVEADDRUSE
ワイルドカード 固有 ワイルドカード 固有 ワイルドカード 固有
Default ワイルドカード INUSE INUSE Success 成功 INUSE INUSE
固有 INUSE INUSE Success 成功 INUSE INUSE
SO_REUSEADDR ワイルドカード INUSE INUSE Success 成功 INUSE INUSE
固有 INUSE INUSE Success 成功 INUSE INUSE
SO_EXCLUSIVEADDRUSE ワイルドカード INUSE INUSE ACCESS ACCESS INUSE INUSE
固有 INUSE INUSE ACCESS ACCESS INUSE INUSE

2 つのソケットが同じポート番号にバインドされているが、異なる明示的なインターフェイスでバインドされている場合、競合はありません。 たとえば、コンピューターに 2 つの IP インターフェイスがある場合、 バインドの最初の呼び出 しが 10.0.0.1 でポートが 5150 に設定され、 SO_EXCLUSIVEADDRUSE が指定されている場合、10.0.0.1 と 10.99.99.99 と 10.99.99.99 で バインド する 2 回目の呼び出しも 5150 に設定され、オプションが指定されていない場合は成功します。 ただし、最初のソケットがワイルドカード・アドレスおよびポート 5150 にバインドされている場合、SO_EXCLUSIVEADDRUSEが設定されたポート 5150 への後続のバインド呼び出しは、バインド操作によって返される WSAEADDRINUSE または WSAEACCES のいずれかで失敗します。

バインドの最初の呼び出しでSO_REUSEADDRまたはソケット オプションがまったく設定されない場合、2 番目のバインド呼び出しではポートが "ハイジャック" され、アプリケーションは"共有" ポートに送信された特定のパケットを受信した 2 つのソケットのうちどれを判別できません。

バインド関数を呼び出す一般的なアプリケーションでは、 バインド 関数の呼び出しの前に ソケットで SO_EXCLUSIVEADDRUSE ソケット オプションが呼び出されない限り、 バインド されたソケットは排他的に割り当てられません。 サーバー アプリケーションが同じポートにバインドされる前に、クライアント アプリケーションがエフェメラル ポートまたは特定のポートにバインドすると、問題が発生する可能性があります。 サーバー アプリケーションは、バインド関数を呼び出す前にソケットの SO_REUSEADDR ソケット オプションを使用して同じポートに強制的に バインド できますが、そのポートにバインドされているすべてのソケットの動作は不確定になります。 サーバー アプリケーションがポートを排他的に使用するために SO_EXCLUSIVEADDRUSE ソケット オプションを使用しようとすると、要求は失敗します。

逆に、 SO_EXCLUSIVEADDRUSE セットを持つソケットは、必ずしもソケットのクローズ直後に再利用できるとは限りません。 たとえば、 SO_EXCLUSIVEADDRUSE セットを持つリッスン ソケットが接続を受け入れ、その後閉じられた場合、元の接続が非アクティブになるまで、別のソケット ( SO_EXCLUSIVEADDRUSE も含む) を最初のソケットと同じポートにバインドすることはできません。

この問題は、ソケットが閉じられている場合でも、基になるトランスポート プロトコルが接続を終了しない可能性があるため、複雑になる可能性があります。 ソケットがアプリケーションによって閉じられた後でも、システムはバッファー内のデータを送信し、正常な切断メッセージをピアに送信し、対応する正常な切断メッセージがピアから待機する必要があります。 基になるトランスポート プロトコルが接続を解放しない可能性があります。たとえば、元の接続に参加しているピアは、サイズが 0 のウィンドウ、または他の形式の "攻撃" 構成をアドバタイズする可能性があります。 このような場合、未確認のデータはバッファー内に残っているため、クライアント接続は閉じる要求にもかかわらずアクティブな状態のままです。

この状況を回避するには、ネットワーク アプリケーションは、SD_SEND フラグを設定して シャットダウン を呼び出して正常なシャットダウンを確保し、接続経由で 0 バイトが返されるまで recv ループで待機する必要があります。 これにより、すべてのデータがピアによって受信され、同様に、送信されたすべてのデータを受信したことをピアに確認し、前述のポート再利用の問題を回避できます。

SO_LINGER ソケット オプションをソケットに設定して、ポートが "アクティブ" 待機状態に遷移しないようにすることができます。ただし、これは、接続のリセットなど、望ましくない効果につながる可能性があるため、推奨されません。 たとえば、ピアによってデータが受信されても、そのデータが認識されないままで、ローカル コンピューターがソケットを閉じ、SO_LINGERが設定されている場合、2 台のコンピューター間の接続はリセットされ、認識されていないデータはピアによって破棄されます。 タイムアウト値を小さくすると突然接続が中止されることがよくありますが、タイムアウト値が大きいほど、システムはサービス拒否攻撃に対して脆弱になります (多くの接続を確立し、アプリケーション スレッドを停止またはブロックする可能性があるため)。 0 以外の残留タイムアウト値を持つソケットを閉じると、 closesocket 呼び出しがブロックされる場合もあります。

ソケット セキュリティの強化

Windows Server 2003 のリリースにより、ソケットのセキュリティが強化されました。 以前の Microsoft サーバー オペレーティング システム リリースでは、既定のソケット セキュリティにより、疑いのないアプリケーションからポートをハイジャックするプロセスが簡単に許可されました。 Windows Server 2003 では、ソケットは既定では共有可能な状態ではありません。 したがって、アプリケーションがソケットが既にバインドされているポートを他のプロセスが再利用できるようにする場合は、それを明示的に有効にする必要があります。 その場合、ポートで バインド を呼び出す最初のソケットは、ソケットに SO_REUSEADDR 設定されている必要があります。 この場合の唯一の例外は、2 番目のバインド呼び出しが バインドする元の呼び出しを行ったのと同じユーザー アカウントによって実行される場合に発生 します。 この例外は、下位互換性を提供するためにのみ存在します。

次の表は、Windows Server 2003 以降のオペレーティング システムで、2 番目のソケットが特定のソケット オプションを使用して最初のソケットによって以前にバインドされたアドレスにバインドしようとしたときに発生する動作を示しています。

注意

次の表の "ワイルドカード" は、指定されたプロトコルのワイルドカード アドレスを示しています (IPv4 の場合は "0.0.0.0"、IPv6 の場合は "::" など)。 "Specific" は、インターフェイスに割り当てられた特定の IP アドレスを示します。 テーブルのセルは、バインドが成功した ("成功") か、または返されたエラー ( WSAEADDRINUSE エラーの場合は "INUSE" ) かを示します。 WSAEACCES エラーの場合は "ACCESS" です)。

また、この特定のテーブルでは、両方の バインド 呼び出しが同じユーザー アカウントで行われます。

最初の バインド 呼び出し 2 回目の バインド 呼び出し
Default SO_REUSEADDR SO_EXCLUSIVEADDRUSE
ワイルドカード 固有 ワイルドカード 固有 ワイルドカード 固有
Default ワイルドカード INUSE Success ACCESS Success INUSE Success
固有 Success INUSE Success ACCESS INUSE INUSE
SO_REUSEADDR ワイルドカード INUSE Success 成功 成功 INUSE Success
固有 Success INUSE Success 成功 INUSE INUSE
SO_EXCLUSIVEADDRUSE ワイルドカード INUSE ACCESS ACCESS ACCESS INUSE ACCESS
固有 Success INUSE Success ACCESS INUSE INUSE

上記のメリットの説明の表のいくつかのエントリ。

たとえば、最初の呼び出し元が特定のアドレスに SO_EXCLUSIVEADDRUSE を設定し、2 番目の呼び出し元が同じポートでワイルドカード アドレスを使用して バインド を呼び出そうとした場合、2 番目の バインド 呼び出しは成功します。 この場合、2 番目の呼び出し元は、最初の呼び出し元がバインドされている特定のアドレスを除くすべてのインターフェイスにバインドされます。 この場合の逆は当てはまらないことに注意してください。最初の呼び出し元が SO_EXCLUSIVEADDRUSE を設定し、ワイルドカード フラグを使用して バインド を呼び出すと、2 番目の呼び出し元は同じポートで バインド を呼び出すことができません。

ソケット バインドの動作は、ソケット バインド呼び出しが異なるユーザー アカウントで行われると変更されます。 次の表は、Windows Server 2003 以降のオペレーティング システムで、特定のソケット オプションと別のユーザー アカウントを使用して、2 番目のソケットが最初のソケットによって以前にバインドされたアドレスにバインドしようとしたときに発生する動作を示しています。

最初の バインド 呼び出し 2 番目 のバインド 呼び出し
Default SO_REUSEADDR SO_EXCLUSIVEADDRUSE
ワイルドカード 固有 ワイルドカード 固有 ワイルドカード 固有
Default ワイルドカード INUSE ACCESS ACCESS ACCESS INUSE ACCESS
固有 Success INUSE Success ACCESS INUSE INUSE
SO_REUSEADDR ワイルドカード INUSE ACCESS Success 成功 INUSE ACCESS
固有 Success INUSE Success 成功 INUSE INUSE
SO_EXCLUSIVEADDRUSE ワイルドカード INUSE ACCESS ACCESS ACCESS INUSE ACCESS
固有 Success INUSE Success ACCESS INUSE INUSE

バインド呼び出しが異なるユーザー アカウントで行われる場合、既定の動作は異なります。 最初の呼び出し元がソケットにオプションを設定せず、ワイルドカード アドレスにバインドする場合、2 番目の呼び出し元は SO_REUSEADDR オプションを設定できず、同じポートに正常にバインドできません。 オプションが設定されていない既定の動作でも、エラーが返されます。

Windows Vista 以降では、IPv6 と IPv4 の両方で動作するデュアル スタック ソケットを作成できます。 デュアル スタック ソケットがワイルドカード アドレスにバインドされている場合、指定されたポートは IPv4 ネットワーク スタックと IPv6 ネットワーク スタックの両方で予約され、 SO_REUSEADDRSO_EXCLUSIVEADDRUSE (設定されている場合) に関連付けられているチェックが行われます。 これらのチェックは、両方のネットワーク スタックで成功する必要があります。 たとえば、デュアル スタック TCP ソケットが SO_EXCLUSIVEADDRUSE を設定し、ポート 5000 にバインドしようとすると、他の TCP ソケットをポート 5000 (ワイルドカードまたは特定のいずれか) に以前にバインドすることはできません。 この場合、IPv4 TCP ソケットが以前にポート 5000 のループバック アドレスにバインドされていた場合、デュアル スタック ソケットの バインド 呼び出しは WSAEACCES で失敗します。

アプリケーション戦略

ソケット 層で動作するネットワーク アプリケーションを開発する場合は、必要なソケット セキュリティの種類を考慮することが重要です。 クライアント アプリケーション (データをサービスに接続または送信するアプリケーション) は、ランダムなローカル (エフェメラル) ポートにバインドされるため、追加の手順を必要とすることはほとんどありません。 クライアントが正しく機能するために特定のローカル ポート バインドを必要とする場合は、ソケット のセキュリティを考慮する必要があります。

SO_REUSEADDR オプションは、データが同じポートにバインドされているすべてのソケットに配信されるマルチキャスト ソケットとは別に、通常のアプリケーションではほとんど使用を行う必要はありません。 それ以外の場合、このソケット オプションを設定するアプリケーションは、"ソケット ハイジャック" に対して脆弱であるため、依存関係を削除するように再設計する必要があります。 ソケット オプションSO_REUSEADDR使用してサーバー アプリケーションのポートをハイジャックする可能性がある限り、アプリケーションはセキュリティで保護されていないと見なす必要があります。

強力なレベルのソケット セキュリティのために、すべてのサーバー アプリケーションで SO_EXCLUSIVEADDRUSE を設定する必要があります。 悪意のあるソフトウェアがポートをハイジャックするのを防ぐだけでなく、別のアプリケーションが要求されたポートにバインドされているかどうかを示します。 たとえば、別のプロセスが現在特定のインターフェイス上の同じポートにバインドされている場合、SO_EXCLUSIVEADDRUSE ソケット オプション が設定されたプロセスによってワイルドカード アドレスにバインドする呼び出しは失敗します。

最後に、Windows Server 2003 ではソケット のセキュリティが強化されましたが、アプリケーションでは常に SO_EXCLUSIVEADDRUSE ソケット オプションを設定して、プロセスが要求したすべての特定のインターフェイスにバインドされるようにする必要があります。 Windows Server 2003 のソケット セキュリティにより、レガシ アプリケーションのセキュリティ レベルが向上しますが、アプリケーション開発者は引き続きセキュリティのすべての側面を念頭に置いて製品を設計する必要があります。