= Other topics (Performance, Security, …) == Performance == Security {{{#!div style="text-align: justify; width: 100%;" ==== Cookie-based Authentication For authentication in our application, we use ASP.NET Core cookie authentication. After a user successfully logs in, the server creates an authentication cookie containing information about the authenticated user. This allows the application to recognize the user on subsequent requests without requiring them to log in again for every request. Cookie authentication is configured in {{{Program.cs}}}: {{{ builder.Services .AddAuthentication("Cookies") .AddCookie("Cookies", options => { options.LoginPath = "/Account/Login"; options.AccessDeniedPath = "/Account/Login"; options.ExpireTimeSpan = TimeSpan.FromHours(8); options.SlidingExpiration = true; }); builder.Services.AddAuthorization(); }}} The authentication cookie is valid for 8 hours. Sliding expiration is enabled, meaning the authentication period can be renewed while the user remains active. After successful login, claims containing information about the user are created: {{{ var claims = new List { new Claim( ClaimTypes.NameIdentifier, user.UserId.ToString()), new Claim( ClaimTypes.Name, user.Username), new Claim( ClaimTypes.Email, user.Email), new Claim( ClaimTypes.Role, role) }; }}} An identity and authentication principal are then created: {{{ var identity = new ClaimsIdentity( claims, "Cookies"); var principal = new ClaimsPrincipal(identity); await HttpContext.SignInAsync( "Cookies", principal); }}} The role claim allows us to distinguish between consumers and administrators and can be used to restrict access to specific functionality. When the user logs out, the authentication cookie is invalidated: {{{ await HttpContext.SignOutAsync("Cookies"); HttpContext.Session.Clear(); }}} ==== Password Storage For password hashing, we use ASP.NET Core's {{{PasswordHasher}}}: {{{ builder.Services.AddScoped< IPasswordHasher, PasswordHasher>(); }}} When a new user registers, their password is hashed before it is stored in the database: {{{ user.Password = _passwordHasher.HashPassword( user, model.Password); _context.Users.Add(user); _context.SaveChanges(); }}} Because password hashing is a one-way operation, the original password cannot be obtained from the stored value. During login, we first retrieve the user by username: {{{ var user = _context.Users .FirstOrDefault(x => x.Username == model.Username); }}} The entered password is then verified against the stored password hash: {{{ var result = _passwordHasher.VerifyHashedPassword( user, user.Password, model.Password); if (result == PasswordVerificationResult.Failed) { ModelState.AddModelError( "", "Invalid username or password."); return View(model); } }}} This allows the application to verify a password without ever storing or comparing plaintext passwords in the database. ==== Protection Against CSRF For POST requests that modify application data, ASP.NET Core anti-forgery protection is used. Controller actions that receive POST requests are marked with: {{{ [HttpPost] [ValidateAntiForgeryToken] }}} For example: {{{ [HttpPost] [ValidateAntiForgeryToken] public IActionResult Register(RegisterViewModel model) { // ... } }}} The anti-forgery token protects the application against Cross-Site Request Forgery (CSRF) attacks by ensuring that the submitted request originates from a valid application form. ==== HTTPS and HSTS The application redirects HTTP requests to HTTPS: {{{ app.UseHttpsRedirection(); }}} Additionally, outside the development environment, HTTP Strict Transport Security (HSTS) is enabled: {{{ if (!app.Environment.IsDevelopment()) { app.UseExceptionHandler("/Home/Error"); app.UseHsts(); } }}} HTTPS protects communication between the browser and the server by encrypting transmitted information, while HSTS instructs browsers to use HTTPS when communicating with the application. }}}