Does the attack prevent open forwarding in nodejs?

I am trying to prevent an open forwarding attack. Take a look at the code below and check the security:

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); }); 

Is this enough to prevent an open call forwarding attack, or should I add something else?

+5
source share
2 answers

CWE-601: Redirecting URL to untrusted site ('Open Redirect')

Description of Open Redirect :

The http parameter may contain a URL value and may cause the web application to redirect the request to the specified URL. By changing the value of the URL to a malicious site, an attacker can successfully launch phishing scams and steal user credentials. Since the server name in the modified link is identical to the original site, phishing attempts have a more reliable appearance.

input validation strategy recommendation to prevent an open redirect attack:

Suppose all input is malicious. Use the โ€œacknowledge wellโ€ admission strategy, i.e. Use a whitelist of valid input that strictly conforms to the specifications. Reject any input that is strictly out of specification or converts it into something that does. Do not rely solely on the search for malicious or incorrect input data (i.e. do not rely on the blacklist). A blacklist is likely to miss at least one unwanted entry, especially if the code environment changes. This can give attackers enough room to circumvent the alleged test. However, blacklists can be useful in detecting potential attacks or determining which entries are so distorted that they should be rejected directly. Use a whitelist of the approved URLs or domains that will be used for redirection.

Using req.headers.host , req.host or req.hostname unsafe because req.headers can be faked (for example, an HTTP request has its own Host header to access the express application written in the code below)

 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); }); 

Use curl to make a request:

 $ 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] 

I suggest you use a whitelist to validate your input, sample code below:

 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); }); 
+4
source

In this situation, I would use HMAC . This will allow the login controller to verify that the redirect parameter was created by someone who knows the secret key.

When you create the "login" URL, you add the redirect HMAC digest parameter URL along with the redirect parameter itself to the address.

The login handler can use HMAC to ensure that the redirect parameter was created by a trusted server that knows the HMAC secret key, thereby preventing open redirect attacks.

eg.

 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; } 
+1
source

All Articles