Back to: ASP.NET Core Tutorials For Beginners and Professionals
How to Encrypt Cookies in ASP.NET Core MVC
In this article, I will discuss How to Encrypt Cookies in ASP.NET Core MVC Applications with Examples. Please read our previous article discussing Cookies in ASP.NET Core MVC.
Why Do We Need to Encrypt Cookies in ASP.NET Core MVC?
Encrypting Cookies in ASP.NET Core MVC is essential for enhancing the application’s security. This ensures that sensitive information within cookies cannot be easily read or tampered with by unauthorized users.
- Cookies can store sensitive information such as user authentication tokens, session identifiers, user preferences, and other data. Encrypting this information ensures that it cannot be easily read by anyone who intercepts the cookie data.
- Encryption helps prevent unauthorized modification of cookie data. Without encryption, an attacker could modify the contents of a cookie to manipulate application behavior, leading to security vulnerabilities such as privilege escalation or unauthorized access.
- Many privacy regulations and standards, such as GDPR, HIPAA, and PCI-DSS, require that sensitive data be protected. Encrypting cookies helps organizations comply with these regulations by ensuring that personal and sensitive information is kept secure.
ASP.NET Core provides built-in mechanisms to implement Cookie Encryption. Using the Data Protection API, we can encrypt Cookies in an ASP.NET Core MVC application.
What is Data Protection API in ASP.NET Core?
In ASP.NET Core MVC, the Data Protection API (DPAPI) encrypts sensitive data such as cookies, authentication tokens, and other sensitive information that needs to be securely stored on the client side or transmitted over the network. The Data Protection API (DPAPI) in ASP.NET Core is a robust, built-in framework that provides services for encrypting and decrypting data.
How Do We Encrypt Custom Cookies in ASP.NET Core MVC?
If we create custom cookies and want to ensure they are encrypted, we need to use the Data Protection API. Let’s understand this with an example. First, create a class file named MyCookieService.cs within the Models folder, and then copy and paste the following code. The code is self-explained, so please read the comment lines for a better understanding.
using Microsoft.AspNetCore.DataProtection; namespace SampleMVCWeb.Models { public class MyCookieService { // Declare a private field to hold IDataProtector instance. private readonly IDataProtector _protector; // Constructor that accepts an IDataProtectionProvider and creates a data protector. public MyCookieService(IDataProtectionProvider dataProtectionProvider) { // Initialize _protector with an IDataProtector instance created using IDataProtectionProvider. // The "ampleMVCWeb.CookieProtection" string is a purpose string used for data protection. // Ensure this string is unique per data protection context to maintain security. _protector = dataProtectionProvider.CreateProtector("SampleMVCWeb.CookieProtection"); } // Method to encrypt (protect) the cookie value. public string Protect(string cookieValue) { try { // Encrypt the provided cookieValue using the IDataProtector instance _protector. // Return the encrypted (protected) cookieValue as a string. return _protector.Protect(cookieValue); } catch (Exception ex) { // Log the exception and rethrow or handle as appropriate. // Logging can be done using a logging framework like NLog, Serilog, etc. // For this example, we'll just rethrow the exception. throw new Exception("An error occurred while encrypting the cookie value.", ex); } } // Method to decrypt (unprotect) the encrypted cookie value. public string Unprotect(string protectedCookieValue) { try { // Decrypt the provided protectedCookieValue using the IDataProtector instance _protector. // Return the decrypted cookieValue as a string. return _protector.Unprotect(protectedCookieValue); } catch (Exception ex) { // Log the exception and rethrow or handle as appropriate. // Logging can be done using a logging framework like NLog, Serilog, etc. // For this example, we'll just rethrow the exception. throw new Exception("An error occurred while decrypting the cookie value.", ex); } } } }
Explanation of Key Concepts:
The Data Protection API works by creating a data protection provider, which is used to create a data protector. The data protector is responsible for encrypting and decrypting data.
- IDataProtectionProvider: This interface is responsible for creating instances of IDataProtector, which performs data protection operations such as encryption and decryption.
- IDataProtector: This interface is responsible for encrypting and decrypting the data. It uses a purpose string (“SampleMVCWeb.CookieProtection”) to ensure that data encrypted under one purpose string cannot be decrypted with another, providing security against data tampering.
- Protect Method: This method encrypts the cookieValue parameter using the _protector instance and returns the encrypted string. It ensures that sensitive cookie data is stored securely.
- Unprotect Method: Decrypts the protectedCookieValue parameter using the _protector instance and returns the decrypted string. It ensures that encrypted cookie data can be safely retrieved and used in the application.
Storing Cookies
When storing cookies in the response header, we need to encrypt the data, and that encrypted data we need to store in the Response header. First, we need to encrypt the data using DataProtector API and then store the encrypted data in the Cookies. The syntax to encrypt the cookie is given below:
//Encrypt the Value using Data Protection API string encryptedValue = myCookieService.Protect("Cookie Value"); //Store the Encrypted Cookie Value in the Response Header Response.Cookies.Append("myCookie", encryptedValue, cookieOptions);
Reading Cookies
When reading the cookie, decrypt the data. First, we need to read the encrypted data from the Cookie and then use the DataProtector API to decrypt the data. The syntax to decrypt the cookie is given below:
//Fetch the Encrypted Cookie Value from the Response Header string encryptedValue = Request.Cookies["myCookie"]; //Decrypt the Encryoted Value using the Data Protection API string decryptedValue = myCookieService.Unprotect(encryptedValue);
Configuring the Service:
Next, we need to configure the MyCookieService within the built-in dependency injection container to access the service throughout the application. Please add the following code to the Program class. Here, we are registering the service as a Singleton.
builder.Services.AddSingleton<MyCookieService>();
Modifying Home Controller:
Next, modify the Home Controller as follows. First, we need to inject the MyCookieService instance through the constructor, and then, using this MyCookieService instance, we need to encrypt and decrypt the cookies. Further, we have stored the retrieved cookie values in the ViewBag, which will be displayed in the UI. We don’t want to write the logic to fetch the encrypted data from the cookie and decrypt the value in the View file.
using Microsoft.AspNetCore.Mvc; using SampleMVCWeb.Models; namespace SampleMVCWeb.Controllers { public class HomeController : Controller { // Define constant strings for cookie names const string CookieUserId = "UserId"; const string CookieUserName = "UserName"; // Declare a private field to hold MyCookieService instance private readonly MyCookieService _myCookieService; // Constructor that accepts MyCookieService and initializes _myCookieService public HomeController(MyCookieService myCookieService) { _myCookieService = myCookieService; } // Action method for the Index view public IActionResult Index() { // Let us assume the User is logged in and we need to store the user information in the cookie var cookieOptions = new CookieOptions { HttpOnly = true, // Set cookie as HttpOnly Secure = true, // Set cookie as Secure Expires = DateTime.Now.AddDays(7) // Set cookie expiration date }; try { // Encrypt the Cookie Value for UserId string encryptedUserId = _myCookieService.Protect("1234567"); // Store the Encrypted value in the Cookies Response Header Response.Cookies.Append(CookieUserId, encryptedUserId, cookieOptions); // Encrypt the Cookie Value for UserName string encryptedUserName = _myCookieService.Protect("pranaya@dotnettutotials.net"); // Store the Encrypted value in the Cookies Response Header Response.Cookies.Append(CookieUserName, encryptedUserName, cookieOptions); } catch (Exception ex) { // Handle the exception (e.g., log the error) // For simplicity, we'll just display the error message in ViewBag ViewBag.Error = $"Error encrypting cookies: {ex.Message}"; } try { // Fetch and decrypt UserName from cookies if it exists string? encryptedUserNameValue = Request.Cookies[CookieUserName]; if (encryptedUserNameValue != null) { ViewBag.UserName = _myCookieService.Unprotect(encryptedUserNameValue); } // Fetch and decrypt UserId from cookies if it exists string? encryptedUserIdValue = Request.Cookies[CookieUserId]; if (encryptedUserIdValue != null) { ViewBag.UserId = Convert.ToInt32(_myCookieService.Unprotect(encryptedUserIdValue)); } } catch (Exception ex) { // Handle the exception (e.g., log the error) // For simplicity, we'll just display the error message in ViewBag ViewBag.Error = $"Error decrypting cookies: {ex.Message}"; } return View(); // Return the view } // Action method for the About view public string About() { try { string? UserName = null; // Fetch the Encrypted Cookie for UserName from the Request Header string? encryptedUserNameValue = Request.Cookies[CookieUserName]; if (encryptedUserNameValue != null) { // Decrypt the Encrypted Value UserName = _myCookieService.Unprotect(encryptedUserNameValue); } int? UserId = null; // Fetch the Encrypted Cookie for UserId from the Request Header string? encryptedUserIdValue = Request.Cookies[CookieUserId]; if (encryptedUserIdValue != null) { // Decrypt the Encrypted Value UserId = Convert.ToInt32(_myCookieService.Unprotect(encryptedUserIdValue)); } string Message = $"UserName: {UserName}, UserId: {UserId}"; return Message; // Return the message with user information } catch (Exception ex) { return $"Error Occurred: {ex.Message}"; // Return the error message } } // Action method for the Privacy view public IActionResult Privacy() { try { // Fetch the Encrypted Cookie for UserName from the Request Header string? encryptedUserNameValue = Request.Cookies[CookieUserName]; if (encryptedUserNameValue != null) { // Store the Decrypted Value in the ViewBag to display in the UI ViewBag.UserName = _myCookieService.Unprotect(encryptedUserNameValue); } // Fetch the Encrypted Cookie for UserId from the Request Header string? encryptedUserIdValue = Request.Cookies[CookieUserId]; if (encryptedUserIdValue != null) { // Store the Decrypted Value in the ViewBag to display in the UI ViewBag.UserId = Convert.ToInt32(_myCookieService.Unprotect(encryptedUserIdValue)); } } catch (Exception ex) { // Handle the exception (e.g., log the error) // For simplicity, we'll just display the error message in ViewBag ViewBag.Error = $"Error decrypting cookies: {ex.Message}"; } return View(); // Return the view } // Action method to delete cookies public string DeleteCookie() { // Delete the Cookie From the Response Header, i.e., from the Browser. Response.Cookies.Delete(CookieUserId); Response.Cookies.Delete(CookieUserName); return "Cookies are Deleted"; // Return the confirmation message } } }
Modifying Index.cshtml View
@{ ViewData["Title"] = "Home Page"; } <div class="text-left"> <b>User Name:</b> @ViewBag.UserName <br /> <b>User Id:</b> @ViewBag.UserId </div>
Modifying Privacy.cshtml View
@{ ViewData["Title"] = "Privacy Policy"; } <h1>@ViewData["Title"]</h1> <div class="text-left"> <b>User Name:</b> @ViewBag.UserName <br /> <b>User Id:</b> @ViewBag.UserId </div>
With the above changes in place, run the application, and now you should see the cookies are transmitted over the network in encrypted format, as shown in the below image:
Configuring Cookie Options Globally in ASP.NET Core MVC:
Configuring Cookie Options globally in the ASP.NET Core MVC application is an efficient way to ensure that all cookies in our application follow the same settings, such as security levels, domain, path, expiration, and other attributes. This is important for maintaining consistent security across the application.
For example, if we want to store the cookies using multiple action methods and we want all action methods to follow the same set of cookie option settings, then we need to configure the cookie settings globally. So, please add the following code to the Program.cs class file:
// The ConfigureApplicationCookie method is an extension method provided by ASP.NET Core // to configure the properties of the cookie used for application authentication. builder.Services.ConfigureApplicationCookie(options => { // Cookie settings // Sets the HttpOnly property to true, which means the cookie cannot be accessed by client-side scripts. // This is a security feature to help prevent cross-site scripting (XSS) attacks. options.Cookie.HttpOnly = true; //SecurePolicy specifies when cookies should be sent over HTTPS. //CookieSecurePolicy.Always ensures cookies are transmitted over HTTPS only, enhancing data security during transport. options.Cookie.SecurePolicy = CookieSecurePolicy.Always; // Marks the cookie as essential for the application. // Essential cookies are allowed even under strict privacy settings (like GDPR) without requiring consent from the user. // This is useful for cookies that are critical for the application's functionality, such as session or authentication cookies. options.Cookie.IsEssential = true; // Sets the expiration time of the cookie to 1 day. // After this period, the cookie will automatically be invalidated and removed. // This setting is important for limiting the duration of the login session for security purposes. options.Cookie.Expiration = TimeSpan.FromDays(1); });
The ConfigureApplicationCookie method in ASP.NET Core MVC customizes the settings and behavior of the cookie used for application authentication. This method allows us to configure various aspects of the authentication cookie, such as lifespan, security, cookie essentials, and paths for login and access denied pages. Later, when we discuss ASP.NET Core Identity, we will see how to configure the Login and Access Denied Path.
Modifying the Home Controller:
Now, you need to use the other version of the Append method to set the cookie, which does not take the cookie option object. So, modify the Home Controller class as follows:
using Microsoft.AspNetCore.Mvc; using SampleMVCWeb.Models; namespace SampleMVCWeb.Controllers { public class HomeController : Controller { // Define constant strings for cookie names const string CookieUserId = "UserId"; const string CookieUserName = "UserName"; // Declare a private field to hold MyCookieService instance private readonly MyCookieService _myCookieService; // Constructor that accepts MyCookieService and initializes _myCookieService public HomeController(MyCookieService myCookieService) { _myCookieService = myCookieService; } // Action method for the Index view public IActionResult Index() { try { // Encrypt the Cookie Value for UserId string encryptedUserId = _myCookieService.Protect("1234567"); // Store the Encrypted value in the Cookies Response Header Response.Cookies.Append(CookieUserId, encryptedUserId); // Encrypt the Cookie Value for UserName string encryptedUserName = _myCookieService.Protect("pranaya@dotnettutotials.net"); // Store the Encrypted value in the Cookies Response Header Response.Cookies.Append(CookieUserName, encryptedUserName); } catch (Exception ex) { // Handle the exception (e.g., log the error) // For simplicity, we'll just display the error message in ViewBag ViewBag.Error = $"Error encrypting cookies: {ex.Message}"; } try { // Fetch and decrypt UserName from cookies if it exists string? encryptedUserNameValue = Request.Cookies[CookieUserName]; if (encryptedUserNameValue != null) { ViewBag.UserName = _myCookieService.Unprotect(encryptedUserNameValue); } // Fetch and decrypt UserId from cookies if it exists string? encryptedUserIdValue = Request.Cookies[CookieUserId]; if (encryptedUserIdValue != null) { ViewBag.UserId = Convert.ToInt32(_myCookieService.Unprotect(encryptedUserIdValue)); } } catch (Exception ex) { // Handle the exception (e.g., log the error) // For simplicity, we'll just display the error message in ViewBag ViewBag.Error = $"Error decrypting cookies: {ex.Message}"; } return View(); // Return the view } // Action method for the About view public string About() { try { string? UserName = null; // Fetch the Encrypted Cookie for UserName from the Request Header string? encryptedUserNameValue = Request.Cookies[CookieUserName]; if (encryptedUserNameValue != null) { // Decrypt the Encrypted Value UserName = _myCookieService.Unprotect(encryptedUserNameValue); } int? UserId = null; // Fetch the Encrypted Cookie for UserId from the Request Header string? encryptedUserIdValue = Request.Cookies[CookieUserId]; if (encryptedUserIdValue != null) { // Decrypt the Encrypted Value UserId = Convert.ToInt32(_myCookieService.Unprotect(encryptedUserIdValue)); } string Message = $"UserName: {UserName}, UserId: {UserId}"; return Message; // Return the message with user information } catch (Exception ex) { return $"Error Occurred: {ex.Message}"; // Return the error message } } // Action method for the Privacy view public IActionResult Privacy() { try { // Fetch the Encrypted Cookie for UserName from the Request Header string? encryptedUserNameValue = Request.Cookies[CookieUserName]; if (encryptedUserNameValue != null) { // Store the Decrypted Value in the ViewBag to display in the UI ViewBag.UserName = _myCookieService.Unprotect(encryptedUserNameValue); } // Fetch the Encrypted Cookie for UserId from the Request Header string? encryptedUserIdValue = Request.Cookies[CookieUserId]; if (encryptedUserIdValue != null) { // Store the Decrypted Value in the ViewBag to display in the UI ViewBag.UserId = Convert.ToInt32(_myCookieService.Unprotect(encryptedUserIdValue)); } } catch (Exception ex) { // Handle the exception (e.g., log the error) // For simplicity, we'll just display the error message in ViewBag ViewBag.Error = $"Error decrypting cookies: {ex.Message}"; } return View(); // Return the view } // Action method to delete cookies public string DeleteCookie() { // Delete the Cookie From the Response Header, i.e., from the Browser. Response.Cookies.Delete(CookieUserId); Response.Cookies.Delete(CookieUserName); return "Cookies are Deleted"; // Return the confirmation message } } }
After making the above changes, run the application, and you should see that it works as expected.
When Should We Use Encrypted Cookies in ASP.NET Core MVC?
Encrypted cookies in ASP.NET Core MVC should be used when we need to store sensitive or important information in cookies that should not be easily accessible or tampered with. Encrypting cookies ensures that their contents are protected from unauthorized access and modification. The following are some specific scenarios where encrypted cookies are useful:
- Storing Authentication Tokens: When using cookies for authentication purposes (e.g., storing JWT tokens or session identifiers). Authentication tokens are sensitive and should be protected to prevent unauthorized access.
- Maintaining User Sessions: When storing session data or user-specific information that persists across multiple requests, it is important to keep it confidential. Session data often includes sensitive information such as user IDs, roles, or preferences.
- Storing Personal Identifiable Information (PII): Cookies are used to store personal information such as names, email addresses, or contact details. Encrypting PII helps protect user privacy and comply with data protection regulations like GDPR.
- Securing CSRF Tokens: When using cookies to store Cross-Site Request Forgery (CSRF) tokens. Ensuring that CSRF tokens are encrypted adds an additional layer of security to prevent CSRF attacks.
- E-commerce Applications: Encrypting cookies containing shopping cart items, order details, or payment information enhances security and protects sensitive transaction data.
In the next article, I will discuss Persistent vs Non-Persistent Cookies in ASP.NET Core MVC Applications with Examples. In this article, I will explain how to Encrypt Cookies in ASP.NET Core MVC applications with examples. I hope you enjoy this article on encrypting cookies in the ASP.NET Core MVC.