How to prevent open redirect vulnerabilities in Laravel
Kevin Kimani
December 27, 2023
0 mins readAn open redirect vulnerability occurs when a website allows user-supplied input to influence the destination of a redirect without implementing proper validation or sanitization measures. To exploit this vulnerability, an attacker may send users a seemingly trustworthy link, which, when clicked, redirects them to a harmful website, potentially leading to phishing attacks or other malicious activities. In the context of Laravel, this often happens when developers don't validate or whitelist redirect destinations.
In this article, you'll learn more about open redirect vulnerabilities and how you can prevent them in Laravel. You'll also learn how to use Snyk to detect this vulnerability in your code and dependencies.
What Is an open redirect vulnerability in Laravel
Open redirect vulnerabilities occur when web applications permit external users to define a URL to which they'll be redirected. Often, this is after a user-triggered action, such as clicking a link or a button. This user-specified URL is commonly included as a query parameter in the application's URL.
For example, consider a vulnerable URL like: http://example.com/redirect?url=http://malicious-site.com
Without the proper validation and sanitization measures in place, the Laravel redirect method may inadvertently send users to the specified malicious site.
Create a vulnerable application
To better understand how an open redirect vulnerability works, let's create a simple vulnerable application. Later on, you'll implement methods to prevent this vulnerability.
To follow along, you need the following:
php-xml
andphp-curl
extensions installed on your local machine.Node.js and npm installed on your local machine.
A web browser and a code editor. This guide uses Visual Studio (VS) Code.
All the code for this tutorial is available in this GitHub repo.
Once you have everything ready to go, it's time to start creating the application.
Navigate to a suitable directory in your local machine, open the folder in a terminal, and execute the following commands to globally install the Laravel installer via Composer and create a new Laravel project:
composer global require laravel/installer
laravel new open-redirect-vulnerability-demo
If this command doesn't work, use composer create-project laravel/laravel open-redirect-vulnerability-demo
to create a new project.
In the prompts that appear in the terminal, select the following options:
Would you like to install a starter kit?: No starter kit
Which testing framework do you prefer?: PHPUnit
Would you like to initialize a Git repository?: No
Which database will your application use?: SQLite
After you've created the application, open the open-redirect-vulnerability-demo
directory in your code editor. Then, to create a route that has an open redirect vulnerability, open the routes/web.php
file and replace the /
route with the following code:
Route::get('/vulnerable', function (Request $request) {
// Get the 'redirect' parameter from the query string
$redirectUrl = $request->input('redirect');
// Perform the redirect
return redirect($redirectUrl);
});
Make sure you have the following use statement at the top of that web.php
file:
use Illuminate\Http\Request;
To show how the open redirect vulnerability works, run the server using the command php artisan serve
and open your web browser. In this scenario, https://www.google.com/
is the malicious URL that an attacker wants to redirect the user to.
In the browser, navigate to http://127.0.0.1:8000/vulnerable?redirect=https://www.google.com/
, which will redirect you to https://www.google.com/
.
The /vulnerable
route you created is vulnerable to an open redirect vulnerability due to a lack of input validation and sanitization. Specifically, it retrieves the redirect parameter from the URL and redirects to the specified web page without verifying whether the URL is safe or the URL is within the application's domain. Since the code blindly redirects users to the URL provided in the redirect parameter, the URL can be manipulated to trick users into visiting phishing sites, downloading malware, or engaging in other harmful activities.
In this case, the attacker could have made a clone of the real site (i.e. http://127.0.0.1:8000
), and when the page loads, the user would think they're on the correct site when, in fact, they're not. If the user proceeded to log into the malicious site, they would unknowingly give out their credentials to the attacker.
How to prevent an open redirect vulnerability in Laravel
An open redirect vulnerability is a common vector of attack that can be prevented. Following are some best practices that can help:
Use fixed redirects
Implementing fixed redirects ensures that users can only be redirected to trusted, predetermined locations within the application. This practice effectively mitigates the risk of open redirect vulnerabilities and is a robust defense mechanism that should be implemented.
To implement fixed redirects in the current code, replace the /vulnerable
route with the following:
Route::get('/', function () {
return view('welcome');
})->name('home');
Route::get('/vulnerable', function (Request $request) {
return redirect()->route('home');
});
In this code, you confine any redirects to specific, trusted routes (i.e. internal routes) within your Laravel application. This approach prevents attackers from creating malicious URLs leading to external destinations. You can test this fix by trying to navigate to the malicious URL used previously: http://127.0.0.1:8000/vulnerable?redirect=https://www.google.com/
.
An allowlist of possible redirects
Another way you can prevent open redirect vulnerabilities is by defining a list of trusted destinations. This precautionary measure helps ensure that redirection only happens to approved URLs.
To implement this strategy in this Laravel project, replace the /vulnerable
route with the following code:
Route::get('/vulnerable', function (Request $request) {
// Define trusted redirect destinations
$whitelistedDestinations = [
'https://snyk.io/',
];
// Get the 'redirect' parameter from the params
$redirectUrl = $request->input('redirect');
// Check if the input URL is in the whitelist
if (in_array($redirectUrl, $whitelistedDestinations)) {
// Perform the redirect
return redirect($redirectUrl);
}
// Handle invalid redirects, for example:
return redirect('/'); // Redirect to a safe default page
});
In this code, you assume that https://snyk.io/
is a trusted redirect URL. The value of the redirect parameter in the URL is validated against the $whitelistedDestinations
array. If it matches any of the trusted destinations, the redirection occurs. Otherwise, the application redirects to a safe default page.
To test this method, navigate to http://127.0.0.1:8000/vulnerable?redirect=https://www.google.com
on your browser. You'll be automatically redirected to the home page of the Laravel application because https://www.google.com
is not in the $whitelistedDestinations
array. However, if you navigate to http://127.0.0.1:8000/vulnerable?redirect=https://snyk.io/
, you'll be redirected to https://snyk.io/
since it's in the $whitelistedDestinations
array.
Disallow redirecting to another domain
Preventing your application from redirecting to another domain ensures users are directed only within the application domain or are adequately informed and cautious when encountering potential redirects outside the trusted environment. This approach bolsters overall security and user trust.
To implement this strategy in this Laravel project, replace the /vulnerable
route with the following code:
Route::get('/vulnerable', function (Request $request) {
$inputUrl = $request->input('redirect');
// Prepend the protocol if missing
if (!parse_url($inputUrl, PHP_URL_SCHEME)) {
$inputUrl = 'http://' . $inputUrl;
}
$parsedInputUrl = parse_url($inputUrl);
// Check if the URL is valid and has a host component
if ($parsedInputUrl && array_key_exists('host', $parsedInputUrl) && $parsedInputUrl['host'] === 'localhost') {
return redirect()->to($inputUrl);
}
// Disallow redirect with a 403 Forbidden status code
return response('Forbidden: Cannot redirect to another domain', Response::HTTP_FORBIDDEN);
});
Also, make sure you add the following use statement to the top of the web.php
file:
use Illuminate\Http\Response;
This code defines a route that takes user input in the form of a URL. It prepends the http://
protocol if missing, then checks if the URL's host is localhost. If it matches, the code allows the redirect. If not, it returns a 403 Forbidden
response, disallowing redirection to another domain and providing a message indicating that it's forbidden to redirect to a different domain.
Use a Snyk IDE extension to detect open redirect vulnerabilities
If you're looking for a seamless solution for detecting open redirect vulnerabilities, consider using a Snyk IDE security extension, like the Snyk Visual Studio Code extension. This tool detects open redirect vulnerabilities in your code, tells you about any vulnerabilities (including their security level), lists the best practices for prevention, and gives you examples of code snippets that you can use to fix the vulnerabilities.
Getting started with the Snyk Visual Studio Code extension is easy. Start by installing, configuring, and authenticating the extension.
To see the extension in action, use the same vulnerable code as before. Open the routes/web.php file and replace the /vulnerable
route with the following:
Route::get('/vulnerable', function (Request $request) {
// Get the 'redirect' parameter from the query string
$redirectUrl = $request->input('redirect');
// Perform the redirect
return redirect($redirectUrl);
});
Save the file and select Snyk from the VS Code sidebar. Click the Rescan button under code security if the scan is not already running:
After the scan is complete, it displays a list of vulnerabilities. From the results, expand web.php and select Open Redirect. You'll see that the Snyk extension displays more details about the vulnerability and shows you how you can fix it:
Inside the code, the Snyk extension also highlights the vulnerable code, and you can hover over it to get more information about the vulnerability:
This extension also offers Open Source Security, a tool that enables you to find and fix vulnerabilities in the open source libraries of your application. If Snyk finds any vulnerabilities in your open source libraries, including open redirect vulnerabilities, it displays the results in the Snyk extension display window:
Conclusion
In this article, you learned all about open redirect vulnerabilities in Laravel applications and the potential risks they pose, including phishing attacks and malware distribution. You also learned how to address this vulnerability through methods such as implementing fixed redirects, whitelisting allowed destinations, and disallowing redirects to external domains. These strategies significantly enhance the security of your Laravel applications by ensuring users are only redirected to trusted and predefined locations.
If you're looking to take your security one step further, consider using Snyk IDE extensions. With Snyk, you can further fortify your Laravel applications against all kinds of vulnerabilities, including open redirects.
The Snyk Visual Studio Code extension scans your codebase, identifying vulnerabilities and providing actionable insights, enabling developers to catch potential threats before they reach production. By utilizing Snyk's comprehensive suite of security solutions, developers can proactively safeguard their Laravel applications, ensuring robust protection and bolstering the overall security posture of their projects.
Get started in capture the flag
Learn how to solve capture the flag challenges by watching our virtual 101 workshop on demand.