9 Tips for Writing Secure Applications in ASP.NET

Brij Bhushan Mishra / Monday, May 30, 2016
 
Security is one of the most important aspects of any application – and when we talk about security, particularly in ASP.NET applications, it is not limited to development. A secure app involves multiple layers of security in the configuration, framework, web server, database server, and more. In this post, we’ll take a look at the top nine tips for writing secure applications in ASP.NET.
 
1- Cross Site Scripting (XSS): This vulnerability allows an attacker to inject some malicious code while entering data. It could be JavaScript code, VB script, or any other script code. By default, ASP.NET MVC validates the inputs and throws a server error in case of script. Say we put the script in the input form:
 
 
 
When we submit the above page, we’ll get the error below:
 
 
By default, the razor view engine protects from XSS attacks. But there are certain scenarios (blogging, social applications, etc.) where we might need to allow html tags in input controls. For that, we have an option to add the ValidateInput filter as false:
 
 [HttpPost]
 [ValidateInput(false)]
  public async Task<ActionResult> Register(RegisterViewModel model)
  {
       if (ModelState.IsValid)
       {
            //  Etc.
}
  }
 
But this is very risky because here we not validating the complete request. Say the model has twenty properties, all will be exempt from the validation while we might need to allow html in only one or a few controls.
 
In that scenario, instead of using this ValidateInput, we should put the an attribute AllowHTML in the specific ViewModel’s property as:
 
public class RegisterViewModel
    {
        [Required]
        [AllowHtml]
        [Display(Name = "User Name")]
        public string Name { get; set; }
       
    }
 
Now we can use tags for the name only.
 
2- Cross site resource forgery (CSRF):  CSRF (also known as one click attack) is a type of malicious attack where unauthorized commands are fired from a trusted website where the user is authenticated. In real world scenario, say the user logged into an application with windows/cookie based authentication. Now without logging out, the user visits a malicious site and clicks on a button. The external website initiates a request via your website for doing an unethical operation. It will be considered as valid request because the request is authenticated.
 
To prevent from CSRF attacks, MVC provides AntiForgeryToken mechanism. For that we need to use AntiForgeryToken helper in view as
 
  @Html.AntiForgeryToken()
 
And to validate the token, we need to put  Antiforgerytoken filter over action as:
     
[ValidateAntiForgeryToken]
      
 public async Task<ActionResult> Register(RegisterViewModel model)
{
      if (ModelState.IsValid)
      {
 
          // etc.
 
      }
 
      return View(model);
  }
 
It creates two tokens in response, one is set as a cookie and other is set in a hidden field as:
 
<form action="/Account/Register" class="form-horizontal" method="post" role="form">
     <input name="__RequestVerificationToken" type="hidden" value="Qorw9RPABdHoRC7AojnSnQYYuGZP5iPF63UFVSw_[…]" />
 
While submitting the form both of the tokens (cookie and hidden field) are sent to the server. Both are validated at the server, and  if either one is not present or tampered then the request is not allowed.
 
3- Handling Errors Properly: Errors are bound to happen, and they find their way to reach user. But if they are not handled properly, errors can leak internal information to the outside world, which can be a threat to the application. Following YSOD is common when an unhandled exception occurs:
 
 
But see how much information it is showing to outside world: internal code, physical file structure, stack trace, and the version of ASP.NET and .NET framework.
 
One quick fix could be setting customErrors mode on as:
 
<customErrors mode="On">
</customErrors> 
 
This will show an ASP.NET default error page in case of each error. To handle it in better way, use custom errors mode RemoteOnly and have a common error page which gets displayed in case of error.
 
<customErrors mode="RemoteOnly" redirectMode="ResponseRewrite" defaultRedirect="~/Error.aspx" />
 
Here we are displaying our own error page in case of an error.
 
4- SQL Injection: SQL injection is a well-known security vulnerability, but it is still not handled properly in many applications. SQL injection allows hackers to tamper with existing data, modify transactions, or even delete data or databases, which can be a major loss to business.
 
Using this technique, the hacker injects some malicious SQL commands via input. These commands have the power to change the SQL statement running on the server.  Say authenticating a user in an application, we have written a query in a class as:
 
"select * from Users where UserName='"+txtUserName.Text+"'and Password='"+txtPwd.Text+"' ";
 
Now user puts the following value in user name:
 
Now the query will be generated on server as:
 
select * from Users where UserName='’ or 1=1 --' and Password='"+txtPwd.Text+"' ";
 
This will always return items and allow users to get into the application.
 
To handle this, the best way is to use SQL stored procedure where we will pass the values a parameter or at least use the parameters as:
 
"select * from Users where UserName= @username and Password=@password”
 
5- Click-Jacking: Click-Jacking is another major vulnerability that gets ignored normally. In this, the attacker uses an opaque layer to trick the user to click on a button or link on different page (say transfer button on the bank website) while they are intended to click on the top level page.
 
To avoid this issue, we should not allow any website of different domain in iframe to open. To achieve this, we need to add a response header X-FRAME-OPTIONS as deny or sameorigin. In ASP.NET, we can set in Global.asax as:
 
void Application_BeginRequest(object sender, EventArgs e)
{
    HttpContext.Current.Response.AddHeader("X-FRAME-OPTIONS ", "DENY");
}
 
It will add the header in all the responses send by the application.
 
We can also use IIS to add the same header. In IIS, go to the intended website, and go to HTTP Headers tab and add a custom header with the header X-FRAME-OPTIONS as discussed. You will need to restart IIS to get it into effect.
 
6- Hide Application Structure/ Directory Listing – Would you like to share the folder structure of your application to the end user?  No! Right? Let’s see an example. I have deployed ASP.NET web forms default application on IIS so now when I access the URL, it displays:
 
 
 
It shows all the files and folders available under Account. This information can be a potential threat to the application if publically available.
 
Directory browsing should be disabled at IIS. When it is disabled, we see:
 
 
It returns 403 (forbidden), but that still leaves some vulnerability as it tells the user that this folder is available. When we try to access a directory which is not available, it returns 404.
 
For this, we can write our own custom http handler and configure it so that it always return 404 whenever anybody try to access a folder.
 
7. Encrypt sensitive information in Web.config – Many times we put critical information in the Web.config, most commonly the connection string.
 
To encrypt any part of connection string, we need to navigate to framework folder on command prompt (say C:\Windows\Microsoft.NET\Framework\v4.0.30319 ) and run the following command:
 
aspnet_regiis -pef "connectionStrings" path
 
Here path is the path of the folder where Web.config resides. After running the command, it shows as:
 
 
 
Similarly we can encrypts other section like <appsettings> etc.
 
7– Secure the cookies: Cookies are small text stored by browsers on users’ machines that travel between the web server and browser. Cookies are used to store the user related information for the specific website. In ASP.NET, Session Id is one of the most common pieces of information for which cookies are used to save.
 
As this information is stored in plain text on a user’s machine, it could be an easy target for attackers. There are couple of steps we need to take to avoid storing data in cookies, such as setting an expiry date and encrypting the data. Apart from these two steps, there are two more things which we should do:
 

1-      Allow cookies on SSL only

2-      Set the cookies as HTTPOnly. This makes sure that cookies cannot be read by client side script so our session or Form authentication token could not read on a browser.

 

We can make the settings in Web.config as:
 
<httpCookies domain="String"
             httpOnlyCookies="true "
             requireSSL="true " />
 
8- Encrypting View State- View State is one of the most common techniques used to maintain the state between the Page PostBacks in ASP.NET Web forms. View State is saved in a hidden variable on the page with id __VIEWSTATE. When we see that in view source, we find that it contains a series of numbers and characters. Be sure that it is not encrypted but in base64 format. Anybody can decode it to read the information.
 
There are two options to encrypt and make it tamper proof. There is the property ViewStateEncryptionMode, which can be set at page level in the aspx file or can be set it in Web.config which applies to all the pages in the application. It encrypts the view state before putting it into the response. Similarly, another property, EnableViewStateMac, can be set as true at the page or in Web.config. It creates a hash of the view state content and added in the hidden field. In the next post back, again the hash gets created and verified. If it does not match, then post back is rejected and an error is thrown.
 
9- Remove sensitive information from Response Headers: Here is the response header of a page of an ASP.NET application:
 
Here we can see that it is revealing too much information to the end user, which they don’t require like in IIS version, site built on, and ASP.NET version. If an attacker knows the loopholes of any of them, he or she can exploit the vulnerability. This information is by default added, and we should remove it unless and until specifically required.
 

a-      To remove ASP.NET version header, we just need to add the following in the Web.config:

 

<system.web>
  <httpRuntime enableVersionHeader="false" />
</system.web>
 

b-      To remove MVC version, we need to go AppliCation_Start event in Global.asax and add the following code:

 
MvcHandler.DisableMvcResponseHeader = true;
 

c-       X-Power-By is added by IIS and can be removed by adding the following configuration:

 

  <system.webServer>
        <httpProtocol>
            <customHeaders>
                <remove name="X-Powered-By" />
            </customHeaders>
        </httpProtocol>
  </system.webServer>
 
Conclusion: In this post, we discussed that security is key for any web application, and if not handled properly, it can harm the business significantly. We discussed nine of the most common vulnerabilities of ASP.NET web applications and saw that most of these can be fixed by making some configuration change or minor code changes.
 

Build full-featured business apps for any browser with Infragistics ASP.NET controls! Download Free Trial now.