In Java, normalmente i controlli delle autorizzazioni sono gestiti da SecurityManager. Per impedire a codice non affidabile di richiamare codice privilegiato e sfruttare qualche bug nel codice privilegiato, SecurityManager controlla l'intero stack di chiamate; se qualcuno dei chiamanti nella traccia dello stack non ha privilegi, per impostazione predefinita la richiesta viene negata. Almeno, è come funzionano gli assegni standard di SecurityManager .
Tuttavia, alcune API Java speciali seguono regole diverse. Ignorano i controlli standard di SecurityManager e sostituiscono un controllo più debole. In particolare, controllano solo il chiamante immediato, non l'intero stack di chiamate. Per ulteriori dettagli, consulta la Linea guida 9-8 delle Linee guida per la codifica sicura di Java . includi, ad esempio, Class.forName()
, Class.getMethod()
e altro.)
Perché? Perché queste API speciali ignorano i controlli standard e sostituiscono un controllo più debole? E perché questo è sicuro? In altre parole, perché è sufficiente che controllino solo il chiamante immediato? Questo non reintroduce tutti i rischi che i controlli standard di SecurityManager sono stati progettati per difendersi da?
L'ho saputo per la prima volta leggendo un'analisi del recente exploit Java zero-day (CVE-2012-4681). Questa analisi decostruisce come funziona l'exploit. Tra le altre cose, l'attacco consiste nel trarre vantaggio dal controllo più debole effettuato da queste API speciali. In particolare, il codice Java dannoso riesce a ottenere un riferimento a una classe di sistema attendibile (attraverso un bug separato), quindi ingannevole quella classe di sistema attendibile a richiamare una di queste API speciali. Il controllo delle autorizzazioni risultante esamina solo il chiamante immediato, rileva che il chiamante immediato è affidabile e consente l'operazione, anche se l'operazione è stata originariamente avviata da codice non attendibile. Quindi i controlli più deboli non fermano l'attacco, ma per quanto posso vedere, questo attacco sarebbe stato prevenuto usando i controlli standard di SecurityManager (dal momento che il chiamante non è attendibile). In altre parole, questo recente attacco sembra un esempio del perché il controllo più debole è rischioso.
Tuttavia, so che i designer Java sono persone intelligenti. Ho il sospetto che i progettisti Java debbano aver considerato questi problemi e avere qualche buona ragione per aggirare i controlli standard e sostituire i controlli più deboli per queste API speciali - o, almeno, hanno pensato che avessero una buona ragione per cui questo era sicuro. Quindi, forse mi manca qualcosa.
Qualcuno può far luce su questo? I progettisti Java hanno fallito con queste API speciali, o c'erano validi motivi per sostituire i controlli più deboli?
Modifica 9/1: non sto chiedendo come funziona l'exploit; Penso di capire come funziona l'exploit. Non sto nemmeno chiedendo perché, in questo particolare esempio, il codice attendibile che ha invocato queste API speciali era buggato. Piuttosto, sto chiedendo perché le API speciali - come Class.forName()
, Class.getMethod()
, e così via - siano specificate e implementate per usare il controllo dei permessi non standard più debole (guarda solo al chiamante immediato) invece del controllo permesso standard di SecurityManager (guarda l'intero stack di chiamate). Questa decisione progettuale (l'utilizzo di controlli delle autorizzazioni più deboli per tali API speciali) ha consentito la recente vulnerabilità, quindi sarebbe facile criticare la decisione di progettazione. Tuttavia, immagino che ci potrebbero essere state alcune buone ragioni per fare le cose in questo modo, e mi chiedo cosa potrebbero essere quelle.