Preventing Open Redirection Attacks In C# And JavaScript

There are different types of attacks that exist in web programming, like SQL Injection Attack, Cross Site Scripting Attack(XSS), Open Redirection Attack etc., and we need to take care of these attacks when writing code and trying to keep our applications from these attack.

Today, we will talk about Open Redirection Attack and see the code which prevents it at Server side level as well as client side level.

Web application works on http protocol and redirects to some URL when we click on any link or button. Sometimes, we pass URL in query string and sometimes it passes directly. But this URL can be changed by external users (hackers) and they can tamper with these URLs and redirect users to some malicious URL. This is called Open Redirection Attack.

C#

As per CWE 601

An http parameter may contain a URL value and could cause the web application to redirect the request to the specified URL. By modifying the URL value to a malicious site, an attacker may successfully launch a phishing scam and steal user credentials. Because the server name in the modified link is identical to the original site, phishing attempts have a more trustworthy appearance.

Therefore, generally we forget to write code to prevent Open Redirection Attack. We just take the URL and redirect to it. However, this is not good way to redirect.

We need to check URL and identify “is this malicious or not?” We need to do these things at code level.

Example of Open Redirection Attack

Let's say, there is a website called “abc.com” which has one login page where users can pass their credentials to the login system. When user passes user name, password, and clicks to log in button, it redirects to some other page where credentials will validate and then it will redirect to welcome page.

However, hackers tampered with the  redirect URL of welcome page with some malicious page, which looks and feels the same as abc.com login page and they will show a message that “user name and password are incorrect”. Here generally nobody will care about URL and just retype their valid credentials and click to login. But this time user has entered their credentials with some malicious site and is being hacked.

Server Side Prevention of Open Redirection Attack

So, to prevent this type of scenario we need to write code to check URL which is processing by system, if anything goes wrong it just shows error page or redirects to login page. Generally we do redirection in Asp.Net as follows. 

  1. if (!String.IsNullOrEmpty(returnUrl))  
  2. {    
  3.       Response.Redirect(returnUrl);  
  4. }  
  5. else  
  6. {  
  7.        Response.Redirect("login.aspx");  
  8. }   

Here, we are only checking Null and Empty URL, we don’t have intention to check if URL is valid or not. To check valid URL, we will validate Request. In the following code, we are validating HttpContext.Current.Request.

We can check if the provided URL is a local URL or not, la ocal URL is that which belongs to the same domain. If URL seems to belong to outside, then it will show error page or redirect to login page. 

  1. using System;  
  2. using System.Collections.Generic;  
  3. using System.Linq;  
  4. using System.Text;  
  5. using System.Threading.Tasks;  
  6. using System.Web;  
  7.   
  8. namespace Helper  
  9. {  
  10.     public class RequestExtensions  
  11.     {  
  12.         System.Web.HttpRequest request = HttpContext.Current.Request;  
  13.         public bool IsLocalUrl(string url)  
  14.         {  
  15.             if (string.IsNullOrEmpty(url))  
  16.             {  
  17.                 return false;  
  18.             }  
  19.   
  20.             Uri absoluteUri;  
  21.             if (Uri.TryCreate(url, UriKind.Absolute, out absoluteUri))  
  22.             {  
  23.                 return String.Equals(request.Url.Host, absoluteUri.Host,  
  24.                             StringComparison.OrdinalIgnoreCase);  
  25.             }  
  26.             else  
  27.             {  
  28.                 bool isLocal = !url.StartsWith("http:", StringComparison.OrdinalIgnoreCase)  
  29.                     && !url.StartsWith("https:", StringComparison.OrdinalIgnoreCase)  
  30.                     && Uri.IsWellFormedUriString(url, UriKind.Relative);  
  31.                 return isLocal;  
  32.             }  
  33.         }  
  34.     }  
  35. }   

And before redirecting to URL, we will check and validate. If everything is fine, then we will redirect to provide URL otherwise redirect to login.aspx page. This will prevent your page from being redirected to some other domain which might not be secure or might be tampered with by third party users. So, always be sure before making any redirection. Just check the URL if it exists locally or not. 

  1. Helper.RequestExtensions requestExtension = new RequestExtensions();  
  2. string returnUrl = Request.QueryString["redirectPage"];  
  3. if (requestExtension.IsLocalUrl(returnUrl))  
  4. {  
  5.        Response.Redirect(returnUrl);  
  6. }  
  7. else  
  8. {  
  9.        Response.Redirect("login.aspx");  
  10. }   

Following code is validating if the returnURL exists locally or not.

  1. if (requestExtension.IsLocalUrl(returnUrl))  

Client Side Prevention of Open Redirection Attack

The following code is  afull example of how to check URL at client side and validate if the URL belongs to the same domain where the system is running. 

  1. <!DOCTYPE html>  
  2. <html xmlns="http://www.w3.org/1999/xhtml">  
  3. <head>  
  4.     <title></title>  
  5.     <script>  
  6.                function LaunchHelp() {  
  7.             try {  
  8.   
  9.                 var surl = "http://www.google.com";  
  10.                 if (validateURL(surl))  
  11.                     window.open(surl, '_blank''toolbar=no,menubar=no,status=yes');  
  12.                 else {  
  13.                     throw new InvalidURLException();  
  14.                 }  
  15.             } catch (e) {  
  16.                 if (e instanceof InvalidURLException)  
  17.                     alert(e.message);  
  18.             }  
  19.         }  
  20.   
  21.         function InvalidURLException() {  
  22.             this.message = "An attempt was made to open a webpage of foreign domain. No allowed.";  
  23.             this.toString = function () {  
  24.                 return this.message  
  25.             };  
  26.         }  
  27.   
  28.         function validateURL(surl) {  
  29.             var url = parseURL(surl);  
  30.             var urlHostname = url.hostname.trim();  
  31.   
  32.             if (urlHostname == '') {  
  33.                 return true;  
  34.             }  
  35.             else {  
  36.                 if (urlHostname.toUpperCase() == location.hostname.trim().toUpperCase()) {  
  37.                     return true;  
  38.                 }  
  39.                 else  
  40.                     return false;  
  41.             }  
  42.         }  
  43.   
  44.         function parseURL(url) {  
  45.             var a = document.createElement('a');  
  46.             a.href = url;  
  47.             return {  
  48.                 source: url,  
  49.                 protocol: a.protocol.replace(':'''),  
  50.                 hostname: a.hostname,  
  51.                 host: a.host,  
  52.                 port: a.port,  
  53.                 query: a.search,  
  54.                 params: (function () {  
  55.                     var ret = {},  
  56.                         seg = a.search.replace(/^\?/, '').split('&'),  
  57.                         len = seg.length, i = 0, s;  
  58.                     for (; i < len; i++) {  
  59.                         if (!seg[i]) { continue; }  
  60.                         s = seg[i].split('=');  
  61.                         ret[s[0]] = s[1];  
  62.                     }  
  63.                     return ret;  
  64.                 })(),  
  65.                 file: (a.pathname.match(/\/([^\/?#]+)$/i) || [, ''])[1],  
  66.                 hash: a.hash.replace('#'''),  
  67.                 path: a.pathname.replace(/^([^\/])/, '/$1'),  
  68.                 relative: (a.href.match(/tps?:\/\/[^\/]+(.+)/) || [, ''])[1],  
  69.                 segments: a.pathname.replace(/^\//, '').split('/')  
  70.             };  
  71.         }  
  72.   
  73.   
  74.   
  75.     </script>  
  76. </head>  
  77. <body>  
  78.     <h1>This is Test 1 Page.</h1>  
  79.     <button id="btnRedirect" name="btnRedirect" onclick="LaunchHelp()">Redirect</button>  
  80. </body>  
  81. </html>   

Conclusion

So, today we have learned how to prevent Open Redirection Attack at server side as well as client side.

I hope this post will help you. Please put your feedback using comment which helps me to improve myself for next post. If you have any doubts please ask your doubts or queries in the comment section and If you like this post, please share it with your friends. Thanks