Introduction
An Open Redirection is when a web application or server uses a user-submitted link to redirect the user to a given website or page.
How can I identify is my application is vulnerable or not?
- If your application redirects to URL which is directly given by user that’s specified via the request such as query string or form data.
- The redirection is performed without checking if the URL is a local URL.
Below is the code:
- [HttpPost]
- [AllowAnonymous]
- public async Task<IActionResult> Login(LoginViewModel model,string returnUrl)
- {
- if (ModelState.IsValid)
- {
- var result = await _signInManager.PasswordSignInAsync(model.Email, model.Password, true, false);
- if (result.Succeeded)
- {
- if(!string.IsNullOrEmpty(returnUrl))
- return Redirect(returnUrl);
- else
- {
- return RedirectToAction("List", "Home");
- }
-
- }
-
- ModelState.AddModelError("", "Invalid Login");
- }
- return View();
- }
In this code we pass this URL directly to the Redirect. We never check if the URL is local or not, meaning that our application is vulnerable to open redirect attacks.
https://ourwebsite.com/account/login?returnURL=http://hackerwebsite.com/account/login
See in the above URL where the first part is our website and in return, the URL is given by a hacker which could be malicious or steal data. If you see the first part it looks like your website and generally, we wouldn't look at the second part which the hacker could use to easily redirect us to their site.
To Prevent Open Redirect Attacks
LocalRedirect In Asp.Net Core
Rather than using Redirect, use LocalRedirect so when the user tries to add another domain URL it will prevent it and give an error.
See in the above image that we used Local redirect in our code. When we login, I pass the return URL as =https://google.com which is not local and our complete URL as below,
https://localhost:44387/Account/Login?ReturnUrl=https://google.com
So it will throw an error like below:
Exception Message
The supplied URL is not local. A URL with an absolute path is considered local if it does not have a host/authority part. URLs using virtual paths (‘~/’) are also local.
As we handle error globally so that’s why such page and message occurs.
Url.IsLocalUrl In Asp.Net Core
If you want to use Redirects only then you can check the URL first and then perform a redirection. The code for checking the URL is shown below
- Url.IsLocalUrl(returnUrl)
And our application code becomes
- [HttpPost]
- [AllowAnonymous]
- public async Task<IActionResult> Login(LoginViewModel model,string returnUrl)
- {
- if (ModelState.IsValid)
- {
- var result = await _signInManager.PasswordSignInAsync(model.Email, model.Password, true, false);
- if (result.Succeeded)
- {
- if(!string.IsNullOrEmpty(returnUrl) && Url.IsLocalUrl(returnUrl))
- return Redirect(returnUrl);
- else
- {
- return RedirectToAction("List", "Home");
- }
-
- }
-
- ModelState.AddModelError("", "Invalid Login");
- }
- return View();
- }