2016-06-06 48 views
5

Sto tentando di impedire l'attacco di reindirizzamento aperto. Si prega di guardare il codice sottostante e verifica per la sicurezza:Sta impedendo l'attacco di reindirizzamenti aperti su nodejs sicuro?

var = require('url'); 

// http://example.com/login?redirect=http://example.com/dashboard 
app.route('/login', function (req, res, next) { 
    var redirect = req.query.redirect, 
     paths = url.parse(redirect); 

    if (paths.host !== req.headers.host) { 
     return next(new Error('Open redirect attack detected')); 
    } 

    return res.redirect(redirect); 
}); 

è sufficiente per prevenire l'attacco di reindirizzamento aperto o devo aggiungere altro?

+1

potrebbe essere più facile da usare 'reindirizzare = dashboard' e poi l'utilizzo di server' res.redirect ('http://example.com/' + req.query.redirect); 'questo modo il reindirizzamento sarà mai andare via dal tuo server. – Molda

+0

Grazie. Come non inserire hardcode 'http: // example.com /' in 'res.redirect' ma usare' req.host' o qualcosa di simile? – Erik

+0

'res.redirect ('http: //' + req.host + '/' + req.query.redirect)' – Molda

risposta

4

CWE-601: URL Redirection to Untrusted Site ('Open Redirect')

descrizione Open Redirect:

Un parametro http può contenere un valore URL e potrebbe causare l'applicazione Web per reindirizzare la richiesta all'URL specificato. Modificando il valore dell'URL su un sito dannoso, un utente malintenzionato può avviare correttamente una truffa di phishing e rubare le credenziali dell'utente. Poiché il nome del server nel collegamento modificato è identico al sito originale, i tentativi di phishing hanno un aspetto più affidabile.

Il suggerimento di input validation strategia per prevenire aperta attacco di reindirizzamento:

assumere tutte ingresso è dannoso. Utilizzare una strategia di convalida dell'input "accetta noto", ovvero utilizzare una whitelist di input accettabili che siano strettamente conformi alle specifiche. Rifiuta qualsiasi input che non è strettamente conforme alle specifiche o trasformalo in qualcosa che lo fa. Non affidarsi esclusivamente alla ricerca di input malevoli o malformati (ad esempio, non fare affidamento su una lista nera). Una lista nera rischia di perdere almeno un input indesiderato, specialmente se l'ambiente del codice cambia. Questo può dare agli attaccanti spazio sufficiente per aggirare la convalida prevista. Tuttavia, le liste nere possono essere utili per individuare potenziali attacchi o determinare quali input sono così malformati da dover essere respinti in modo definitivo. Utilizzare una whitelist di URL o domini approvati da utilizzare per il reindirizzamento.

Usa req.headers.host, req.host o req.hostname è insicuro, perché req.headers possono essere contraffatti (ad es. Una richiesta HTTP avete l'usanza Host intestazione per accedere a un'applicazione esplicito scritto nel codice qui sotto)

var url = require('url'); 

app.get('/login', function (req, res, next) { 
    var redirect = req.query.redirect, 
     targetUrl = url.parse(redirect); 
    console.log('req.headers.host: [%s]', req.headers.host); 
    console.log('req.host: [%s]', req.host); 
    console.log('req.hostname: [%s]', req.hostname); 
    if (targetUrl.host != req.headers.host) { 
     return next(new Error('Open redirect attack detected')); 
    } 
    return res.redirect(redirect); 
}); 

Usa curl per fare una richiesta:

$ curl -H 'Host: malicious.example.com' 'http://localhost:3012/login?redirect=http://malicious.example.com' -i 
HTTP/1.1 302 Found 
X-Powered-By: Express 
Location: http://malicious.example.com 
Vary: Accept 
Content-Type: text/plain; charset=utf-8 
Content-Length: 54 
Date: Mon, 13 Jun 2016 06:30:55 GMT 
Connection: keep-alive 

$ #server output 
req.headers.host: [malicious.example.com] 
req.host: [malicious.example.com] 
req.hostname: [malicious.example.com] 

vi suggerisco di utilizzare whitelist per convalidare l'input, un codice di esempio sotto:

const WHITELIST_TO_REDIRECT = new Set(["localhost:3012", "www.realdomain.com"]); 

app.get('/login', function (req, res, next) { 
    var redirect = req.query.redirect, 
     targetUrl = url.parse(redirect); 
    console.log("req.hostname: [%s]", req.hostname); 
    console.log("url.host: [%s]", targetUrl.host); 
    if (!WHITELIST_TO_REDIRECT.has(targetUrl.host)) { 
     return next(new Error('Open redirect attack detected')); 
    } 

    return res.redirect(redirect); 
}); 
+0

Grazie per la risposta. È possibile non utilizzare la whitelist ma alcune convalide tramite regexp? – Erik

+0

Sicuro. La regexp rappresenta anche una gamma di whitelist 'whitelist', white list hardcode solo più chiaramente quando la whitelist non è troppo lunga. – Shawyeok

+0

Se l'intestazione host è stata falsificata dal browser dell'utente, quell'utente ha problemi di sicurezza molto più grandi. Mentre questo è un approccio ragionevole, non riesco a vedere quali sono le offerte rispetto a un controllo rispetto all'intestazione 'Host', dal punto di vista della sicurezza. – Brendon

1

In questa situazione, utilizzerei uno HMAC. Ciò consentirà al controller di accesso di verificare che il parametro redirect sia stato generato da qualcuno che conosce la chiave segreta.

Quando si genera l'URL di "accesso" si aggiunge un HMAC digest del parametro redirect all'URL insieme al parametro di reindirizzamento stesso.

Il gestore di accesso può utilizzare HMAC per garantire che il parametro redirect sia stato generato da un server trusted che conosce la chiave segreta HMAC impedendo in tal modo attacchi di reindirizzamento aperti.

ad es.

var crypto = require('crypto'); 
var secretKey = 'change-me'; 
var loginUrl = 'http://example.com/login' 

// called to work out where to redirect to for login 
function getLoginUrl(redirectBackUrl) { 
    var sig = crypto.createHmac('sha1', secretKey) 
        .update(redirectBackUrl) 
        .digest('hex'); 

    return loginUrl 
     + '?redirect=' 
     + encodeURIComponent(redirectBackUrl) 
     +'&sig=' + sig; 
} 

// called by the login function to ensure that the 
// redirect parameter is valid 
function isRedirectUrlValid(url, sig) { 
    var expectedSig 
      = crypto.createHmac('sha1', secretKey) 
        .update(url) 
        .digest('hex'); 

    return expectedSig === sig; 
}