Freigeben über


Verwenden von SO_REUSEADDR und SO_EXCLUSIVEADDRUSE

Die Entwicklung einer sicheren Netzwerkinfrastruktur auf hoher Ebene hat für die meisten Netzwerkanwendungsentwickler Priorität. Die Socketsicherheit wird jedoch häufig übersehen, obwohl sie sehr kritisch ist, wenn eine vollständig sichere Lösung in Betracht gezogen wird. Socketsicherheit befasst sich insbesondere mit Prozessen, die an denselben Port gebunden sind, der zuvor durch einen anderen Anwendungsprozess gebunden war. In der Vergangenheit war es für eine Netzwerkanwendung möglich, den Port einer anderen Anwendung zu "entführen", was leicht zu einem "Denial-of-Service"-Angriff oder Datendiebstahl führen konnte.

Im Allgemeinen gilt die Socketsicherheit für serverseitige Prozesse. Insbesondere gilt die Socketsicherheit für jede Netzwerkanwendung, die Verbindungen akzeptiert und IP-Datagrammdatenverkehr empfängt. Diese Anwendungen binden in der Regel an einen bekannten Port und sind häufige Ziele für schädlichen Netzwerkcode.

Clientanwendungen sind weniger wahrscheinlich die Ziele solcher Angriffe – nicht, weil sie weniger anfällig sind, sondern weil die meisten Clients an "kurzlebige" lokale Ports und nicht an statische "Dienst"-Ports binden. Clientnetzwerkanwendungen sollten immer an kurzlebige Ports binden (durch Angabe von Port 0 in der SOCKADDR-Struktur, auf die beim Aufrufen der Bindungsfunktion durch den Parameter name verwiesen wird), es sei denn, es gibt einen überzeugenden architektonischen Grund, dies nicht. Die kurzlebigen lokalen Ports bestehen aus Ports, die größer als Port 49151 sind. Die meisten Serveranwendungen für dedizierte Dienste binden an einen bekannten reservierten Port, der kleiner oder gleich Port 49151 ist. Für die meisten Anwendungen gibt es also in der Regel keinen Konflikt für Bindungsanforderungen zwischen Client- und Serveranwendungen.

In diesem Abschnitt wird das Standardniveau der Sicherheit auf verschiedenen Microsoft Windows-Plattformen beschrieben und beschrieben, wie sich die spezifischen Socketoptionen SO_REUSEADDR und SO_EXCLUSIVEADDRUSE auf die Sicherheit von Netzwerkanwendungen auswirken und diese beeinflussen. Ein zusätzliches Feature namens Erweiterte Socketsicherheit ist unter Windows Server 2003 und höher verfügbar. Die Verfügbarkeit dieser Socketoptionen und die erweiterte Socketsicherheit variieren je nach Version von Microsoft-Betriebssystemen, wie in der folgenden Tabelle dargestellt.

Plattform SO_REUSEADDR SO_EXCLUSIVEADDRUSE Erweiterte Socketsicherheit
Windows 95 Verfügbar Nicht verfügbar Nicht verfügbar.
Windows 98 Verfügbar Nicht verfügbar Nicht verfügbar.
Windows Me Verfügbar Nicht verfügbar Nicht verfügbar.
Windows NT 4.0 Verfügbar Verfügbar in Service Pack 4 und höher Nicht verfügbar
Windows 2000 Verfügbar Verfügbar Nicht verfügbar
Windows XP Verfügbar Verfügbar Nicht verfügbar
Windows Server 2003 Verfügbar Verfügbar Verfügbar
Windows Vista Verfügbar Verfügbar Verfügbar
WindowsServer 2008 Verfügbar Verfügbar Verfügbar
Windows 7 und höher Verfügbar Verfügbar Verfügbar

Verwenden von SO_REUSEADDR

Die SO_REUSEADDR Socketoption ermöglicht es einem Socket, sich gewaltsam an einen Port zu binden, der von einem anderen Socket verwendet wird. Der zweite Socket ruft setsockopt auf, wobei der Optname-Parameter auf SO_REUSEADDR festgelegt ist und der Optval-Parameter auf einen booleschen Wert von TRUE festgelegt ist, bevor die Bindung an demselben Port wie der ursprüngliche Socket aufgerufen wird. Nachdem der zweite Socket erfolgreich gebunden wurde, ist das Verhalten für alle Sockets, die an diesen Port gebunden sind, unbestimmt. Wenn beispielsweise alle Sockets am gleichen Port TCP-Dienst bereitstellen, kann nicht garantiert werden, dass alle eingehenden TCP-Verbindungsanforderungen über den Port vom richtigen Socket verarbeitet werden – das Verhalten ist nicht deterministisch. Ein schadhaftes Programm kann SO_REUSEADDR verwenden, um Bereits verwendete Sockets für Standardnetzwerkprotokolldienste zwangszubinden, um den Zugriff auf diesen Dienst zu verweigern. Für die Verwendung dieser Option sind keine besonderen Berechtigungen erforderlich.

Wenn eine Clientanwendung an einen Port gebunden wird, bevor eine Serveranwendung an denselben Port gebunden werden kann, können Probleme auftreten. Wenn die Serveranwendung mit der SO_REUSEADDR Socketoption gewaltsam an denselben Port bindet, ist das Verhalten für alle an diesen Port gebundenen Sockets unbestimmt.

Die Ausnahme von diesem nicht deterministischen Verhalten sind Multicastsockets. Wenn zwei Sockets an die gleiche Schnittstelle und denselben Port gebunden sind und Mitglieder derselben Multicastgruppe sind, werden Daten an beide Sockets anstatt an einen willkürlich ausgewählten Socket übermittelt.

Verwenden von SO_EXCLUSIVEADDRUSE

Bevor die Socketoption SO_EXCLUSIVEADDRUSE eingeführt wurde, konnte ein Netzwerkanwendungsentwickler nur sehr wenig tun, um zu verhindern, dass ein schadhaftes Programm an den Port gebunden ist, an den die Netzwerkanwendung eigene Sockets gebunden hatte. Um dieses Sicherheitsproblem zu beheben, hat Windows Sockets die Option SO_EXCLUSIVEADDRUSE Socket eingeführt, die unter Windows NT 4.0 mit Service Pack 4 (SP4) und höher verfügbar wurde.

Die SO_EXCLUSIVEADDRUSE Socketoption kann nur von Mitgliedern der Sicherheitsgruppe Administratoren unter Windows XP und früher verwendet werden. Die Gründe, warum diese Anforderung unter Windows Server 2003 und höher geändert wurde, werden weiter unten im Artikel erläutert.

Die option SO_EXCLUSIVEADDRUSE wird durch Aufrufen der setockopt-Funktion mit dem optname-Parameter auf SO_EXCLUSIVEADDRUSE und dem optval-Parameter auf einen booleschen Wert TRUE festgelegt, bevor der Socket gebunden wird. Nachdem die Option festgelegt wurde, unterscheidet sich das Verhalten der nachfolgenden Bindungsaufrufe je nach der Netzwerkadresse, die in jedem Bindungsaufruf angegeben ist.

In der folgenden Tabelle wird das Verhalten beschrieben, das in Windows XP und früher auftritt, wenn ein zweiter Socket versucht, an eine Adresse zu binden, die zuvor durch einen ersten Socket mit bestimmten Socketoptionen gebunden wurde.

Hinweis

In der folgenden Tabelle bezeichnet "Wildcard" die Feldhalteradresse für das angegebene Protokoll (z. B. "0.0.0.0" für IPv4 und "::" für IPv6). "Spezifisch" bezeichnet eine bestimmte IP-Adresse, die einer Schnittstelle zugewiesen ist. Die Tabellenzellen geben an, ob die Bindung erfolgreich ist ("Erfolg") oder ein Fehler zurückgegeben wird ("INUSE" für den WSAEADDRINUSE-Fehler ; "ACCESS" für den WSAEACCES-Fehler ).

Erster Bindungsaufruf Zweiter Bindungsaufruf
Standard SO_REUSEADDR SO_EXCLUSIVEADDRUSE
Platzhalter Spezifisch Platzhalter Spezifisch Platzhalter Spezifisch
Standard Platzhalter INUSE INUSE Erfolg Erfolgreich INUSE INUSE
Spezifisch INUSE INUSE Erfolg Erfolgreich INUSE INUSE
SO_REUSEADDR Platzhalter INUSE INUSE Erfolg Erfolgreich INUSE INUSE
Spezifisch INUSE INUSE Erfolg Erfolgreich INUSE INUSE
SO_EXCLUSIVEADDRUSE Platzhalter INUSE INUSE ACCESS ACCESS INUSE INUSE
Spezifisch INUSE INUSE ACCESS ACCESS INUSE INUSE

Wenn zwei Sockets an dieselbe Portnummer, aber an verschiedene explizite Schnittstellen gebunden sind, gibt es keinen Konflikt. Wenn ein Computer beispielsweise über zwei IP-Schnittstellen verfügt, 10.0.0.1 und 10.99.99.99, wenn der erste Aufruf der Bindung auf 10.0.0.1 erfolgt, wobei der Port auf 5150 festgelegt ist und SO_EXCLUSIVEADDRUSE angegeben ist, dann wird ein zweiter Aufruf der Bindung an 10.99.99.99 mit ebenfalls auf 5150 festgelegter Port und ohne angegebene Optionen erfolgreich ausgeführt. Wenn der erste Socket jedoch an die Wildcardadresse und port 5150 gebunden ist, schlägt jeder nachfolgende Bindungsaufruf an Port 5150 mit SO_EXCLUSIVEADDRUSE set entweder mit WSAEADDRINUSE oder WSAEACCES fehl, die vom Bindungsvorgang zurückgegeben wird.

In dem Fall, in dem der erste Aufruf der Bindungentweder SO_REUSEADDR oder gar keine Socketoptionen festlegt, wird der zweite Bindungsaufruf den Port "hijack" und die Anwendung kann nicht ermitteln, welche der beiden Sockets bestimmte Pakete empfangen hat, die an den "freigegebenen" Port gesendet werden.

Eine typische Anwendung, die die Bindfunktion aufruft, weist den gebundenen Socket nicht für die exklusive Verwendung zu, es sei denn, die Option SO_EXCLUSIVEADDRUSE Socket wird für den Socket vor dem Aufruf der Bindfunktion aufgerufen. Wenn eine Clientanwendung an einen kurzlebigen Port oder einen bestimmten Port gebunden wird, bevor eine Serveranwendung an denselben Port bindet, können Probleme auftreten. Die Serveranwendung kann zwangsgebunden an denselben Port binden, indem sie die Option SO_REUSEADDR Socket für den Socket verwendet, bevor die Bindfunktion aufgerufen wird, aber das Verhalten für alle Sockets, die an diesen Port gebunden sind, ist dann unbestimmt. Wenn die Serveranwendung versucht, die Option SO_EXCLUSIVEADDRUSE Socket für die exklusive Verwendung des Ports zu verwenden, schlägt die Anforderung fehl.

Umgekehrt kann ein Socket mit dem SO_EXCLUSIVEADDRUSE Satz nicht unbedingt sofort nach dem Schließen des Sockets wiederverwendet werden. Wenn z. B. ein Abhörsocket mit SO_EXCLUSIVEADDRUSE Satz eine Verbindung akzeptiert und anschließend geschlossen wird, kann ein anderer Socket (auch mit SO_EXCLUSIVEADDRUSE) nicht an denselben Port wie der erste Socket gebunden werden, bis die ursprüngliche Verbindung inaktiv wird.

Dieses Problem kann kompliziert werden, da das zugrunde liegende Transportprotokoll die Verbindung möglicherweise nicht beendet, obwohl der Socket geschlossen wurde. Selbst nachdem der Socket von der Anwendung geschlossen wurde, muss das System alle gepufferten Daten übertragen, eine ordnungsgemäße Trennungsmeldung an den Peer senden und auf eine entsprechende ordnungsgemäße Trennungsmeldung vom Peer warten. Es ist möglich, dass das zugrunde liegende Transportprotokoll die Verbindung niemals freigibt. Beispielsweise kann der Peer, der an der ursprünglichen Verbindung teilnimmt, ein Fenster der Größe null oder eine andere Form der "Angriffs"-Konfiguration ankündigen. In einem solchen Fall bleibt die Clientverbindung trotz der Anforderung, sie zu schließen, in einem aktiven Zustand, da nicht gesicherte Daten im Puffer verbleiben.

Um diese Situation zu vermeiden, sollten Netzwerkanwendungen ein ordnungsgemäßes Herunterfahren sicherstellen, indem sie shutdown aufrufen, wobei das flag SD_SEND festgelegt ist, und dann in einer recv-Schleife warten, bis null Bytes über die Verbindung zurückgegeben werden. Dadurch wird sichergestellt, dass alle Daten vom Peer empfangen werden und dem Peer ebenfalls bestätigt wird, dass er alle übertragenen Daten empfangen hat, und das oben erwähnte Problem der Portwiederverwendung wird vermieden.

Die Option SO_LINGER Sockets kann für einen Socket festgelegt werden, um zu verhindern, dass der Port in einen "aktiven" Wartezustand übergehen kann. Dies wird jedoch abgeraten, da dies zu unerwünschten Effekten führen kann, z. B. zum Zurücksetzen von Verbindungen. Wenn beispielsweise Daten vom Peer empfangen, aber von diesem nicht bestätigt werden, und der lokale Computer den Socket mit SO_LINGER schließt, wird die Verbindung zwischen den beiden Computern zurückgesetzt, und die nicht bestätigten Daten werden vom Peer verworfen. Die Auswahl einer geeigneten Zeit für das Verweilen ist schwierig, da ein kleinerer Timeoutwert häufig zu plötzlich abgebrochenen Verbindungen führt, während größere Timeoutwerte das System anfällig für Denial-of-Service-Angriffe machen (durch das Einrichten vieler Verbindungen und möglicherweise blockierte/blockierende Anwendungsthreads). Das Schließen eines Sockets mit einem Timeoutwert ungleich null kann auch dazu führen, dass der Closesocket-Aufruf blockiert wird.

Erweiterte Socketsicherheit

Mit der Veröffentlichung von Windows Server 2003 wurde eine verbesserte Socketsicherheit hinzugefügt. In früheren Versionen des Microsoft-Serverbetriebssystems ermöglichte die Standardmäßige Socketsicherheit problemlos Prozesse, um Ports von ahnungslosen Anwendungen zu entführen. In Windows Server 2003 befinden sich Sockets standardmäßig nicht in einem teilbaren Zustand. Wenn eine Anwendung es daher anderen Prozessen ermöglichen möchte, einen Port wiederzuverwenden, an den ein Socket bereits gebunden ist, muss sie ihn speziell aktivieren. Wenn dies der Fall ist, muss für den ersten Socket, der die Bindung für den Port aufruft, SO_REUSEADDR für den Socket festgelegt sein. Die einzige Ausnahme in diesem Fall tritt auf, wenn der zweite Bindungsaufruf von demselben Benutzerkonto ausgeführt wird, das den ursprünglichen Aufruf der Bindung durchgeführt hat. Diese Ausnahme besteht ausschließlich aus Gründen der Abwärtskompatibilität.

In der folgenden Tabelle wird das Verhalten beschrieben, das unter Windows Server 2003 und höher auftritt, wenn ein zweiter Socket versucht, eine Bindung an eine Adresse durchzuführen, die zuvor von einem ersten Socket mithilfe bestimmter Socketoptionen gebunden wurde.

Hinweis

In der folgenden Tabelle bezeichnet "Wildcard" die Wildcardadresse für das angegebene Protokoll (z. B. "0.0.0.0" für IPv4 und "::" für IPv6). "Spezifisch" bezeichnet eine bestimmte IP-Adresse, die einer Schnittstelle zugewiesen ist. Die Tabellenzellen geben an, ob die Bindung erfolgreich ist ("Erfolg") oder der zurückgegebene Fehler ("INUSE" für den WSAEADDRINUSE-Fehler ; "ACCESS" für den WSAEACCES-Fehler ).

Beachten Sie auch, dass in dieser spezifischen Tabelle beide Bindungsaufrufe unter demselben Benutzerkonto ausgeführt werden.

Erster Bindungsaufruf Zweiter Bindungsaufruf
Standard SO_REUSEADDR SO_EXCLUSIVEADDRUSE
Platzhalter Spezifisch Platzhalter Spezifisch Platzhalter Spezifisch
Standard Platzhalter INUSE Erfolg ACCESS Erfolg INUSE Erfolg
Spezifisch Erfolg INUSE Erfolg ACCESS INUSE INUSE
SO_REUSEADDR Platzhalter INUSE Erfolg Erfolgreich Erfolgreich INUSE Erfolg
Spezifisch Erfolg INUSE Erfolg Erfolgreich INUSE INUSE
SO_EXCLUSIVEADDRUSE Platzhalter INUSE ACCESS ACCESS ACCESS INUSE ACCESS
Spezifisch Erfolg INUSE Erfolg ACCESS INUSE INUSE

Einige Einträge in der obigen Tabelle sind erklärungswürdig.

Wenn der erste Aufrufer beispielsweise SO_EXCLUSIVEADDRUSE für eine bestimmte Adresse festlegt und der zweite Aufrufer versucht, die Bindung mit einer Platzhalteradresse an demselben Port aufzurufen, wird der zweite Bindungsaufruf erfolgreich ausgeführt. In diesem speziellen Fall ist der zweite Aufrufer an alle Schnittstellen mit Ausnahme der spezifischen Adresse gebunden, an die der erste Aufrufer gebunden ist. Beachten Sie, dass der umgekehrte Fall nicht richtig ist: Wenn der erste Aufrufer SO_EXCLUSIVEADDRUSE und Aufrufe mit dem Platzhalterflag bindet , kann der zweite Aufrufer die Bindung nicht mit demselben Port aufrufen.

Das Verhalten der Socketbindung ändert sich, wenn die Socketbindungsaufrufe unter verschiedenen Benutzerkonten erfolgen. Die folgende Tabelle gibt das Verhalten an, das in Windows Server 2003 und höheren Betriebssystemen auftritt, wenn ein zweiter Socket versucht, sich an eine Adresse zu binden, die zuvor durch einen ersten Socket mit bestimmten Socketoptionen und einem anderen Benutzerkonto gebunden wurde.

Erster Bindungsaufruf Zweiter Bindungsaufruf
Standard SO_REUSEADDR SO_EXCLUSIVEADDRUSE
Platzhalter Spezifisch Platzhalter Spezifisch Platzhalter Spezifisch
Standard Platzhalter INUSE ACCESS ACCESS ACCESS INUSE ACCESS
Spezifisch Erfolg INUSE Erfolg ACCESS INUSE INUSE
SO_REUSEADDR Platzhalter INUSE ACCESS Erfolg Erfolgreich INUSE ACCESS
Spezifisch Erfolg INUSE Erfolg Erfolgreich INUSE INUSE
SO_EXCLUSIVEADDRUSE Platzhalter INUSE ACCESS ACCESS ACCESS INUSE ACCESS
Spezifisch Erfolg INUSE Erfolg ACCESS INUSE INUSE

Beachten Sie, dass sich das Standardverhalten unterscheidet, wenn die Bindungsaufrufe unter verschiedenen Benutzerkonten erfolgen. Wenn der erste Aufrufer keine Optionen für den Socket legt und an die Platzhalteradresse bindet, kann der zweite Aufrufer die Option SO_REUSEADDR nicht festlegen und erfolgreich an denselben Port binden. Das Standardverhalten ohne festgelegte Optionen gibt ebenfalls einen Fehler zurück.

Unter Windows Vista und höher kann ein Dual Stack-Socket erstellt werden, der sowohl über IPv6 als auch über IPv4 funktioniert. Wenn ein Dual Stack-Socket an die Feldhalteradresse gebunden ist, wird der angegebene Port sowohl für den IPv4- als auch für den IPv6-Netzwerkstapel reserviert, und die Überprüfungen, die SO_REUSEADDR und SO_EXCLUSIVEADDRUSE zugeordnet sind (sofern festgelegt) werden durchgeführt. Diese Überprüfungen müssen auf beiden Netzwerkstapeln erfolgreich durchgeführt werden. Wenn beispielsweise ein TCP-Socket mit dualem Stapel SO_EXCLUSIVEADDRUSE festlegt und dann versucht, eine Bindung an Port 5000 zu binden, kann zuvor kein anderer TCP-Socket an Port 5000 gebunden werden (entweder als Wildcard oder spezifisch). In diesem Fall, wenn ein IPv4-TCP-Socket zuvor an die Loopbackadresse an Port 5000 gebunden war, schlägt der Bindungsaufruf für den Dual Stack-Socket mit WSAEACCES fehl.

Anwendungsstrategien

Bei der Entwicklung von Netzwerkanwendungen, die auf Socketebene ausgeführt werden, ist es wichtig, die Art der erforderlichen Socketsicherheit zu berücksichtigen. Clientanwendungen – Anwendungen, die Eine Verbindung mit einem Dienst herstellen oder Daten an einen Dienst senden – erfordern selten zusätzliche Schritte, da sie an einen zufälligen lokalen (kurzlebigen) Port gebunden sind. Wenn der Client eine bestimmte lokale Portbindung erfordert, um ordnungsgemäß zu funktionieren, müssen Sie die Socketsicherheit in Betracht ziehen.

Die Option SO_REUSEADDR hat nur sehr wenige Verwendungsmöglichkeiten in normalen Anwendungen, abgesehen von Multicastsockets, bei denen Daten an alle Sockets übermittelt werden, die an denselben Port gebunden sind. Andernfalls sollte jede Anwendung, die diese Socketoption festlegt, neu gestaltet werden, um die Abhängigkeit zu entfernen, da sie äußerst anfällig für "Socket-Hijacking" ist. Solange SO_REUSEADDR Socketoption verwendet werden kann, um möglicherweise einen Port in einer Serveranwendung zu kapern, muss die Anwendung als nicht sicher angesehen werden.

Alle Serveranwendungen müssen SO_EXCLUSIVEADDRUSE für ein hohes Maß an Socketsicherheit festlegen. Es verhindert nicht nur, dass Schadsoftware den Port kapern kann, sondern gibt auch an, ob eine andere Anwendung an den angeforderten Port gebunden ist. Beispielsweise schlägt ein Aufruf der Bindung an die Wildcardadresse durch einen Prozess mit der SO_EXCLUSIVEADDRUSE Socketoption fehl, wenn ein anderer Prozess derzeit an denselben Port auf einer bestimmten Schnittstelle gebunden ist.

Auch wenn die Socketsicherheit in Windows Server 2003 verbessert wurde, sollte eine Anwendung immer die Option SO_EXCLUSIVEADDRUSE Socket festlegen, um sicherzustellen, dass sie an alle spezifischen Schnittstellen gebunden ist, die der Prozess angefordert hat. Die Socketsicherheit in Windows Server 2003 erhöht die Sicherheit für Legacyanwendungen, aber Anwendungsentwickler müssen ihre Produkte weiterhin unter Berücksichtigung aller Sicherheitsaspekte entwerfen.