8 Web Security Standards for every .Net MVC web application

Security is a beast! As a bare minimum, we need to ensure our applications meet industry best practices when released into the wild.

The vast majority of attacks seek to exploit common vulnerabilities so by implementing basic standards we can dramatically reduce risk.

Reviewing the 8 practices below are a great start when assessing the security of your coding practices.

1. Always use an ORM

SQL injection, the injection of untrusted SQL into the database via a query inputted to the application, is still one of the most common vulnerabilities on the web today. The fact this most basic type of attack is still prevalent points to the volume of poorly designed and implemented applications on the web today.

Protecting yourself against SQL Injection is easy and can be done in numerous ways by simply ensuring that data inputted to your application is never directly injected at database level.

Parameterised stored procedures with input validated against a whitelist is an acceptable approach as long as the developer does not concatenate strings within the SP.

However, the best way to protect your application is to use an ORM every time you are querying or writing to the database. There are numerous options for .Net ORM’s with the Entity Framework being the most popular choice but it really is a personal preference.

2. Using Get and Post attributes correctly

Get data is appended to the query string and available publicly while Post data is passed to the server as part of the request body.

Action methods should be decorated with the appropriate Get or Post attribute.

Get should be used when a call is made to a controller function that retrieves data to load a page.


[HttpGet]
 public ActionResult Index(string username)
 {
 // ... etc
 }

Any controller function that accepts and processes data should have the Post attribute.

[HttpPost]
 public ActionResult Delete(string username)
 {
 // ... etc
 }

3. Anti-Forgery Tokens

When the server is processing a request, it should validate that the source of the request to confirm that the user is not the subject of a Cross-Site Request Forgery (CSRF) attack.

MVC provides antiforgery token helpers to that gives you a means to detect and block CSRF attacks through putting a hidden field in the form and then checking that the correct value was submitted on the server side.

To use this first place an HTML.AntiForgeryToken() helper in the form


@using (Html.BeginForm()) {

@Html.AntiForgeryToken()

  <!-- Rest of code here -->
}

This will output a token in the HTML and also give the visitor a corresponding cookie.

Next we need to validate that incoming post at the target action method.

To do this we just need to add the ValidateAntiForgeryToken attribute to the action method.


public ViewResult SubmitPasswordChangeUpdate()
{
 // add code here
}

As a standard all form requests should be validated with anti-forgery tokens. Otherwise you have opened a vulnerability in your application.

4. SSL

SSL will ensure that personal information going up the line is encrypted in the request body.

Ensure your site has a valid SSL certificate. Then force any pages that either retrieve or send personal information from http to https .

Use the .Net RequiresHttps action filter by applying the attribute where required as follows:

[RequireHttps]
public ActionResult SignIn()
{
    return View();
}

Or why not apply the filter globally to force all pages to Https.

protected void Application_Start()
{
    GlobalFilters.Filters.Add(new RequireHttpsAttribute());

    // rest of code here
}

5. Cachable SSL Pages

Any pages that are forced onto HTTPS and contains sensitive data should disable caching. Add “Cache-Control: no-cache, no-store, must-revalidate” to the response headers.

This can be achieved in .Net by setting specific response values. Do this by creating a custom action filter attribute as demonstrated here:

public class NoCacheAttribute : ActionFilterAttribute
{
   public override void OnResultExecuting(ResultExecutingContext filterContext)
   {
      if (filterContext == null)
throw new ArgumentNullException(filterContext);
var cache = GetCache(filterContext);
      cache.SetExpires(DateTime.UtcNow.AddDays(-1));
      cache.SetValidUntilExpires(false);
      cache.SetRevalidation(HttpCacheRevalidation.AllCaches);
      cache.SetCacheability(HttpCacheability.NoCache);
      cache.SetNoStore();
      base.OnResultExecuting(filterContext);
   }
protected virtual HttpCachePolicyBase GetCache(ResultExecutingContext filterContext)
   {
      return filterContext.HttpContext.Response.Cache;
   }
}

6. Password Storage

Ensure you have a strong password policy implemented. As an absolute minimum your policy should insist on 7 character comprising of lowercase, uppercase, numeric and special characters.

You can do that by setting membership provider attributes in the web.config or by configuring the provider to use a regular expression to validate passwords as in this example.

<membership>
     <providers add passwordStrengthRegularExpression= "^(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{8,10}$" ...></providers>
</membership>

Passwords stored in the database should be hashed using a salt. Better yet you could move to a more robust hashing algorithm than .Net’s standard SHA1.

7. Error Handling and Custom Error Pages

It is imperative that we never give away information to a potential threat about the internal workings of our system.

If a visitor can generate an error message like below it is technically poor and not a good user experience.

All unhandled exceptions should be redirected to a custom error page that only contains a friendly generic message (i.e. message that does not reveal any information nor the type of error that occurred).

This can also be set in the web.config like below:

 <customErrors mode="RemoteOnly" defaultRedirect="Error">
 <error statusCode="404" redirect="Error"" >
 </customErrors>

8 Secure Cookie

These days we live a large amount of our lives online and how do websites know who we are? Through cookies of course!

If there is an XSS vulnerability on the site, a malicious user could inject some JS that could modify cookies on page load or worse still, send the cookies to a remote server! If somebody has your browser cookies they essentially have your identity for that website.

A HTTP only cookie tell’s the browser that this cookie should only be accessed by the server. Any attempt to access the cookie from a client script will be forbidden.

You can add the following line to your application which will set the HttpOnly header on cookies for your application:

<httpCookies httpOnlyCookies="true">

HttpOnly cookies don’t make you immune from XSS attacks but they do raise the bar

 

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: