Delen via


SO_REUSEADDR en SO_EXCLUSIVEADDRUSE gebruiken

Het ontwikkelen van een veilige netwerkinfrastructuur op hoog niveau is een prioriteit voor de meeste ontwikkelaars van netwerktoepassingen. Socketbeveiliging wordt echter vaak over het hoofd gezien, ondanks dat deze zeer kritiek is bij het overwegen van een volledig veilige oplossing. Socketbeveiliging behandelt met name processen die zijn gebonden aan dezelfde poort die eerder door een ander toepassingsproces zijn gebonden. In het verleden was het mogelijk dat een netwerktoepassing de poort van een andere toepassing 'kapt', wat eenvoudig kan leiden tot een 'Denial of Service'-aanval of gegevensdiefstal.

Over het algemeen is socketbeveiliging van toepassing op processen aan de serverzijde. Meer specifiek geldt socketbeveiliging voor elke netwerktoepassing die verbindingen accepteert en IP-datagramverkeer ontvangt. Deze toepassingen binden doorgaans aan een bekende poort en zijn veelvoorkomende doelen voor schadelijke netwerkcode.

Clienttoepassingen zijn minder waarschijnlijk de doelen van dergelijke aanvallen, niet omdat ze minder gevoelig zijn, maar omdat de meeste clients zich binden aan 'tijdelijke' lokale poorten in plaats van statische servicepoorten. Clientnetwerktoepassingen moeten altijd verbinding maken met tijdelijke poorten (door poort 0 op te geven in de SOCKADDR- structuur die wordt verwezen door de parameter naam bij het aanroepen van de binding functie) tenzij er een overtuigende architecturale reden is dat niet. De tijdelijke lokale poorten bestaan uit poorten die groter zijn dan poort 49151. De meeste servertoepassingen voor toegewezen services binden zich aan een bekende gereserveerde poort die kleiner is dan of gelijk is aan poort 49151. Voor de meeste toepassingen is er dus meestal geen conflict voor bindingsaanvragen tussen client- en servertoepassingen.

In deze sectie wordt het standaardniveau van beveiliging op verschillende Microsoft Windows-platforms beschreven en wordt beschreven hoe de specifieke socketopties SO_REUSEADDR en SO_EXCLUSIVEADDRUSE van invloed zijn op de beveiliging van netwerktoepassingen. Er is een extra functie met de naam Enhanced Socket Security beschikbaar op Windows Server 2003 en hoger. De beschikbaarheid van deze socketopties en verbeterde socketbeveiliging verschilt per versie van Microsoft-besturingssystemen, zoals wordt weergegeven in de onderstaande tabel.

Perron SO_REUSEADDR SO_EXCLUSIVEADDRUSE Verbeterde socketbeveiliging
Windows 95 Beschikbaar Niet beschikbaar Niet beschikbaar
Windows 98 Beschikbaar Niet beschikbaar Niet beschikbaar
Windows Me Beschikbaar Niet beschikbaar Niet beschikbaar
Windows NT 4.0 Beschikbaar Beschikbaar in Service Pack 4 en hoger Niet beschikbaar
Windows 2000 Beschikbaar Beschikbaar Niet beschikbaar
Windows XP Beschikbaar Beschikbaar Niet beschikbaar
Windows Server 2003 Beschikbaar Beschikbaar Beschikbaar
Windows Vista Beschikbaar Beschikbaar Beschikbaar
Windows Server 2008 Beschikbaar Beschikbaar Beschikbaar
Windows 7 en hoger Beschikbaar Beschikbaar Beschikbaar

SO_REUSEADDR gebruiken

Met de SO_REUSEADDR socketoptie kan een socket geforceerd worden verbonden met een poort die door een andere socket wordt gebruikt. De tweede socket roept setsockopt- aan met de parameter optname ingesteld op SO_REUSEADDR en de optval- parameter ingesteld op een booleaanse waarde van TRUE- voordat bindt op dezelfde poort als de oorspronkelijke socket. Zodra de tweede socket is gebonden, is het gedrag voor alle sockets die aan die poort zijn gebonden, onbepaald. Als bijvoorbeeld alle sockets op dezelfde poort TCP-service bieden, kunnen binnenkomende TCP-verbindingsaanvragen via de poort niet worden gegarandeerd door de juiste socket worden verwerkt. Het gedrag is niet deterministisch. Een schadelijk programma kan SO_REUSEADDR gebruiken om geforceerd sockets te binden die al in gebruik zijn voor standaardnetwerkprotocolservices om de toegang tot deze service te weigeren. Er zijn geen speciale bevoegdheden vereist om deze optie te gebruiken.

Als een clienttoepassing verbinding maakt met een poort voordat een servertoepassing verbinding kan maken met dezelfde poort, kunnen er problemen optreden. Als de servertoepassing geforceerd bindt met behulp van de SO_REUSEADDR socketoptie op dezelfde poort, is het gedrag voor alle sockets die aan die poort zijn gebonden, onbepaald.

De uitzondering op dit niet-deterministische gedrag is multicast-sockets. Als twee sockets zijn gebonden aan dezelfde interface en poort en lid zijn van dezelfde multicast-groep, worden gegevens aan beide sockets geleverd in plaats van een willekeurig gekozen socket.

SO_EXCLUSIVEADDRUSE gebruiken

Voordat de SO_EXCLUSIVEADDRUSE socket-optie werd geïntroduceerd, was er weinig dat een ontwikkelaar van netwerktoepassingen kon doen om te voorkomen dat een schadelijk programma verbinding kan maken met de poort waarop de netwerktoepassing zijn eigen sockets gebonden had. Om dit beveiligingsprobleem op te lossen, heeft Windows Sockets de optie SO_EXCLUSIVEADDRUSE socket geïntroduceerd, die beschikbaar werd in Windows NT 4.0 met Service Pack 4 (SP4) en hoger.

De optie SO_EXCLUSIVEADDRUSE socket kan alleen worden gebruikt door leden van de beveiligingsgroep Administrators in Windows XP en eerder. De redenen waarom deze vereiste is gewijzigd in Windows Server 2003 en hoger, worden verderop in het artikel besproken.

De optie SO_EXCLUSIVEADDRUSE wordt ingesteld door de functie setsockopt aan te roepen met de parameter optname ingesteld op SO_EXCLUSIVEADDRUSE en de parameter optval ingesteld op de booleaanse waarde TRUE voordat de socket wordt gebonden. Nadat de optie is ingesteld, verschilt het gedrag van volgende aanroepen afhankelijk van het netwerkadres dat is opgegeven in elke binding aanroep.

In de onderstaande tabel wordt het gedrag beschreven dat zich voordoet in Windows XP en eerder wanneer een tweede socket probeert te binden aan een adres dat eerder is gebonden door een eerste socket met behulp van specifieke socketopties.

Notitie

In de onderstaande tabel geeft 'jokerteken' het jokerteken voor het opgegeven protocol aan (zoals '0.0.0.0.0' voor IPv4 en '::' voor IPv6). 'Specifiek' geeft een specifiek IP-adres aan waaraan een interface is toegewezen. De tabelcellen geven aan of de binding is geslaagd ('Geslaagd') of dat er een fout wordt geretourneerd ('INUSE' voor de WSAEADDRINUSE fout; 'ACCESS' voor de WSAEACCES fout).

Eerst binden oproepen Tweede verbind oproep
Verstek SO_REUSEADDR SO_EXCLUSIVEADDRUSE
Wildcard Specifiek Wildcard Specifiek Wildcard Specifiek
Verstek Wildcard In Gebruik IN GEBRUIK Succes Succes in gebruik IN GEBRUIK
Specifiek IN GEBRUIK IN GEBRUIK Succes Succes IN GEBRUIK IN GEBRUIK
SO_REUSEADDR Wildcard INUSE IN GEBRUIK Succes Succes In Gebruik in gebruik
Specifiek In gebruik IN GEBRUIK Succes Succes INUSE IN GEBRUIK
SO_EXCLUSIVEADDRUSE Wildcard IN GEBRUIK In Gebruik TOEGANG TOEGANG IN GEBRUIK In Gebruik
Specifiek In gebruik IN GEBRUIK TOEGANG TOEGANG INUSE In gebruik

Wanneer twee sockets zijn gebonden aan hetzelfde poortnummer, maar op verschillende expliciete interfaces, is er geen conflict. In het geval dat een computer bijvoorbeeld twee IP-interfaces heeft, 10.0.0.1 en 10.99.99.99, als de eerste aanroep naar bind op 10.0.0.1 met de poort ingesteld op 5150 en de optie SO_EXCLUSIVEADDRUSE opgegeven is, zal een tweede aanroep voor bind op 10.99.99.99 met de poort ook ingesteld op 5150 en zonder opgegeven opties slagen. Als de eerste socket echter is gebonden aan het wildcardadres en poort 5150, zal elke volgende bind-aanroep naar poort 5150 met SO_EXCLUSIVEADDRUSE ingesteld mislukken, met als resultaat WSAEADDRINUSE of WSAEACCES geretourneerd door de bind-operatie.

In het geval dat de eerste aanroep naar bind ofwel SO_REUSEADDR of helemaal geen socketopties instelt, zal de tweede aanroep naar bind de poort overnemen, en zal de toepassing niet kunnen bepalen welke van de twee sockets specifieke pakketten heeft ontvangen die naar de "gedeelde" poort zijn verzonden.

Een typische toepassing die de bind functie aanroept, reserveert de gebonden socket niet voor exclusief gebruik, tenzij de SO_EXCLUSIVEADDRUSE socketoptie op de socket wordt aangeroepen voordat de bind functie wordt aangeroepen. Als een clienttoepassing wordt gebonden aan een tijdelijke poort of een specifieke poort voordat een servertoepassing wordt verbonden met dezelfde poort, kunnen er problemen optreden. De servertoepassing kan geforceerd verbinding maken met dezelfde poort met behulp van de SO_REUSEADDR socketoptie op de socket voordat de bind functie aanroept, maar het gedrag voor alle sockets die aan die poort zijn gebonden, is dan onbepaald. Als de servertoepassing de SO_EXCLUSIVEADDRUSE socketoptie probeert te gebruiken voor exclusief gebruik van de poort, mislukt de aanvraag.

Omgekeerd kan een socket met de SO_EXCLUSIVEADDRUSE set niet noodzakelijkerwijs onmiddellijk na het sluiten van de socket opnieuw worden gebruikt. Als een luistersocket met SO_EXCLUSIVEADDRUSE set bijvoorbeeld een verbinding accepteert en vervolgens wordt gesloten, kan een andere socket (ook met SO_EXCLUSIVEADDRUSE) niet worden verbonden met dezelfde poort als de eerste socket totdat de oorspronkelijke verbinding inactief wordt.

Dit probleem kan ingewikkeld worden omdat het onderliggende transportprotocol de verbinding mogelijk niet beëindigt, ook al is de socket gesloten. Zelfs nadat de socket door de toepassing is gesloten, moet het systeem gebufferde gegevens verzenden, een probleemloze verbinding met de peer verzenden en wachten op een overeenkomstig probleemloos verbindingsbericht van de peer. Het is mogelijk dat het onderliggende transportprotocol de verbinding nooit vrijgeeft; De peer die deelneemt aan de oorspronkelijke verbinding kan bijvoorbeeld een venster met nulgrootte of een andere vorm van 'aanvalsconfiguratie' adverteren. In dat geval blijft de clientverbinding actief, ondanks de aanvraag om deze te sluiten, omdat niet-bekende gegevens in de buffer blijven.

Om deze situatie te voorkomen, moeten netwerktoepassingen zorgen voor een probleemloos afsluiten door afsluiten aan te roepen met de SD_SEND vlag ingesteld en vervolgens te wachten in een recv lus totdat er nul bytes worden geretourneerd via de verbinding. Dit garandeert dat alle gegevens door de peer worden ontvangen en bevestigt met de peer dat alle verzonden gegevens zijn ontvangen, en voorkomt het bovengenoemde probleem met het opnieuw gebruiken van de poort.

De SO_LINGER socketoptie kan worden ingesteld op een socket om te voorkomen dat de poort overgaat naar een 'actieve' wachtstatus; Dit wordt echter afgeraden omdat dit kan leiden tot ongewenste effecten, zoals het opnieuw instellen van verbindingen. Als gegevens bijvoorbeeld worden ontvangen door de peer, maar niet door de peer worden aangegeven en de lokale computer de socket sluit met SO_LINGER ingesteld, wordt de verbinding tussen de twee computers opnieuw ingesteld en worden de niet-bekende gegevens verwijderd door de peer. Het kiezen van een geschikte tijd om te blijven hangen is moeilijk omdat een kleinere time-outwaarde vaak resulteert in plotseling afgebroken verbindingen, terwijl grotere time-outwaarden het systeem kwetsbaar maken voor denial-of-service-aanvallen (door veel verbindingen tot stand te brengen en mogelijk vastlopen/blokkerende toepassingsthreads). Als u een socket sluit die een niet-nul linger time-outwaarde heeft, kan dit er ook toe leiden dat de closesocket aanroep blokkeert.

Verbeterde socketbeveiliging

Verbeterde socketbeveiliging is toegevoegd met de release van Windows Server 2003. In eerdere versies van het Microsoft-serverbesturingssysteem kon de standaard socketbeveiliging gemakkelijk poorten overnemen van nietsvermoedende toepassingen. In Windows Server 2003 hebben sockets standaard geen deelbare status. Als een toepassing andere processen toestaat om een poort te hergebruiken waarop een socket al is gebonden, moet deze daarom specifiek worden ingeschakeld. Als dat het geval is, moet de eerste socket voor het aanroepen van bind op de poort SO_REUSEADDR ingesteld zijn op de socket. De enige uitzondering op dit geval treedt op wanneer de tweede -aanroep wordt uitgevoerd door hetzelfde gebruikersaccount dat de oorspronkelijke aanroep naar bind-heeft gemaakt. Deze uitzondering bestaat alleen om compatibiliteit met eerdere versies te bieden.

In de onderstaande tabel wordt het gedrag beschreven dat optreedt in besturingssystemen van Windows Server 2003 en hoger wanneer een tweede socket probeert verbinding te maken met een adres dat eerder is gebonden door een eerste socket met behulp van specifieke socketopties.

Notitie

In de onderstaande tabel geeft 'jokerteken' het jokerteken voor het opgegeven protocol aan (zoals '0.0.0.0.0' voor IPv4 en '::' voor IPv6). 'Specifiek' geeft een specifiek IP-adres aan waaraan een interface is toegewezen. De tabelcellen geven aan of de koppeling succesvol is ("Geslaagd") of de fout die is geretourneerd ("INUSE" voor de WSAEADDRINUSE fout; "ACCESS" voor de WSAEACCES fout).

Houd er ook rekening mee dat in deze specifieke tabel beide binden aanroepen worden uitgevoerd onder hetzelfde gebruikersaccount.

Eerste koppelaan gesprek Tweede bind call
Verstek SO_REUSEADDR SO_EXCLUSIVEADDRUSE
Wildcard Specifiek Wildcard Specifiek Wildkaart Specifiek
Verstek Jokerteken IN GEBRUIK Succes TOEGANG Succes IN GEBRUIK Succes
Specifiek Succes IN GEBRUIK Succes TOEGANG INUSE IN GEBRUIK
SO_REUSEADDR Wildcard IN GEBRUIK Succes Succes Succes In Gebruik Succes
Specifiek Succes In gebruik Succes Succes IN GEBRUIK IN GEBRUIK
SO_EXCLUSIVEADDRUSE Jokerteken In Gebruik TOEGANG TOEGANG TOEGANG IN GEBRUIK TOEGANG
Specifiek Succes In gebruik Succes TOEGANG IN GEBRUIK IN GEBRUIK

Een paar vermeldingen in de bovenstaande tabel verdienen uitleg.

Als de eerste beller bijvoorbeeld SO_EXCLUSIVEADDRUSE instelt op een specifiek adres en de tweede beller probeert te binden met een jokerteken op dezelfde poort, slaagt de tweede bind--aanroep. In dit specifieke geval is de tweede beller gebonden aan alle interfaces, met uitzondering van het specifieke adres waaraan de eerste beller is gebonden. Houd er rekening mee dat het omgekeerde van dit geval niet waar is: als de eerste aanroeper SO_EXCLUSIVEADDRUSE instelt en bind aanroept met de wildcard-vlag, kan de tweede aanroeper bind- met dezelfde poort niet aanroepen.

Het gedrag van socketbinding verandert wanneer de socketbindingsaanroepen worden uitgevoerd onder verschillende gebruikersaccounts. De onderstaande tabel geeft het gedrag op dat optreedt in Windows Server 2003 en hoger besturingssystemen wanneer een tweede socket probeert te binden aan een adres dat eerder is gebonden door een eerste socket met behulp van specifieke socketopties en een ander gebruikersaccount.

Eerst binden oproep Tweede bind call
Verstek SO_REUSEADDR SO_EXCLUSIVEADDRUSE
Jokerteken Specifiek Jokerteken Specifiek Wildcard Specifiek
Verstek Wildcard IN GEBRUIK TOEGANG TOEGANG TOEGANG IN GEBRUIK TOEGANG
Specifiek Succes IN GEBRUIK Succes TOEGANG INUSE IN GEBRUIK
SO_REUSEADDR Jokerteken IN GEBRUIK TOEGANG Succes Succes IN GEBRUIK TOEGANG
Specifiek Succes IN GEBRUIK Succes Succes IN GEBRUIK IN GEBRUIK
SO_EXCLUSIVEADDRUSE Wildcard In gebruik TOEGANG TOEGANG TOEGANG IN GEBRUIK TOEGANG
Specifiek Succes IN GEBRUIK Succes TOEGANG IN GEBRUIK In gebruik

Houd er rekening mee dat het standaardgedrag verschilt wanneer de bindt aanroepen worden uitgevoerd onder verschillende gebruikersaccounts. Als de eerste beller geen opties op de socket instelt en verbinding maakt met het jokertekenadres, kan de tweede beller de optie SO_REUSEADDR niet instellen en met succes verbinden met dezelfde poort. Het standaardgedrag zonder optieset retourneert ook een fout.

Op Windows Vista en hoger kan een dubbele stack socket worden gemaakt die werkt via zowel IPv6 als IPv4. Wanneer een dual stack socket is gebonden aan het wildcardadres, wordt de opgegeven poort gereserveerd op zowel de IPv4- als IPv6-netwerkstacks en worden de controles uitgevoerd die zijn gekoppeld aan SO_REUSEADDR en SO_EXCLUSIVEADDRUSE (indien ingesteld). Deze testen moeten slagen op beide netwerkstacks. Als bijvoorbeeld een TCP-socket met twee stacks SO_EXCLUSIVEADDRUSE instelt en vervolgens verbinding probeert te maken met poort 5000, kan er geen andere TCP-socket eerder worden gebonden aan poort 5000 (jokerteken of specifiek). In dit geval, als een IPv4-TCP-socket eerder was gebonden aan het loopback-adres op poort 5000, zou de bind-aanroep voor de dual stack socket mislukken met WSAEACCES.

Toepassingsstrategieën

Bij het ontwikkelen van netwerktoepassingen die op de socketlaag werken, is het belangrijk om rekening te houden met het type socketbeveiliging dat nodig is. Clienttoepassingen, toepassingen die verbinding maken met of gegevens verzenden naar een service, vereisen zelden aanvullende stappen omdat ze verbinding maken met een willekeurige lokale (tijdelijke) poort. Als de client wel een specifieke lokale poortbinding nodig heeft om correct te kunnen functioneren, moet u rekening houden met socketbeveiliging.

De optie SO_REUSEADDR heeft weinig gebruik in normale toepassingen, afgezien van multicast-sockets waar gegevens worden geleverd aan alle sockets die op dezelfde poort zijn gebonden. Anders moet elke toepassing die deze socketoptie instelt, opnieuw worden ontworpen om de afhankelijkheid te verwijderen, omdat deze zeer kwetsbaar is voor 'socket hijacking'. Zolang SO_REUSEADDR socketoptie kan worden gebruikt om mogelijk een poort in een servertoepassing te kapen, moet de toepassing worden beschouwd als niet veilig.

Alle servertoepassingen moeten SO_EXCLUSIVEADDRUSE instellen voor een sterk socketbeveiligingsniveau. Het voorkomt niet alleen dat schadelijke software de poort kapt, maar geeft ook aan of een andere toepassing is gebonden aan de aangevraagde poort. Een aanroep van om te binden op het wildcard-adres door een proces met de SO_EXCLUSIVEADDRUSE socketoptie mislukt bijvoorbeeld als een ander proces momenteel op dezelfde poort op een specifieke interface is gebonden.

Ten slotte moet een toepassing, ook al is socketbeveiliging verbeterd in Windows Server 2003, altijd de SO_EXCLUSIVEADDRUSE socketoptie instellen om ervoor te zorgen dat deze wordt gekoppeld aan alle specifieke interfaces die het proces heeft aangevraagd. De socketbeveiliging in Windows Server 2003 voegt een verhoogd beveiligingsniveau toe voor verouderde toepassingen, maar toepassingsontwikkelaars moeten hun producten nog steeds ontwerpen met alle aspecten van beveiliging in gedachten.