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

Secure core app feature image

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

In this article, you are going to walk through 10 best practices that everyone must consider in the security aspects while writing web applications in ASP.NET Core or MVC framework. These security vulnerabilities are common to all web applications.

Below are the few major security vulnerabilities that can be exploited by hackers 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 a web page with the intention to steal 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 the 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 expressions to validate the user’s form inputs. So, you can deny malicious characters, symbols or you can allow only acceptable required characters to the input field to proceed further.

To learn more about regular expression attributes 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 the 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 encodes all the inputs so that the script part given in any field will never be 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 the URL query string, this will cause the XSS attack. So, we should encode the query parameter input in the URL.

We have an 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 runs into our database and the attacker can get the confidential information stored in the database.

Refer to the below link to know details about SQL Injection.

https://en.wikipedia.org/wiki/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 attacks because entity framework internal uses parameterized queries.

Use least privileged DB access

We should limit the DB user permission for the 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 confidential information like email, passwords, etc. in plain text format in the database. This should be stored in an encrypted format.

Cross-Site Request Forgery (CSRF)

What is Cross-Site Request Forgery?

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

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

For example,

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

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

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

However, it is a 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 the 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 the customer which related to database configuration info, table name, stored procedures, and data structures, programming coding structure.

How can we add proper custom error handling?

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

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

This attribute will handle the exception.

We can override the OnException method 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 in the 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.  

The second Approach is to configure UseExceptionHandler in a 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 the browser. 

Version Discloser

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

Whenever browser sends HTTP to request to the server in response, the 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 the ASP.NET framework version your website is running on.

X- AspnetMvc-Version: 4.0: This shows the 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 a web configuration file, and in that web config file, add the element to remove X-Powered-By element under <system.webServer>

<system.webServer>
  <httpProtocol>
    <customHeaders>
      <remove name="X-Powered-By" />
    </customHeaders>
  </httpProtocol>
</system.webServer>

  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 the below change in the web configuration file.

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

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 establishes the secure/encrypted connection between client and server. So, the requests which passed between the client browser to the server end and the response from the server end to the 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.

ASP.net Core 2.1 and later version, we can easily create an application which configured over HTTPS. We can also configure HTTPS with ASP.net Core before the .NET core framework 1.1 but it was 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 to 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 the 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: Timespan that defines the max-age of Strict-Transport-Security header valid. The default value is 30 days.

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

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

ExcludedHosts: It is a list of hostnames that 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 uploaded by the end-user, there will be a possibility of 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 causes server shutdown. This kind of attack is called a “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, an 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 web applications have authentication modules, 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 mistake allows attackers to steal the user’s credentials such as cookies, session values, this may cause attackers to access the complete application and make any kind of major impact.

Below mistakes can helpful attackers 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 to the below code to remove the session and to remove the authentication cookie [.AspNetCore.Session] after logged out.

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

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

HttpOnly is a flag that 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 gets 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 at regular intervals. We can set up collecting logs using IIS logs or you can store your logs in text files or databases. Based on the logs, we can get insights into any errors or performance issues in a production application also, if anyone trying to attack an 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 causes a 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. For example if you allowed only image files, the attacker can save the script file in .jpeg extension and do the upload. In this case your validation accepts the files by thinking it is an image file, but it is a script file that 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.

Conclusion

I hope in this article, you have learned the best security practices that everyone must consider while writing web applications in ASP.NET Core and MVC framework.

He is a product manager at a reputed software company and a freelance blog writer. He is experienced in different technologies, web securities, and web applications. He keeps learning and make himself up to date on the latest technologies, news, health, and fitness. This encouraged him to share his experiences by writing articles.

Leave a Reply

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

Back To Top
%d bloggers like this: