Uso di SO_REUSEADDR e SO_EXCLUSIVEADDRUSE
Lo sviluppo di un'infrastruttura di rete di alto livello sicura è 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 associata in precedenza da un altro processo dell'applicazione. In passato, era possibile che un'applicazione di rete potesse dirottare la porta di un'altra applicazione, il che poteva facilmente causare un attacco di negazione del servizio o un furto di dati.
In generale, la sicurezza 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 dell'ip datagram. Queste applicazioni in genere si associano a una porta nota e sono destinazioni comuni per il codice di rete dannoso.
Le applicazioni client hanno meno probabilità di essere 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 nome parametro quando si chiama la funzione di associazione) a meno che non esista un motivo architetturale interessante. 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 le richieste di associazione tra le 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 socket avanzata è disponibile in Windows Server 2003 e versioni successive. La disponibilità di queste opzioni socket e la sicurezza del socket avanzata variano 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 successive | Disponibile | Disponibile | Disponibile |
Uso di SO_REUSEADDR
L'opzione socket SO_REUSEADDR consente a un socket di associarsi forzatamente a una porta in uso da un altro socket. Il secondo socket chiama setsockopt con il parametro optname impostato a SO_REUSEADDR e il parametro optval impostato a un valore booleano di 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 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 è costituito dai socket multicast. Se due socket sono associati alla stessa interfaccia e alla stessa 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 SO_EXCLUSIVEADDRUSE, uno sviluppatore di applicazioni di rete poteva fare ben poco per impedire a un programma dannoso di eseguire il binding alla porta alla quale 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 di TRUE prima dell'associazione del socket. Dopo aver configurato l'opzione, il comportamento delle successive chiamate di bind varia, a seconda dell'indirizzo di rete specificato in ogni chiamata di bind .
La tabella seguente descrive il comportamento che si verifica in Windows XP e versioni precedenti quando un secondo socket tenta di eseguire il binding a un indirizzo precedentemente associato 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.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 se viene restituito un errore ("INUSE" per il WSAEADDRINUSE errore; "ACCESS" per l'errore di WSAEACCES).
Prima chiamata binding | Second bind call | ||||||
Predefinito | SO_REUSEADDR | SO_EXCLUSIVEADDRUSE | |||||
Carattere jolly | Specifico | Jolly | Specifico | Carattere jolly | Specifico | ||
Predefinito | Jolly | INUSE | INUSE | Successo | Successo | INUSE | INUSE |
Specifico | INUSE | INUSE | Successo | Successo | INUSE | In uso | |
SO_REUSEADDR | Carattere jolly | INUSE | INUSE | Successo | Successo | INUSE | In uso |
Specifico | INUSE | INUSE | Successo | Successo | In uso | In uso | |
SO_EXCLUSIVEADDRUSE | Carattere wildcard | INUSE | INUSE | ACCESSO | ACCESSO | INUSE | INUSE |
Specifico | In uso | In uso | ACCESSO | ACCESSO | 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 abbia due interfacce IP, 10.0.0.1 e 10.99.99.99, se la prima chiamata a binding è 10.0.0.1 con la porta impostata su 5150 e SO_EXCLUSIVEADDRUSE specificata, una seconda chiamata a associare su 10.99.99.99 con la porta impostata anche su 5150 e nessuna opzione specificata avrà esito positivo. Tuttavia, se il primo socket è associato all'indirizzo con caratteri jolly e alla porta 5150, qualsiasi chiamata di bind successiva alla porta 5150 con SO_EXCLUSIVEADDRUSE impostato avrà esito negativo con WSAEADDRINUSE o WSAEACCES restituito dall'operazione di bind .
Nel caso in cui la prima chiamata a bind imposti SO_REUSEADDR o nessuna opzione di socket, la seconda chiamata bind sottrarrebbe 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 uso esclusivo, a meno che non venga chiamata l'opzione socket SO_EXCLUSIVEADDRUSE sul socket prima della chiamata alla funzione di associazione . Se un'applicazione client viene associata a una porta temporanea o a una porta specifica prima che un'applicazione server venga associata alla stessa porta, possono verificarsi problemi. L'applicazione server può essere associata forzatamente alla stessa porta usando l'opzione socket SO_REUSEADDR sul socket prima di chiamare la funzione di associazione , ma il comportamento per tutti i socket associati a tale porta viene 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 in ascolto con SO_EXCLUSIVEADDRUSE impostato accetta una connessione e viene successivamente chiuso, un altro socket (anch'esso con SO_EXCLUSIVEADDRUSE) non può essere associato alla stessa porta del primo socket finché 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 normale al peer e attendere un messaggio di disconnessione normale corrispondente dal peer. È possibile che il protocollo di trasporto sottostante non rilasci mai la connessione; Ad esempio, il peer che partecipa alla connessione originale potrebbe annunciare una finestra di dimensioni zero o un'altra forma di configurazione di "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 controllato chiamando shutdown con il flag SD_SEND impostato e quindi attendere in un ciclo recv fino a che vengono restituiti zero byte sulla connessione. Ciò garantisce che tutti i dati vengano ricevuti dal peer e conferma allo stesso tempo al peer che ha ricevuto tutti i dati trasmessi, oltre a evitare il problema menzionato del riutilizzo della porta.
L'opzione socket SO_LINGER può essere impostata su un socket per impedire la transizione della porta a uno stato di attesa "attivo". Tuttavia, questo è sconsigliato perché può portare a effetti indesiderati, ad esempio la reimpostazione delle connessioni. Ad esempio, se i dati vengono ricevuti dal peer ma rimangono non riconosciuti 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 rimossi dal peer. La selezione di un tempo appropriato per rimanere è difficile perché un valore di timeout più piccolo spesso comporta connessioni interrotte improvvisamente, mentre valori di timeout più grandi lasciano il sistema vulnerabile agli attacchi Denial of Service (stabilendo molte connessioni e potenzialmente bloccando o bloccando thread dell'applicazione). La chiusura di un socket con un valore di timeout non zero può anche causare la closesocket chiamata a bloccarsi.
Sicurezza socket avanzata
La sicurezza avanzata dei socket è stata aggiunta con la versione di Windows Server 2003. Nelle versioni precedenti del sistema operativo del server Microsoft, la sicurezza del socket predefinita consente facilmente ai processi di dirottare le porte da applicazioni insospettabili. In Windows Server 2003 i socket non sono condivisibili 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 tal caso, il primo socket da chiamare per legare sulla porta deve avere impostato SO_REUSEADDR sul socket. L'unica eccezione a questo caso si verifica quando la seconda binding chiamata viene eseguita dallo stesso account utente che ha eseguito la chiamata originale a binding. Questa eccezione esiste esclusivamente 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 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 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 l'errore restituito ("INUSE" per l'errore WSAEADDRINUSE; "ACCESS" per l'errore di WSAEACCES).
Si noti anche che in questa tabella specifica, entrambe le chiamate legano vengono effettuate con lo stesso account utente.
Prima chiamata binding | Secondo bind chiamata | ||||||
Impostazione predefinita | SO_REUSEADDR | SO_EXCLUSIVEADDRUSE | |||||
Carattere jolly | Specifico | Jolly | Specifico | Carattere jolly | Specifico | ||
Predefinito | Metacarattere | INUSE | Successo | ACCESSO | Successo | INUSE | Successo |
Specifico | Successo | INUSO | Successo | ACCESSO | INUSE | INUSE | |
SO_REUSEADDR | Jolly | INUSE | Successo | Successo | Successo | INUSE | Successo |
Specifico | Successo | In Uso | Successo | Successo | INUSE | INUSE | |
SO_EXCLUSIVEADDRUSE | Carattere jolly | INUSE | ACCESSO | ACCESSO | ACCESSO | INUSE | ACCESSO |
Specifico | Successo | INUSE | Successo | ACCESSO | In Uso | 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 associare con un indirizzo con caratteri jolly sulla stessa porta, la seconda chiamata di associare 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 è vero: se il primo chiamante imposta SO_EXCLUSIVEADDRUSE e chiama bind con il flag wildcard, il secondo chiamante non è in grado di chiamare bind 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 binding | Secondo bind call | ||||||
Predefinito | SO_REUSEADDR | SO_EXCLUSIVEADDRUSE (uso esclusivo dell'indirizzo) | |||||
Wildcard | Specifico | Carattere jolly | Specifico | Carattere jolly | Specifico | ||
Predefinito | Carattere jolly | INUSE | ACCESSO | ACCESSO | ACCESSO | INUSE | ACCESSO |
Specifico | Successo | in uso | Successo | ACCESSO | INUSE | INUSE | |
SO_REUSEADDR | Carattere jolly | INUSE | ACCESSO | Successo | Successo | INUSE | ACCESSO |
Specifico | Successo | In uso | Successo | Successo | INUSE | INUSE | |
SO_EXCLUSIVEADDRUSE | Jolly | INUSE | ACCESSO | ACCESSO | ACCESSO | INUSE | ACCESSO |
Specifico | Successo | in uso | Successo | ACCESSO | INUSO | INUSE |
Si noti che il comportamento predefinito è diverso quando il associare chiamate vengono effettuate con account utente diversi. Se il primo chiamante non imposta alcuna opzione sul socket e 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 socket dual stack è associato all'indirizzo jolly, la porta specificata è riservata sia negli stack di rete IPv4 che in IPv6 e ai controlli effettuati con SO_REUSEADDR e SO_EXCLUSIVEADDRUSE (se impostati). 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 eseguire l'associazione 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 fallirebbe con WSAEACCES.
Strategie dell'applicazione
Quando si sviluppa un'applicazione di rete che opera a livello di socket, è importante considerare il tipo di sicurezza del socket necessario. Le applicazioni client, ovvero applicazioni che si connettono o inviano dati a un servizio, richiedono raramente passaggi aggiuntivi perché si associano a una porta locale casuale (temporanea). Se il client richiede un'associazione di porte locale specifica per funzionare correttamente, è necessario prendere in considerazione la sicurezza del socket.
L'opzione SO_REUSEADDR ha pochissimi usi nelle normali applicazioni a parte i 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 di socket deve essere riprogettata per rimuovere la dipendenza, poiché è estremamente vulnerabile al "dirottamento di socket". Finché l'opzione socket SO_REUSEADDR può essere usata per potenzialmente dirottare una porta in un'applicazione server, l'applicazione deve essere considerata non sicura.
Tutte le applicazioni server devono impostare SO_EXCLUSIVEADDRUSE per un livello di sicurezza del socket elevato. Non solo impedisce al software dannoso di dirottare la porta, ma indica anche se un'altra applicazione è associata alla porta richiesta. Ad esempio, una chiamata a per associare all'indirizzo wildcard da un processo con le opzioni socket SO_EXCLUSIVEADDRUSE impostate fallirà se un altro processo è attualmente vincolato alla stessa porta su un'interfaccia specifica.
Infine, anche se la sicurezza socket è stata migliorata in Windows Server 2003, un'applicazione deve sempre impostare l'opzione socket SO_EXCLUSIVEADDRUSE per assicurarsi che sia associato 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 tenendo presenti tutti gli aspetti della sicurezza.