Stiamo costruendo un'applicazione che utilizza LDAP via php e ho avuto modo di pensare che c'è qualcosa che puoi fare con l'iniezione in LDAP e meglio ancora come si protegge contro le iniezioni LDAP?come proteggere contro LDAP Injection
risposta
Quando si costruisce filtri LDAP è necessario assicurarsi che il filtro valori vengono gestiti secondo le RFC2254:
Qualsiasi carattere di controllo con un codice ACII < 32 così come i personaggi con un significato speciale nei filtri LDAP " * "," (",") "e" \ "(la barra rovesciata) vengono convertiti nella rappresentazione di una barra rovesciata seguita da due cifre esadecimali che rappresentano il valore esadecimale del carattere.
Zend_Ldap
per esempio utilizza le seguenti impostazioni
//[...]
$val = str_replace(array('\\', '*', '(', ')'), array('\5c', '\2a', '\28', '\29'), $val);
for ($i = 0; $i<strlen($val); $i++) {
$char = substr($val, $i, 1);
if (ord($char)<32) {
$hex = dechex(ord($char));
if (strlen($hex) == 1) $hex = '0' . $hex;
$val = str_replace($char, '\\' . $hex, $val);
}
}
//[...]
Nella maggior parte dei casi utilizza un account di sola lettura per LDAP. Poiché LDAP è scarso in scrittura, gli aggiornamenti si verificano solo in sezioni molto piccole dell'applicazione in cui è possibile utilizzare un altro account.
Anche in questo caso il linguaggio di query e la lingua di aggiornamento sono completamente separati.
Per evitare la visualizzazione di informazioni indesiderate, considerare tutti gli input dell'utente come contaminati e assicurarsi che i dati contaminati non vengano mai utilizzati prima di essere analizzati, puliti e correttamente fugati e copiati in una variabile pulita.
Analogamente si può prendere in considerazione solo il prelievo dei dati previsti dalla risposta e il ritorno per la visualizzazione.
"Per la protezione contro la visualizzazione di informazioni indesiderate trattare tutto l'input dell'utente come contaminato e assicurarsi che i dati grezzi sono mai usato prima di essere analizzato, puliti e adeguatamente fuggì e copiato in un ambiente pulito variabile." come si fa a fare questa è la domanda? – Chris
Un elemento da considerare è che un binding LDAP con un nome utente (DN) ma nessuna password è considerata un binding anonimo. Pertanto, dovresti testare per vedere se le credenziali passate possono collegarsi tramite LDAP per convalidare l'utente, se passano una password vuota e tu l'hai passata così com'è, potresti lasciare qualcuno in modo errato.
Grazie, questo capisco e non è davvero un'iniezione. – Chris
@Chris: concordato, non proprio un'iniezione, ma all'interno dello stesso problema di base dello spazio. – geoffc
Dopo aver letto questa risposta, ho immediatamente testato un'app in sviluppo e questo particolare problema non è stato rilevato, grazie! –
function ldap_quote($str) {
return str_replace(
array('\\', ' ', '*', '(', ')'),
array('\\5c', '\\20', '\\2a', '\\28', '\\29'),
$str
);
}
Sebbene questo codice possa rispondere alla domanda, fornire un contesto aggiuntivo riguardo a _how_ e/o _why_ risolve il problema migliorerebbe il valore a lungo termine della risposta. –
In PHP 5.6+ si dovrebbe utilizzare la funzione ldap_escape per i valori di filtro e RDNs. Come ad esempio:
// Escaping an LDAP filter for ldap_search ...
$username = ldap_escape($username, null, LDAP_ESCAPE_FILTER);
$filter = "(sAMAccountName=$username)";
// Escaping a DN to be used in an ldap_add, or a rename...
$rdn = ldap_escape('Smith, John', null, LDAP_ESCAPE_DN);
$dn = "cn=$rdn,dc=example,dc=local";
Inoltre, se si sta accettando l'input dell'utente per i nomi degli attributi nelle ricerche si dovrebbe essere la validazione che si tratta di un OID accettabile o nome di attributo. È possibile farlo con una funzione come questa:
/**
* Validate an attribute is an OID or a valid string attribute name.
*
* @param string
* @return bool
*/
function isValidAttributeFormat($value)
{
$matchOid = '/^[0-9]+(\.[0-9]+?)*?$/';
$matchDescriptor = '/^\pL([\pL\pN-]+)?$/iu';
return preg_match($matchOid, $value)
|| preg_match($matchDescriptor, $value);
}
$attribute = 'sAMAccountName';
$value = 'foo';
if (!isValidAttributeFormat($attribute)) {
throw new \InvalidArgumentException(sprintf('Invalid attribute name: %s', $attribute));
}
$value = ldap_escape($value, null, LDAP_ESCAPE_FILTER);
$filter = "($attribute=$value)";
Come posso disinfettare la password, poiché questi caratteri speciali sono consentiti? – Bastien974
Questo è esattamente ciò che fa il codice sopra ... trasforma caratteri speciali e li codifica. È proprio come gli URL, immagina se qualcuno inserisce un parametro & in, così lo converti.Solo perché la password del browser/ldap è intelligente e tenta di correggere questo errore, non significa che sia ancora consentito inviare caratteri speciali. – TravisO
Ho provato questa soluzione e non funziona correttamente. Ho dovuto sostituire una matrice di caratteri esadecimali con: array ("\ x5c", "\ x2a", "\ x28", "\ x29") per farlo funzionare. –