Uso di SO_REUSEADDR e SO_EXCLUSIVEADDRUSE

Lo sviluppo di un'infrastruttura di rete di alto livello sicuro è una priorità per la maggior parte degli sviluppatori di applicazioni di rete. Tuttavia, la sicurezza dei socket viene spesso trascurata nonostante sia molto critica quando si considera una soluzione completamente sicura. La sicurezza dei socket, in particolare, gestisce i processi che si associano alla stessa porta precedentemente associata da un altro processo dell'applicazione. In passato, è stato possibile che un'applicazione di rete "dirotta" la porta di un'altra applicazione, che potrebbe facilmente portare a un attacco "Denial of Service" o a un furto di dati.

In generale, la sicurezza dei socket si applica ai processi lato server. In particolare, la sicurezza socket si applica a qualsiasi applicazione di rete che accetta connessioni e riceve il traffico del datagramma IP. Queste applicazioni in genere si associano a una porta nota e sono destinazioni comuni per il codice di rete dannoso.

È meno probabile che le applicazioni client siano le destinazioni di tali attacchi, non perché sono meno vulnerabili, ma perché la maggior parte dei client è associata a porte locali "temporanee" anziché a porte statiche di "servizio". Le applicazioni di rete client devono sempre essere collegate alle porte temporanee (specificando la porta 0 nella struttura SOCKADDR a cui punta il parametro name quando si chiama la funzione di associazione ), a meno che non vi sia un motivo architettonico interessante da non usare. Le porte locali temporanee sono costituite da porte maggiori della porta 49151. La maggior parte delle applicazioni server per i servizi dedicati è associata a una porta riservata nota minore o uguale alla porta 49151. Pertanto, per la maggior parte delle applicazioni, in genere non esiste un conflitto per associare le richieste tra applicazioni client e server.

Questa sezione descrive il livello di sicurezza predefinito in varie piattaforme Di Microsoft Windows e il modo in cui le opzioni socket specifiche SO_REUSEADDR e SO_EXCLUSIVEADDRUSE impatto e influiscono sulla sicurezza delle applicazioni di rete. Una funzionalità aggiuntiva denominata sicurezza avanzata dei socket è disponibile in Windows Server 2003 e versioni successive. La disponibilità di queste opzioni socket e la sicurezza avanzata dei socket varia in base alle versioni dei sistemi operativi Microsoft, come illustrato nella tabella seguente.

Piattaforma SO_REUSEADDR SO_EXCLUSIVEADDRUSE Sicurezza avanzata dei socket
Windows 95 Disponibile Non disponibile Non disponibile
Windows 98 Disponibile Non disponibile Non disponibile
Windows Me Disponibile Non disponibile Non disponibile
Windows NT 4.0 Disponibile Disponibile in Service Pack 4 e versioni successive Non disponibile
Windows 2000 Disponibile Disponibile Non disponibile
Windows XP Disponibile Disponibile Non disponibile
Windows Server 2003 Disponibile Disponibile Disponibile
Windows Vista Disponibile Disponibile Disponibile
Windows Server 2008 Disponibile Disponibile Disponibile
Windows 7 e versioni più recenti Disponibile Disponibile Disponibile

Uso di SO_REUSEADDR

L'opzione socket SO_REUSEADDR consente a un socket di associare forzatamente a una porta in uso da un altro socket. Il secondo socket chiama setsockopt con il parametro optname impostato su SO_REUSEADDR e il parametro optval impostato su un valore booleano TRUE prima di chiamare bind sulla stessa porta del socket originale. Una volta che il secondo socket è stato associato correttamente, il comportamento per tutti i socket associati a tale porta è indeterminato. Ad esempio, se tutti i socket sulla stessa porta forniscono il servizio TCP, non è possibile garantire che tutte le richieste di connessione TCP in ingresso sulla porta vengano gestite dal socket corretto. Il comportamento non è deterministico. Un programma dannoso può usare SO_REUSEADDR per associare forzatamente i socket già in uso per i servizi di protocollo di rete standard per negare l'accesso a tali servizi. Per usare questa opzione non sono necessari privilegi speciali.

Se un'applicazione client viene associata a una porta prima che un'applicazione server sia in grado di eseguire l'associazione alla stessa porta, potrebbero verificarsi problemi. Se l'applicazione server associa forzatamente usando l'opzione socket SO_REUSEADDR alla stessa porta, il comportamento per tutti i socket associati a tale porta è indeterminato.

L'eccezione a questo comportamento non deterministico è i socket multicast. Se due socket sono associati alla stessa interfaccia e porta e sono membri dello stesso gruppo multicast, i dati verranno recapitati a entrambi i socket, anziché a uno scelto arbitrariamente.

Uso di SO_EXCLUSIVEADDRUSE

Prima dell'introduzione dell'opzione socket di SO_EXCLUSIVEADDRUSE , c'era molto poco da fare uno sviluppatore di applicazioni di rete per impedire a un programma dannoso di eseguire il binding alla porta in cui l'applicazione di rete aveva i propri socket associati. Per risolvere questo problema di sicurezza, Windows Sockets ha introdotto l'opzione socket SO_EXCLUSIVEADDRUSE , che è diventata disponibile in Windows NT 4.0 con Service Pack 4 (SP4) e versioni successive.

L'opzione socket SO_EXCLUSIVEADDRUSE può essere usata solo dai membri del gruppo di sicurezza Administrators in Windows XP e versioni precedenti. I motivi per cui questo requisito è stato modificato in Windows Server 2003 e versioni successive sono descritti più avanti nell'articolo.

L'opzione SO_EXCLUSIVEADDRUSE viene impostata chiamando la funzione setsockopt con il parametro optname impostato su SO_EXCLUSIVEADDRUSE e il parametro optval impostato su un valore booleano TRUE prima che il socket sia associato. Dopo aver impostato l'opzione, il comportamento delle chiamate di associazione successive varia a seconda dell'indirizzo di rete specificato in ogni chiamata di associazione .

La tabella seguente descrive il comportamento che si verifica in Windows XP e versioni precedenti quando un secondo socket tenta di eseguire l'associazione a un indirizzo associato in precedenza a un primo socket usando opzioni socket specifiche.

Nota

Nella tabella seguente "carattere jolly" indica l'indirizzo con caratteri jolly per il protocollo specificato, ad esempio "0.0.0.0" per IPv4 e "::" per IPv6. "Specifico" indica un indirizzo IP specifico assegnato a un'interfaccia. Le celle della tabella indicano se l'associazione ha esito positivo ("Operazione riuscita") o viene restituito un errore ("INUSE" per l'errore WSAEADDRINUSE ; "ACCESS" per l'errore WSAEACCES .

Prima chiamata di associazione Seconda chiamata di associazione
Predefinito SO_REUSEADDR SO_EXCLUSIVEADDRUSE
Wildcard (Carattere jolly) Specifica Wildcard (Carattere jolly) Specifica Wildcard (Carattere jolly) Specifica
Predefinito Wildcard (Carattere jolly) INUSE INUSE Operazione completata Operazione completata INUSE INUSE
Specifica INUSE INUSE Operazione completata Operazione completata INUSE INUSE
SO_REUSEADDR Wildcard (Carattere jolly) INUSE INUSE Operazione completata Operazione completata INUSE INUSE
Specifica INUSE INUSE Operazione completata Operazione completata INUSE INUSE
SO_EXCLUSIVEADDRUSE Wildcard (Carattere jolly) INUSE INUSE ACCESS ACCESS INUSE INUSE
Specifica INUSE INUSE ACCESS ACCESS INUSE INUSE

Quando due socket sono associati allo stesso numero di porta, ma su interfacce esplicite diverse, non esiste alcun conflitto. Ad esempio, nel caso in cui un computer disponga di due interfacce IP, 10.0.0.1 e 10.99.99.99,99, se la prima chiamata all'associazione è 10.0.0.1 con la porta impostata su 5150 e SO_EXCLUSIVEADDRUSE specificata, verrà quindi eseguita una seconda chiamata a binding sulla 10.99.99.99 con la porta impostata anche su 5150 e non verranno specificate opzioni specificate. Tuttavia, se il primo socket è associato all'indirizzo jolly e alla porta 5150, qualsiasi chiamata di associazione successiva alla porta 5150 con SO_EXCLUSIVEADDRUSE set avrà esito negativo con WSAEADDRINUSE o WSAEACCES restituito dall'operazione di associazione .

Nel caso in cui la prima chiamata ai set di associazione SO_REUSEADDR o nessuna opzione socket, la seconda chiamata di associazione "hijack" la porta e l'applicazione non sarà in grado di determinare quale dei due socket ha ricevuto pacchetti specifici inviati alla porta "condivisa".

Un'applicazione tipica che chiama la funzione di associazione non alloca il socket associato per l'uso esclusivo, a meno che l'opzione socket SO_EXCLUSIVEADDRUSE venga chiamata sul socket prima della chiamata alla funzione di associazione . Se un'applicazione client viene associata a una porta temporaneo o a una porta specifica prima che un'applicazione server si associa alla stessa porta, i problemi possono causare. L'applicazione server può essere associata in modo forcibly alla stessa porta usando l'opzione socket SO_REUSEADDR nel socket prima di chiamare la funzione di associazione, ma il comportamento per tutti i socket associati a tale porta è quindi indeterminato. Se l'applicazione server tenta di usare l'opzione socket SO_EXCLUSIVEADDRUSE per l'uso esclusivo della porta, la richiesta avrà esito negativo.

Al contrario, un socket con il set di SO_EXCLUSIVEADDRUSE non può necessariamente essere riutilizzato immediatamente dopo la chiusura del socket. Ad esempio, se un socket di ascolto con SO_EXCLUSIVEADDRUSE set accetta una connessione e viene successivamente chiuso, un altro socket (anche con SO_EXCLUSIVEADDRUSE) non può essere associato alla stessa porta del primo socket fino a quando la connessione originale non diventa inattiva.

Questo problema può diventare complicato perché il protocollo di trasporto sottostante potrebbe non terminare la connessione anche se il socket è stato chiuso. Anche dopo che il socket è stato chiuso dall'applicazione, il sistema deve trasmettere tutti i dati memorizzati nel buffer, inviare un messaggio di disconnessione graziato al peer e attendere un messaggio di disconnessione grazia corrispondente dal peer. È possibile che il protocollo di trasporto sottostante non possa mai rilasciare la connessione; ad esempio, il peer che partecipa alla connessione originale potrebbe annunciare una finestra di dimensioni zero o un'altra forma di configurazione "attacco". In tal caso, la connessione client rimane in uno stato attivo nonostante la richiesta di chiuderla, poiché i dati non riconosciuti rimangono nel buffer.

Per evitare questa situazione, le applicazioni di rete devono garantire un arresto normale chiamando l'arresto con il flag di SD_SEND impostato e quindi attendere in un ciclo recv fino a quando non vengono restituiti zero byte sulla connessione. Ciò garantisce che tutti i dati vengano ricevuti dal peer e, analogamente, confermano con il peer che ha ricevuto tutti i dati trasmessi, oltre a evitare il problema di riutilizzo della porta precedente.

L'opzione SO_LINGER socket può essere impostata su un socket per impedire la transizione della porta a uno stato di attesa "attivo". tuttavia, questo è sconsigliato perché può causare effetti non indesiderati, ad esempio la reimpostazione delle connessioni. Ad esempio, se i dati vengono ricevuti dal peer, ma rimangono non riconosciuti da esso e il computer locale chiude il socket con SO_LINGER impostato su di esso, la connessione tra i due computer viene reimpostata e i dati non riconosciuti ignorati dal peer. La selezione di un tempo appropriato per il ritardo è difficile perché un valore di timeout più piccolo spesso comporta connessioni interrotte improvvisamente, mentre i valori di timeout più grandi lasciano il sistema vulnerabile agli attacchi denial-of-service (stabilendo molte connessioni e potenzialmente bloccando i thread dell'applicazione). La chiusura di un socket con un valore di timeout non zeroo può anche causare il blocco della chiamata closesocket .

Sicurezza del socket avanzata

La sicurezza del socket avanzata è stata aggiunta con la versione di Windows Server 2003. Nelle versioni precedenti del sistema operativo microsoft server, la sicurezza del socket predefinita consente facilmente di eseguire il hijack delle porte dalle applicazioni insospettabili. In Windows Server 2003 i socket non sono in uno stato condivisibile per impostazione predefinita. Pertanto, se un'applicazione vuole consentire ad altri processi di riutilizzare una porta su cui è già associato un socket, deve abilitarla in modo specifico. In caso affermativo, il primo socket da chiamare sulla porta deve avere SO_REUSEADDR impostato sul socket. L'unica eccezione a questo caso si verifica quando la seconda chiamata di associazione viene eseguita dallo stesso account utente che ha eseguito la chiamata originale per l'associazione. Questa eccezione esiste solo per garantire la compatibilità con le versioni precedenti.

La tabella seguente descrive il comportamento che si verifica nei sistemi operativi Windows Server 2003 e versioni successive quando un secondo socket tenta di associare un indirizzo a un indirizzo associato in precedenza a un primo socket usando opzioni di socket specifiche.

Nota

Nella tabella seguente "jolly" indica l'indirizzo jolly per il protocollo specificato, ad esempio "0.0.0.0" per IPv4 e "::" per IPv6. "Specifico" indica un indirizzo IP specifico assegnato a un'interfaccia. Le celle della tabella indicano se il binding ha esito positivo ("Success") o l'errore restituito ("INUSE" per l'errore WSAEADDRINUSE ; "ACCESS" per l'errore WSAEACCES .

Si noti anche che in questa tabella specifica vengono eseguite entrambe le chiamate di associazione nello stesso account utente.

Prima chiamata di associazione Seconda chiamata di associazione
Predefinito SO_REUSEADDR SO_EXCLUSIVEADDRUSE
Wildcard (Carattere jolly) Specifica Wildcard (Carattere jolly) Specifica Wildcard (Carattere jolly) Specifica
Predefinito Wildcard (Carattere jolly) INUSE Operazione riuscita ACCESS Operazione riuscita INUSE Operazione riuscita
Specifica Operazione riuscita INUSE Operazione riuscita ACCESS INUSE INUSE
SO_REUSEADDR Wildcard (Carattere jolly) INUSE Operazione completata Operazione completata Operazione completata INUSE Operazione riuscita
Specifica Operazione riuscita INUSE Operazione completata Operazione completata INUSE INUSE
SO_EXCLUSIVEADDRUSE Wildcard (Carattere jolly) INUSE ACCESS ACCESS ACCESS INUSE ACCESS
Specifica Operazione riuscita INUSE Operazione riuscita ACCESS INUSE INUSE

Alcune voci nella tabella precedente meritano una spiegazione.

Ad esempio, se il primo chiamante imposta SO_EXCLUSIVEADDRUSE su un indirizzo specifico e il secondo chiamante tenta di chiamare binding con un indirizzo con caratteri jolly sulla stessa porta, la seconda chiamata di associazione avrà esito positivo. In questo caso specifico, il secondo chiamante è associato a tutte le interfacce tranne l'indirizzo specifico a cui è associato il primo chiamante. Si noti che il contrario di questo caso non è true: se il primo chiamante imposta SO_EXCLUSIVEADDRUSE e chiama associa con il flag con caratteri jolly, il secondo chiamante non è in grado di chiamare binding con la stessa porta.

Il comportamento di associazione socket cambia quando le chiamate di associazione socket vengono eseguite con account utente diversi. La tabella seguente specifica il comportamento che si verifica nei sistemi operativi Windows Server 2003 e versioni successive quando un secondo socket tenta di eseguire l'associazione a un indirizzo associato in precedenza a un primo socket usando opzioni socket specifiche e un account utente diverso.

Prima chiamata di associazione Seconda chiamata di associazione
Predefinito SO_REUSEADDR SO_EXCLUSIVEADDRUSE
Wildcard (Carattere jolly) Specifica Wildcard (Carattere jolly) Specifica Wildcard (Carattere jolly) Specifica
Predefinito Wildcard (Carattere jolly) INUSE ACCESS ACCESS ACCESS INUSE ACCESS
Specifica Operazione riuscita INUSE Operazione riuscita ACCESS INUSE INUSE
SO_REUSEADDR Wildcard (Carattere jolly) INUSE ACCESS Operazione completata Operazione completata INUSE ACCESS
Specifica Operazione riuscita INUSE Operazione completata Operazione completata INUSE INUSE
SO_EXCLUSIVEADDRUSE Wildcard (Carattere jolly) INUSE ACCESS ACCESS ACCESS INUSE ACCESS
Specifica Operazione riuscita INUSE Operazione riuscita ACCESS INUSE INUSE

Si noti che il comportamento predefinito è diverso quando le chiamate di associazione vengono effettuate con account utente diversi. Se il primo chiamante non imposta alcuna opzione sul socket e si associa all'indirizzo con caratteri jolly, il secondo chiamante non può impostare l'opzione SO_REUSEADDR e associarla correttamente alla stessa porta. Il comportamento predefinito senza set di opzioni restituisce anche un errore.

In Windows Vista e versioni successive è possibile creare un dual stack socket che funziona sia su IPv6 che su IPv4. Quando un dual stack socket è associato all'indirizzo con caratteri jolly, la porta specificata è riservata negli stack di rete IPv4 e IPv6 e i controlli associati a SO_REUSEADDR e SO_EXCLUSIVEADDRUSE (se impostato). Questi controlli devono avere esito positivo in entrambi gli stack di rete. Ad esempio, se un socket TCP dual stack imposta SO_EXCLUSIVEADDRUSE e quindi tenta di associare alla porta 5000, nessun altro socket TCP può essere associato in precedenza alla porta 5000 (carattere jolly o specifico). In questo caso, se un socket TCP IPv4 è stato associato in precedenza all'indirizzo di loopback sulla porta 5000 , la chiamata di associazione per il socket dual stack avrà esito negativo con WSAEACCES.

Strategie dell'applicazione

Quando si sviluppa un'applicazione di rete che opera a livello di socket, è importante considerare il tipo di sicurezza socket necessario. Applicazioni client: applicazioni che si connettono o inviano dati a un servizio, raramente richiedono eventuali passaggi aggiuntivi perché si associano a una porta locale casuale (effimero). Se il client richiede un'associazione di porte locale specifica per funzionare correttamente, è necessario considerare la sicurezza del socket.

L'opzione SO_REUSEADDR include pochissimi usi nelle normali applicazioni, oltre ai socket multicast in cui i dati vengono recapitati a tutti i socket associati alla stessa porta. In caso contrario, qualsiasi applicazione che imposta questa opzione socket deve essere riprogettata per rimuovere la dipendenza poiché è estremamente vulnerabile al "hijacking socket". Purché SO_REUSEADDR opzione socket possa essere usata per eseguire l'hijack di una porta in un'applicazione server, l'applicazione deve essere considerata non sicura.

Tutte le applicazioni server devono impostare SO_EXCLUSIVEADDRUSE per un livello elevato di sicurezza del socket. Non solo impedisce al software dannoso di eseguire il hijacking della porta, ma indica anche se un'altra applicazione è associata alla porta richiesta. Ad esempio, una chiamata all'associazione all'indirizzo jolly di un processo con il set di opzioni socket SO_EXCLUSIVEADDRUSE avrà esito negativo se un altro processo è attualmente associato alla stessa porta in un'interfaccia specifica.

Infine, anche se la sicurezza del socket è stata migliorata in Windows Server 2003, un'applicazione deve sempre impostare l'opzione socket SO_EXCLUSIVEADDRUSE per assicurarsi che si associa a tutte le interfacce specifiche richieste dal processo. La sicurezza socket in Windows Server 2003 aggiunge un maggiore livello di sicurezza per le applicazioni legacy, ma gli sviluppatori di applicazioni devono ancora progettare i propri prodotti con tutti gli aspetti della sicurezza.