Data Protection API (DPAPI) system in ASP.NET Core

Over the year’s developers are struggling to secure web applications and their data. In the windows desktop application system, we have a Data Protection API (DPAPI) but not in the web applications but ASP.NET Core 2.0 release brought more goodies to developers in the realm of cryptography as Microsoft has added DPAPI to make it easier for developers to use strong cryptography to safeguard their data. 

In this article, we will discuss
  • What is the data protection system.
  • How does the data protection system work.
  • Why do we need the data protection system.
  • Implementation of the data protection system in ASP.NET Core project.
  • Custom configuration of the data protection system.

   What is data-protection system?

    The data-protection system is a set of cryptography APIs used by the ASP.NET Core to encrypt/ decrypt the sensitive data. So, it is all about how to protect sensitive information that will be exposed to the attackers, ideally without exposing any key material to the developers while following the best practices for key rotation and encryption at rest. 

   How does data-protection system work?

    The data protection system uses symmetric key encryption to protect sensitive information. Below is the diagrammatical representation of the same:

Symmetric encryption from Wikipedia Munkhzaya Ganbold


   Why do we need the data-protection system?

    In modern times, because of the modularization and customization development techniques, developers need to be sure that their data is secure between the server round trips. In short, developers need an “Authentic data transfer”.

    It will be easier to understand the need for the data-protection system with the help of examples. Below are the two examples: -

        1.       Query-string parameters

        2.       Authentication Cookies

   Query-string Parameters

    Have a look at the below snapshot which is providing information about an employee

        

       If we look at the URI of the details page, then we can see the Employee ID property value which is being passed as a query-string parameter. Think of it, we do not want to show the actual ID value in the URI.

    Authentication Cookies

     Cookies are a way of persisting state between requests. You do not have to provide the username and password for each request to the server. Instead, you log in once to the server and the server verifies your credential against the database and issues a cookie for validating the further requests as explained below in the diagram


    The cookie is a very sensitive item. Any request that includes the cookie will be treated as though it was sent by the original user, just as they provide their username and password with every request.

    Modern browsers already providing protection to stop attackers from getting access to these cookies like CORS. However, as a developer, we cannot rely on only on the browser's protection and we cannot let any user tampers with their own cookies.

    This is where DPAPI comes in handy whether it is for protecting the actual query-string value or for protecting the login cookies.

  Implementation of data-protection in ASP.NET Core project

    For implementing the data-protection system in the ASP.NET Core project, make sure that you have installed the following NuGet package (install the latest stable package)

  •     Install-Package Microsoft.AspNetCore.DataProtection -Version 3.0.0

    and you have added the following namespace

  •        using Microsoft.AspNetCore.DataProtection;

      In Microsoft.AspNetCore.DataProtection namespace we have one interface that is IDataProtectionProvider and it contains one method CreateProtector. 


      We have one more interface, IDataProtector, which inherits the IDataProtectionProvider interface. It includes two different method definitions.


    Protect - Cryptographically protects a piece of plaintext data.
Unprotect - Cryptographically unprotects a piece of protected data

    As in the above snippets, we have used the Dependency Injection and for initializing an instance of IDataProtector (_protector) we are using the CreateProtector method of IDataProtectionProvider which is accepting a string parameter is also known as “purpose string”.

    For protecting the query-string parameter value we need to add two lines of code

  •     Use the protect method where you are passing the value to the query-string parameter.
  •     Use the unprotect method where you are using the query-string parameter value.
    For protecting the session cookies, we can follow the same approach

  •     Use the protect method where you are passing the value of the session cookie for making the secure data packet to the server.
  •     Use the unprotect method where you are using the session cookie value for validating the authenticity of the request.

    As Microsoft stated, two different IDataProtector instances created by two different purpose strings will not be able to decipher each other payloads, and purpose string value is not intended to be kept secret. So, if you have protected something using “Protector_A” then “Protector_B” will not be able to unprotect it.

    This is the basic implementation of Data Protection system and its methods. Now let us make it a bit complex. What if we have the following scenarios

        1.  How to manage purpose string where multiple developers are working on a single project but on different modules?

        2.  What if there are multiple applications are in within one project hosted on a single server?

        3.  What if multiple applications are in one project but hosted on multiple servers or in the cloud?


  Custom configuration of data-protection system

    All the above use cases can be handled easily. Let us solve them one by one: -

   Shared Purpose String

    We can store the purpose string in the app settings file and then can access its value in any controller using Dependency Injection. So, the developers need not to define the purpose string in their respective controllers or modules and based on the requirements, data protected by one developer of one module can be unprotected by other developers in another module. Below is the implementation for the same

    Shared Data Protection configuration between multiple application on the same server

    By default, the data-protection system isolates apps from one another based on their content root paths even if they are sharing the same physical repository (or same server). This prevents the apps from understanding each other’s protected data (payloads). So, for handling this we need to configure the Data Protection in startup file and set the common application name in ConfigureServices method in all applications which are hosted on a single server and want to share the protected payloads like below

    Once you have configured the common application name in all the applications then these applications will be able to unprotect the data which has been protected by another application.

    Shared Data Protection configuration file between multiple applications hosted on multiple/cloud server

     If there is no configuration then by default data-protection configuration will be stored on the root path of the application. But when multiple application(s) want to unprotect the data which has been protected by another application and all these applications are hosted on multiple servers or in the cloud then the DP configuration should be stored at the shared storage location and the shared storage location should be accessible for all these applications. 

    A classic example for this scenario is a multitenant web application that is consuming a Web API like below



    In this setup, we have 4 web applications that are consuming one API and/or interacting with each other also. For example, a single user can log in into Web App – A and then using the same session he can access Web App – B or Web App – C or Web App – D.

    So, if all these web apps and Web API are using the same shared storage location for storing data-protection configuration then web app will be able to unprotect the protected data of Web API and vice versa.

    For achieving this, we need to configure the Data Protection in startup and need to define the shared DP configuration storage path for all application(s) which are hosted on multiple servers. There are multiple ways to define a common storage as defined in this article

     https://docs.microsoft.com/en-us/aspnet/core/security/data-protection/configuration/overview?view=aspnetcore-5.0


    Here we are going to save the Data Protection Configuration file in the Azure Container as a Blob. For this configure the startup file like below

    Firstly install NuGet package for storing configuration file in Azure Blob
install-package Azure.Extensions.AspNetCore.DataProtection.Blobs


    Once all configuration is done then it will store the data-protection configuration file in the azure container as a blob and you can download or view it. It will be something like this



    We can see the creation date, expiration date, validation algorithm used, and the value of the master key. Notice that we have a warning that our key is unencrypted, which is not that good. For fixing it we can use any of the available 3 methods

  •     ProtectKeysWithCertificate
  •     ProtectKeysWithDpapi
  •     ProtectKeysWithDpapiNG

    Here we are using “ProtectKeysWithDpapi” as below


    Let us delete this configuration file and run our app again.

    Now if we look at our key, we are going to see that it is encrypted


  Conclusion

    We have covered many different features related to data protection in ASP.NET Core and there are many to cover but that I leave to you guys. Go ahead and play with it as this can be quite useful when it comes to protecting sensitive data in our application.

Comments

Popular posts from this blog

Get Started with GIT Repository and VSTS

Querying Cross Databases in Azure SQL