10 best practices to secure ASP.NET Core MVC Web applications

In this article, you are going to walk-through 10 best practices which everyone must consider in security aspect while writing web applications in ASP.NET Core and MVC framework. These security vulnerabilities are common to all web application framework like PHP.

Below are the few major security vulnerabilities which can be exploits by hacker to gather information, inject malicious code, steal your confidential information like user name, passwords, card information etc.

  • Cross-Site Scripting (XSS)
  • SQL Injection
  • Cross-Site Request Forgery (CSRF)
  • Custom Error Page for Error Handling
  • Version Discloser
  • Enforce SSL (Secure Sockets Layer) and HSTS
  • XXE (XML External Entity) Attack
  • Improper Authentication and Session Management
  • Sensitive Data Exposure and Audit Trail
  • File Upload Validation

Note:  I have shared the same article with Syncfusion Blog, sharing here for my subscribers.

Cross-Site Scripting (XSS)

What is Cross-Site Scripting (XSS)?

A malicious script is injected through the input/form fields of web page with the intension to steal the confidential information like login credentials or other authentication information, cookies, and session values is called Cross-site Scripting (XSS) attack.

This script injection can be carried out in below ways,

  1. Form Inputs
  2. URL Query Strings
  3. HTTP Headers

How to Prevent Cross-Site Scripting (XSS)?

  1. Regular Expression Attribute
  2. Regular Expression Object Model
  3. HTML Encoding
  4. URL Encoding

Regular Expression Attribute

You can use regular expression to validate the user’s form inputs. So, you can deny malicious characters, symbols or you can allow only acceptable required characters to input field to proceed further.

To learn more about regular expression attribute follow this link.

Regular Expression Object Model

Same as above regular expression attribute, using this way you can validate the user inputs by calling static methods of Regex class.

To learn more about regular expression object model follow this link.

Note: You can do both client and server-side input validations.

HTML Encoding

The MVC Razor engine automatically encode all the inputs so that the script part which given in any field will never executed.

Note: if you like to use raw text without encoding, you need to use the syntax “@Html.Raw()”.

URL Encoding

Usually we use plain text in URL query string, this will cause the XSS attack. So, we should encode the query parameter input in URL.

We have inbuilt library in NuGet to Encode and Decode the text.

string encodedValue = System.Net.WebUtility.UrlEncode(“raw-string-text”);

string decodedValue = System.Net.WebUtility.UrlDecode(encodedValue);

SQL Injection

What is SQL Injection (XSS)?

It is a dangerous attack that unauthorized user will inject the malicious SQL code which run into the our database and the attacker can get the confidential information which stored in the database.

Refer the below link to know detailed about SQL Injection.

How to Prevent SQL Injection?

  1. Validate Inputs
  2. Use Stored Procedure
  3. Use Parameterized queries
  4. Use Entity Framework or any other ORM
  5. Use least privileged DB access.
  6. Store Encrypted Data

Validate Inputs

  • We should always validate the user inputs in both client and server side.
  • We should not allow the special character which involves in SQL scripts.
  • We can use regular expression, data annotation to validate the inputs.

Use Stored Procedure

  • Using stored procedure will prevent the SQL injection. But we should to validate the input parameters which passed to execute the stored procedures.

Use Parameterized queries

  • If you want to use inline queries, we must use the parameterized query to prevent SQL injection.

Use Entity Framework or any other ORM

ORM stands for Object Relational Mapper which maps SQL object to your application class object.

If you are using entity framework properly you are not prone to SQL injection attack because entity framework internal uses parameterized query.

Use least privileged DB access

We should limit the DB user permission for table which has confidential data. Like we can stop insert, update, delete permission to tables which related to payments and transaction. Also, we can limit the permission to tables which stored user’s personal information.

For example, if the user only works related to select queries, then we must give select permission only and shouldn’t not provide Insert, Update, and Delete permissions.

Store Encrypted Data

We should not store the confidential information like email, passwords, etc. as plain text format in database. This should be stored in encrypted format.

Cross-Site Request Forgery (CSRF)

What is Cross-Site Request Forgery?

Attacker acts as a trusted source and send some forged data to site, so the site process this forged data by believing this as coming from trusted source.

You can learn how this attack works by referring the link.

For example,

A user is transferring fund from one account to another account and trusted connection established between the user and bank site after user login successfully.

At the same time user click on malicious link from junked email which sent by the attacker.

Because of the secure session is established between user and bank site, the attacker uses this connection and does some malicious activity such as fund transfer.

However, it is vulnerability at the server (web application) side, not an end-user side.

How to Prevent Cross-Site Request Forgery?

We can prevent this attack by using AntiForgeryToken.

We can use the html tag helper “asp-antiforgery” in HTML attribute and need to set this value as true. By default, this value will be false. If we set this value as true, it will generate the anti-forgery token. Then we need to add [ValidateAntiForgeryToken] attribute on the form post action method to check valid token is coming or not.

Adding [ValidateAntiForgeryToken] Attribute to [HttpPost] Method of form action.

Custom Error Page for Error Handling

Sometimes we missed or not properly write error handling code in our web application, which lead us to expose the sensitive information to customer which related to database configuration info, table name, stored procedures, and data structures, programing coding structure.

How can we add proper custom error handling?

There are two ways to add the custom error handling page in Core application.

First approach, we can create a custom error handling attribute using ExceptionFilterAttribute.

This attribute will handle the exception.

We can override the OnException method to and write an exception in a text file according to date wise and this can be stored inside the desired folder path. Also, we can store the exception to database. Finally redirect the route to custom error page like,

public class CustomExceptionFilterAttribute: ExceptionFilterAttribute
        //write the code logic to store the error here
        var result = new RedirectToRouteResult(
        new RouteValueDictionary
            {"controller", "Error"}, {"action", "CustomError"}

 Then we need to register this filter globally inside the ConfigureServices method in Startup.cs file.  

Second Approach is to configure UseExceptionHandler in production environment.

Here we have written to show the custom error page in error controller only if the hosting environment is Production, so staging and development environment won’t show the custom error page instead of showing the actual error in browser. 

Version Discloser

We should keep hide the version information which we used to develop the application to end users, because if an attacker gets a specific version in which application is developed then they may try to target specific attack on that version which is disclosed.

Whenever browser sends HTTP to request to the server in response, browser gets response header which contains information the following information

  • server,
  • x-powered-by,
  • x-aspnet-version,
  • x-aspnetmvc-version,
  • x-sourcefiles

The server shows information about which web server is begin used.

Server: Microsoft-IIS/10.0: Application as hosted by Microsoft-IIS version 10.0.

X-Powered-By: ASP.NET: This shows ASP.NET framework your website is running on.

X-Aspnet-Version: 4.0.30319: This shows ASP.NET framework version your website is running on.

X- AspnetMvc-Version: 4.0: This shows ASP.NET MVC framework version your website is running on.

X-SourceFiles: This will only be generated for localhost requests and serves debugging purposes.

How can we hide this header values?

Server Header:

We can remove server header by adding the line UseKestrel(c => c.AddServerHeader = false) in the CreateWebHostBuilder method in Program.cs class.

X-Powered-By Header:

To remove X-Powered-By header, we need to add web configuration file, and in that web config file, add the element to remove X-Powered-By element under <system.webServer>

      <remove name="X-Powered-By" />

  We can remove this from IIS settings too. Select this header and remove it.

X-Aspnet-Version Header:

To remove X-Aspnet-Version header, make below change in web configuration file.

  <httpRuntime enableVersionHeader="false" />

X- AspnetMvc-Version:

To remove X- AspnetMvc-Version header, add the below line in application start in Global.aspx.

protected void Application_Start(object sender, EventArgs e)
  MvcHandler.DisableMvcResponseHeader = true;

Enforce SSL (Secure Socket Layer) and HSTS

What is SSL?

It stands for Secure Socket Layer, and this establish the secure/encrypted connection between client and server. So, the requests which passed between client browser to server end and the response from server end to client browser will be encrypted to maintain the integrity of the data.

We can use HTTPS (HyperText Transfer Protocol Secure) protocol to secure your ASP.NET Core application. Core 2.1 and later version, we can easily create an application which configured over HTTPS. We can also configure HTTPS with Core before the .NET core framework 1.1 but it was some difficult to configure.

We can find the option to configure our web application over HTTPS when we are creating a web application template with Visual Studio. Refer the screenshot,

What is HSTS (HTTP Strict Transport Security Protocol)

It stands for HTTP Strict Transport Security Protocol. It is a web security policy that protects our web application from downgrade protocol attacks and cookie hijacking. It forces webserver to communicate over an HTTPS connection. It always rejects insecure HTTP connections.

The ASP.NET Core template by default adds HSTS middleware. It is not recommended to use in the development environment as a browser is cache the HSTS header.

We can override few options to configure HSTS. There are,

MaxAge: Time span that defines the max-age of Strict-Transport-Security header valid. The default value is 30 days.

IncludeSubDomains: If this value set to true, Strict-Transport-Security header available for subdomains tool.

Preload: Using this property, we can add preload for Strict-Transport-Security header.

ExcludedHosts: It is a list of hostnames which will not add the HSTS header.

The ASP.NET Core default template also adds another middleware that redirects request from non-secure HTTP. It uses default redirect status code (307) to redirect the request. We can also override the default option.

XXE (XML External Entity) attack

If your application uses the logic to parse the XML file which uploaded by end-user, there will be a possibility to XXE (XML External Entity) attack. The XML input contains the malicious XML code or the reference of the external entity which weakly configured in the XML parser. This kind of attacker can cause a Denial of Service attack by injecting entities within entities which makes your server utilization too high which cause server shutdown. This kind of attack called as “Billion Laughs Attack”.

How to prevent this Attack?

If we use “XmlTextReader” to parse the XML file, we must set the property called “DtdProcessing” as Prohibit or Ignore.

If “Prohibit” is set, exception will be thrown if DTD (Document Type Definition) is identified

If “Ignore” is set, it will ignore any DTD specifications in the document and continue to process the document.

If Parse is set, it will parse any DTD specifications in the document. By default, “Parse” will be set. It is potentially vulnerable.

Improper Authentication & session management

Most of the web application have authentication module, and we should be careful in writing this authentication code. Sometimes we made few mistakes in this process like not removing the authentication cookies after successful logout. This kind of mistakes allows attackers to steal the user’s credentials such as cookies, session values, this may cause attacker to access the complete application and make any kind of major impact.

Below mistakes can helpful attacker to steal data

  1. Insecure connection (Without SSL)
  2. Use predictable login credentials
  3. Storing plain (unencrypted) credentials.
  4. Improper Application logs out.

How to avoid these mistakes?

  1. Remove Cookies after successful logout
  2. Secure cookies and sessions by using SSL
  3. Secure cookies by setting HTTP Only

Refer the below code to remove session and to remove the authentication cookie [.AspNetCore.Session] after logged out.

To set HttpOnly on Cookies in ASP.NET Core refer below code,

CookieOptions option = new CookieOptions {Expires = DateTime.Now.AddHours(24), HttpOnly = true};

HttpOnly is a flag is set to any cookie, that couldn’t be used accessed from client-side scripts.

To set up HttpOnly globally in Startup.cs Configure Method.

Sensitive Data Exposure & Audit Trail

We are always managing user personal important/secured in the web application. There are more chances we expose and store these sensitive data like normal information, or we only consider few sensitive data and missed to consider other sensitive data without knowing it. If the attacker get access to these data, they will misuse it.

What we need to do to avoid these mistakes?

  1. Send the sensitive data in encrypted format using suitable encryption algorithm like we should not pass customer mail address over URL without encrypt.
  2. Use SSL and access the production web applications in HTTPS mode
  3. Do not store sensitive data anywhere which includes database, application code. If you should store it, use strong encryption algorithm to encrypt the data then store it.

Audit Trail

It will be best practice to keep monitoring your production web applications activity logs in regular interval. We can setup collecting logs using IIS logs or you can store you logs in text files or databases. Based on the logs, we can get insights of any errors or performance issues in a production application also, if anyone trying to attack application, we can know their attempts.

File Upload Validation

There will be more chances for attackers to use file upload control to upload some malicious script file which cause problem. So, we should always do the proper file validation.

The main validation we do on file is file extension is expected. But here attacker can change the file extension and upload it. Example if you allowed only image files, the attacker can save the script file in .jpeg extension and do the upload. This case your validation accepts the files by thinking it is image file, but it is a script file which has some malicious script codes.

How to do proper validation?

  1. First check the file upload count, If the upload count is zero, no file is uploaded. If upload count is greater than zero proceed further validation.
  2. Then check the file extension. This will allow only valid extension files. Sometimes attacker passes malicious file with allowed extensions. In that case do further validation.
  3. Then we need check to file content type and file bytes. 
  4. Only allow to upload the file when above 3 steps successfully validated.


I hope in this article, you are learned important security practices which everyone must consider while writing web applications in ASP.NET Core and MVC framework.

Leave a Reply

Your email address will not be published. Required fields are marked *