Security Tip: Avoid Open Redirects!
[Tip#16] Ever clicked a link that looked legitimate, but took you somewhere unexpected?
An Open Redirect vulnerability is where an attacker can trick the server into redirecting the victim somewhere specific, usually somewhere completely unrelated to the site the vulnerability is on. They are used to mask the final destination of a URL, so if the victim looks at the malicious open redirect link, all they see is a safe domain name at the beginning, not the real domain hiding at the end.
For example, consider an app that redirects a user to a login form with the intended authenticated URL in as a query string parameter.
A legitimate redirect could look like this:
https://example.com/login?redirect=/project/1
The user is shown the login form, and upon successful authentication, they are redirected to the “/project/1
” route.
But, if the redirect is “open”, an attacker could send a victim to this URL:
https://example.com/login?redirect=https://evilsite.com
The user would see the valid login form, but then be redirected to a malicious page that could be absolutely anything. Yes, it wouldn’t have cookies, session, or login details, but you can get quite creative with it.
What if the redirect existed on a URL that wasn’t a form endpoint, but rather responded to GET
requests to trigger the redirect?
Something like this:
GET https://example.com/redirect?url=https://evilsite.com
If you throw that in an email or on a website, and pad it out a bit, it’s easy for an attacker to show the victim only this bit before they click on it:
https://example.com/redirect?url=...
As far as the victim is concerned, they are going to your safe website at example.com
. But it will immediately redirect to the attacker’s evilsite.com
. That’s your site reputation they are using to trick their victims, and the victim may not trust your site again.
How do we mitigate this?
- Inject the redirect URL into the session. This only works in some instances (like auth redirects), but when it’s possible, it is definitely the best solution as the attacker cannot modify the redirect destination.
This is how Laravel does it by default with it’s authentication redirects. - Use an allow-list of domains and/or URLs. Only complete the redirect request if the domain and/or URL being redirected to is on the allow-list. This gives you the freedom to redirect to multiple locations in different scenarios, without opening the gates to redirect anywhere.
- Hard-code the list of redirections in code/configuration. Very similar to #2, but rather than allow a dynamic redirection through an allow-list of domains/URLs, have all redirections listed and reference them by an identifier.
redirect()->back()
While we’re talking about this subject, I want to very briefly mention redirect()->back()
, around which there is some discussion about open redirect vulnerabilities. redirect()->back()
uses the Referer
header to know where to redirect the user back to, which means it’s technically an Open Redirect vulnerability (as the referrer header could be anything).
It is important to note however that in order to abuse this vulnerability, you need to control the Referer
headers in the browser. This cannot be done without having a level of control in the browser or over the request that makes an open redirect vulnerability meaningless. If you can modify the request to change headers, you can modify it to do anything else you like too.
So in my opinion, redirect()->back()
is safe to use.
Found this security tip helpful? Don't forget to subscribe to receive new Security Tips each week, and upgrade to a premium subscription to receive monthly In Depth articles, or toss a coin in the tip jar.
Reach out if you're looking for a Laravel Security Audit and Penetration Test or a budget-friendly Security Review, and find me on the various socials through Pinkary. Finally, don't forget to check out Practical Laravel Security, my interactive security course.