Files
Masterarbeit/Versuche/Versuch 02/Ergenisse/software/Security_Patterns.md

1037 lines
36 KiB
Markdown

# Security Patterns and Implementation - Centron Enterprise Application
## Overview
This document provides comprehensive coverage of security patterns and implementations within the Centron .NET 8 enterprise application. Security patterns encompass authentication, authorization, data protection, audit logging, secure communication, and security boundary enforcement that protect the application and its data from threats.
## Security Architecture
### **Multi-Layered Security Approach**
The Centron application implements a defense-in-depth security strategy with multiple security layers:
1. **Network Security**: Secure communication protocols and network segmentation
2. **Application Security**: Authentication, authorization, and input validation
3. **Data Security**: Encryption, data protection, and secure storage
4. **Audit Security**: Comprehensive logging and monitoring
5. **Operational Security**: Secure deployment and configuration management
## Authentication Patterns
### **1. Multi-Authentication Strategy Pattern**
The application supports multiple authentication mechanisms through a unified interface:
```csharp
public interface IAuthenticator
{
Task<Result<AuthenticationResult>> AuthenticateAsync(AuthenticationRequest request);
Task<Result> ValidateTokenAsync(string token);
Task<Result> RefreshTokenAsync(string refreshToken);
bool SupportsAuthenticationType(AuthenticationType type);
}
public class AuthenticatorFactory
{
private readonly Dictionary<AuthenticationType, IAuthenticator> _authenticators = new();
public AuthenticatorFactory()
{
_authenticators[AuthenticationType.Basic] = new BasicAuthenticator();
_authenticators[AuthenticationType.ActiveDirectory] = new ActiveDirectoryAuthenticator();
_authenticators[AuthenticationType.OpenIdConnect] = new OpenIdConnectAuthenticator();
_authenticators[AuthenticationType.WebAccount] = new WebAccountAuthenticator();
}
public IAuthenticator GetAuthenticator(AuthenticationType type)
{
return _authenticators.ContainsKey(type)
? _authenticators[type]
: throw new NotSupportedException($"Authentication type {type} is not supported");
}
}
// Basic Authentication Implementation
public class BasicAuthenticator : IAuthenticator
{
private readonly IUserRepository _userRepository;
private readonly IPasswordHashingService _passwordService;
public async Task<Result<AuthenticationResult>> AuthenticateAsync(AuthenticationRequest request)
{
try
{
Guard.NotNullOrEmpty(request.Username, nameof(request.Username));
Guard.NotNullOrEmpty(request.Password, nameof(request.Password));
var userResult = await _userRepository.GetUserByUsernameAsync(request.Username);
if (userResult.Status != ResultStatus.Success || userResult.Data == null)
return Result<AuthenticationResult>.AsError("Invalid username or password");
var user = userResult.Data;
// Check if account is locked
if (user.IsLocked)
return Result<AuthenticationResult>.AsError("Account is locked. Please contact administrator.");
// Verify password
var passwordValid = _passwordService.VerifyPassword(request.Password, user.PasswordHash, user.Salt);
if (!passwordValid)
{
await IncrementFailedLoginAttempts(user);
return Result<AuthenticationResult>.AsError("Invalid username or password");
}
// Reset failed login attempts on successful login
await ResetFailedLoginAttempts(user);
// Generate authentication token
var token = GenerateAuthenticationToken(user);
return Result<AuthenticationResult>.AsSuccess(new AuthenticationResult
{
User = user,
Token = token,
ExpiresAt = DateTime.UtcNow.AddHours(8),
AuthenticationType = AuthenticationType.Basic
});
}
catch (Exception ex)
{
return Result<AuthenticationResult>.AsError($"Authentication failed: {ex.Message}");
}
}
private async Task IncrementFailedLoginAttempts(User user)
{
user.FailedLoginAttempts++;
user.LastFailedLogin = DateTime.UtcNow;
// Lock account after 5 failed attempts
if (user.FailedLoginAttempts >= 5)
{
user.IsLocked = true;
user.LockedAt = DateTime.UtcNow;
}
await _userRepository.UpdateUserAsync(user);
}
}
// Active Directory Authentication
public class ActiveDirectoryAuthenticator : IAuthenticator
{
private readonly IActiveDirectoryService _adService;
private readonly IUserMappingService _userMappingService;
public async Task<Result<AuthenticationResult>> AuthenticateAsync(AuthenticationRequest request)
{
try
{
// Authenticate against Active Directory
var adAuthResult = await _adService.AuthenticateUserAsync(request.Username, request.Password);
if (!adAuthResult.IsSuccess)
return Result<AuthenticationResult>.AsError("Active Directory authentication failed");
// Map AD user to local user
var userMappingResult = await _userMappingService.GetOrCreateUserFromAdAsync(adAuthResult.User);
if (userMappingResult.Status != ResultStatus.Success)
return Result<AuthenticationResult>.FromResult(userMappingResult);
var localUser = userMappingResult.Data;
// Check user status
if (!localUser.IsActive)
return Result<AuthenticationResult>.AsError("User account is disabled");
// Generate token
var token = GenerateAuthenticationToken(localUser);
return Result<AuthenticationResult>.AsSuccess(new AuthenticationResult
{
User = localUser,
Token = token,
ExpiresAt = DateTime.UtcNow.AddHours(8),
AuthenticationType = AuthenticationType.ActiveDirectory,
AdditionalClaims = ExtractAdClaims(adAuthResult.User)
});
}
catch (Exception ex)
{
return Result<AuthenticationResult>.AsError($"AD authentication failed: {ex.Message}");
}
}
}
// OpenID Connect Authentication
public class OpenIdConnectAuthenticator : IAuthenticator
{
private readonly IOpenIdConnectService _oidcService;
public async Task<Result<AuthenticationResult>> AuthenticateAsync(AuthenticationRequest request)
{
try
{
// Validate OIDC token
var tokenValidationResult = await _oidcService.ValidateTokenAsync(request.Token);
if (!tokenValidationResult.IsValid)
return Result<AuthenticationResult>.AsError("Invalid OpenID Connect token");
// Extract user information from token claims
var userInfo = ExtractUserInfoFromClaims(tokenValidationResult.Claims);
// Get or create local user account
var localUserResult = await GetOrCreateLocalUser(userInfo);
if (localUserResult.Status != ResultStatus.Success)
return Result<AuthenticationResult>.FromResult(localUserResult);
return Result<AuthenticationResult>.AsSuccess(new AuthenticationResult
{
User = localUserResult.Data,
Token = request.Token,
ExpiresAt = tokenValidationResult.ExpiresAt,
AuthenticationType = AuthenticationType.OpenIdConnect
});
}
catch (Exception ex)
{
return Result<AuthenticationResult>.AsError($"OIDC authentication failed: {ex.Message}");
}
}
}
```
### **2. Token-Based Authentication Pattern**
```csharp
public class TokenAuthenticationService
{
private readonly ITokenGenerator _tokenGenerator;
private readonly ITokenValidator _tokenValidator;
private readonly IUserRepository _userRepository;
public async Task<Result<string>> GenerateTokenAsync(User user, TimeSpan? expiry = null)
{
try
{
var expiresAt = DateTime.UtcNow.Add(expiry ?? TimeSpan.FromHours(8));
var tokenClaims = new TokenClaims
{
UserId = user.I3D,
Username = user.Username,
Email = user.Email,
Roles = user.UserRoles.Select(ur => ur.Role.Name).ToList(),
ExpiresAt = expiresAt,
IssuedAt = DateTime.UtcNow
};
var token = _tokenGenerator.GenerateToken(tokenClaims);
// Store token in database for revocation capability
await StoreTokenAsync(token, user.I3D, expiresAt);
return Result<string>.AsSuccess(token);
}
catch (Exception ex)
{
return Result<string>.AsError($"Token generation failed: {ex.Message}");
}
}
public async Task<Result<TokenValidationResult>> ValidateTokenAsync(string token)
{
try
{
// Check if token is revoked
var isRevokedResult = await IsTokenRevokedAsync(token);
if (isRevokedResult.Status == ResultStatus.Success && isRevokedResult.Data)
return Result<TokenValidationResult>.AsError("Token has been revoked");
// Validate token signature and expiry
var validationResult = _tokenValidator.ValidateToken(token);
if (!validationResult.IsValid)
return Result<TokenValidationResult>.AsError(validationResult.Error);
// Verify user still exists and is active
var userResult = await _userRepository.GetUserByIdAsync(validationResult.Claims.UserId);
if (userResult.Status != ResultStatus.Success || !userResult.Data.IsActive)
return Result<TokenValidationResult>.AsError("User account is no longer active");
return Result<TokenValidationResult>.AsSuccess(new TokenValidationResult
{
IsValid = true,
Claims = validationResult.Claims,
User = userResult.Data
});
}
catch (Exception ex)
{
return Result<TokenValidationResult>.AsError($"Token validation failed: {ex.Message}");
}
}
public async Task<Result> RevokeTokenAsync(string token)
{
return await RevokeTokenInDatabaseAsync(token);
}
}
```
## Authorization Patterns
### **1. Role-Based Access Control (RBAC) Pattern**
```csharp
public class AuthorizationService
{
private readonly IUserRightsRepository _userRightsRepository;
private readonly IRoleRepository _roleRepository;
public async Task<Result<bool>> HasRightAsync(int userId, int rightId)
{
try
{
var userRightsResult = await _userRightsRepository.GetUserRightsAsync(userId);
if (userRightsResult.Status != ResultStatus.Success)
return Result<bool>.FromResult(userRightsResult);
var hasRight = userRightsResult.Data.Any(ur => ur.RightI3D == rightId && ur.HasRight);
return Result<bool>.AsSuccess(hasRight);
}
catch (Exception ex)
{
return Result<bool>.AsError($"Authorization check failed: {ex.Message}");
}
}
public async Task<Result<bool>> HasRoleAsync(int userId, string roleName)
{
try
{
var userRolesResult = await _roleRepository.GetUserRolesAsync(userId);
if (userRolesResult.Status != ResultStatus.Success)
return Result<bool>.FromResult(userRolesResult);
var hasRole = userRolesResult.Data.Any(r => r.Name.Equals(roleName, StringComparison.OrdinalIgnoreCase));
return Result<bool>.AsSuccess(hasRole);
}
catch (Exception ex)
{
return Result<bool>.AsError($"Role check failed: {ex.Message}");
}
}
public async Task<Result<List<int>>> GetUserRightsAsync(int userId)
{
try
{
var userRightsResult = await _userRightsRepository.GetUserRightsAsync(userId);
if (userRightsResult.Status != ResultStatus.Success)
return Result<List<int>>.FromResult(userRightsResult);
var rightIds = userRightsResult.Data
.Where(ur => ur.HasRight)
.Select(ur => ur.RightI3D)
.ToList();
return Result<List<int>>.AsSuccess(rightIds);
}
catch (Exception ex)
{
return Result<List<int>>.AsError($"Failed to get user rights: {ex.Message}");
}
}
}
// Authorization attribute for web service endpoints
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class)]
public class AuthenticateAttribute : Attribute
{
public int[] RequiredRights { get; set; }
public string[] RequiredRoles { get; set; }
public bool AllowAnonymous { get; set; } = false;
public AuthenticateAttribute(params int[] requiredRights)
{
RequiredRights = requiredRights ?? new int[0];
}
}
// Authorization enforcement interceptor
public class AuthorizationInterceptor
{
private readonly AuthorizationService _authorizationService;
public async Task<Result> AuthorizeAsync(MethodInvocationContext context)
{
var authAttribute = context.Method.GetCustomAttribute<AuthenticateAttribute>();
if (authAttribute == null || authAttribute.AllowAnonymous)
return Result.AsSuccess();
var currentUser = context.GetCurrentUser();
if (currentUser == null)
return Result.AsError("Authentication required");
// Check required rights
if (authAttribute.RequiredRights != null && authAttribute.RequiredRights.Any())
{
foreach (var requiredRight in authAttribute.RequiredRights)
{
var hasRightResult = await _authorizationService.HasRightAsync(currentUser.I3D, requiredRight);
if (hasRightResult.Status != ResultStatus.Success || !hasRightResult.Data)
return Result.AsError($"Access denied. Required right: {requiredRight}");
}
}
// Check required roles
if (authAttribute.RequiredRoles != null && authAttribute.RequiredRoles.Any())
{
foreach (var requiredRole in authAttribute.RequiredRoles)
{
var hasRoleResult = await _authorizationService.HasRoleAsync(currentUser.I3D, requiredRole);
if (hasRoleResult.Status != ResultStatus.Success || !hasRoleResult.Data)
return Result.AsError($"Access denied. Required role: {requiredRole}");
}
}
return Result.AsSuccess();
}
}
// Usage in web service methods
public class CentronRestService : ICentronRestService
{
[Authenticate(UserRightsConst.Sales.Customer.SHOW_CUSTOMER)]
public async Task<Response<AccountDTO>> GetAccount(Request<AccountFilter> request)
{
// Method implementation - authorization is enforced by interceptor
var result = await _accountsLogic.GetAccountAsync(request.Data.Filter, request.Data.MixMode);
return Response<AccountDTO>.FromResult(result);
}
[Authenticate(UserRightsConst.Administration.Users.MANAGE_USERS)]
public async Task<Response<List<UserDTO>>> GetUsers(Request<UserFilter> request)
{
// Only users with MANAGE_USERS right can access this method
var result = await _userLogic.GetUsersAsync(request.Data);
return Response<List<UserDTO>>.FromResult(result);
}
}
```
### **2. Feature-Based Authorization Pattern**
```csharp
public class FeatureAuthorizationService
{
private readonly IFeatureRepository _featureRepository;
public async Task<Result<bool>> IsFeatureEnabledForUserAsync(int userId, string featureName)
{
try
{
var userFeaturesResult = await _featureRepository.GetUserFeaturesAsync(userId);
if (userFeaturesResult.Status != ResultStatus.Success)
return Result<bool>.FromResult(userFeaturesResult);
var isEnabled = userFeaturesResult.Data.Any(f =>
f.Name.Equals(featureName, StringComparison.OrdinalIgnoreCase) && f.IsEnabled);
return Result<bool>.AsSuccess(isEnabled);
}
catch (Exception ex)
{
return Result<bool>.AsError($"Feature authorization check failed: {ex.Message}");
}
}
}
// Feature gate attribute
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class)]
public class RequireFeatureAttribute : Attribute
{
public string FeatureName { get; }
public RequireFeatureAttribute(string featureName)
{
FeatureName = featureName ?? throw new ArgumentNullException(nameof(featureName));
}
}
// Usage in UI modules
[RequireFeature(FeatureConst.ADVANCED_REPORTING)]
public class AdvancedReportModule : ICentronAppModuleController
{
public bool IsAvailable(User user)
{
// Feature authorization is checked by framework
return true;
}
}
```
## Data Protection Patterns
### **1. Encryption and Data Security Pattern**
```csharp
public interface IDataProtectionService
{
Result<string> EncryptSensitiveData(string plainText);
Result<string> DecryptSensitiveData(string encryptedText);
Result<string> HashPassword(string password, out string salt);
Result<bool> VerifyPassword(string password, string hash, string salt);
}
public class DataProtectionService : IDataProtectionService
{
private readonly IDataProtector _dataProtector;
private readonly IPasswordHasher _passwordHasher;
public DataProtectionService(IDataProtectionProvider dataProtectionProvider)
{
_dataProtector = dataProtectionProvider.CreateProtector("Centron.SensitiveData.v1");
_passwordHasher = new PasswordHasher();
}
public Result<string> EncryptSensitiveData(string plainText)
{
try
{
if (string.IsNullOrEmpty(plainText))
return Result<string>.AsSuccess(plainText);
var encrypted = _dataProtector.Protect(plainText);
return Result<string>.AsSuccess(encrypted);
}
catch (Exception ex)
{
return Result<string>.AsError($"Encryption failed: {ex.Message}");
}
}
public Result<string> DecryptSensitiveData(string encryptedText)
{
try
{
if (string.IsNullOrEmpty(encryptedText))
return Result<string>.AsSuccess(encryptedText);
var decrypted = _dataProtector.Unprotect(encryptedText);
return Result<string>.AsSuccess(decrypted);
}
catch (Exception ex)
{
return Result<string>.AsError($"Decryption failed: {ex.Message}");
}
}
public Result<string> HashPassword(string password, out string salt)
{
try
{
salt = GenerateSalt();
var hash = _passwordHasher.HashPassword(password + salt);
return Result<string>.AsSuccess(hash);
}
catch (Exception ex)
{
salt = null;
return Result<string>.AsError($"Password hashing failed: {ex.Message}");
}
}
public Result<bool> VerifyPassword(string password, string hash, string salt)
{
try
{
var isValid = _passwordHasher.VerifyPassword(password + salt, hash);
return Result<bool>.AsSuccess(isValid);
}
catch (Exception ex)
{
return Result<bool>.AsError($"Password verification failed: {ex.Message}");
}
}
private string GenerateSalt()
{
using (var rng = RandomNumberGenerator.Create())
{
var saltBytes = new byte[32];
rng.GetBytes(saltBytes);
return Convert.ToBase64String(saltBytes);
}
}
}
// Entity-level data protection
public class CustomerEntity
{
public int I3D { get; set; }
public string CompanyName { get; set; }
[SensitiveData]
public string Email { get; set; }
[SensitiveData]
public string PhoneNumber { get; set; }
[SensitiveData]
public string BankAccountNumber { get; set; }
// Navigation properties
public virtual List<CustomerAddress> Addresses { get; set; }
}
// Data protection interceptor
public class SensitiveDataInterceptor
{
private readonly IDataProtectionService _dataProtection;
public void OnSaving(object entity)
{
var properties = entity.GetType().GetProperties()
.Where(p => p.GetCustomAttribute<SensitiveDataAttribute>() != null);
foreach (var property in properties)
{
var value = property.GetValue(entity) as string;
if (!string.IsNullOrEmpty(value))
{
var encryptedResult = _dataProtection.EncryptSensitiveData(value);
if (encryptedResult.Status == ResultStatus.Success)
{
property.SetValue(entity, encryptedResult.Data);
}
}
}
}
public void OnLoading(object entity)
{
var properties = entity.GetType().GetProperties()
.Where(p => p.GetCustomAttribute<SensitiveDataAttribute>() != null);
foreach (var property in properties)
{
var value = property.GetValue(entity) as string;
if (!string.IsNullOrEmpty(value))
{
var decryptedResult = _dataProtection.DecryptSensitiveData(value);
if (decryptedResult.Status == ResultStatus.Success)
{
property.SetValue(entity, decryptedResult.Data);
}
}
}
}
}
```
## Audit Logging and Compliance Patterns
### **1. Comprehensive Audit Trail Pattern**
```csharp
public class AuditService
{
private readonly IAuditRepository _auditRepository;
private readonly ICurrentUserService _currentUserService;
public async Task<Result> LogActionAsync(AuditLogEntry auditEntry)
{
try
{
auditEntry.UserId = _currentUserService.GetCurrentUserId();
auditEntry.Timestamp = DateTime.UtcNow;
auditEntry.IpAddress = _currentUserService.GetCurrentUserIpAddress();
auditEntry.UserAgent = _currentUserService.GetCurrentUserAgent();
var result = await _auditRepository.SaveAuditEntryAsync(auditEntry);
return result;
}
catch (Exception ex)
{
// Audit logging should never fail the main operation
// Log error but return success
LogAuditError(ex);
return Result.AsSuccess();
}
}
public async Task<Result> LogDataAccessAsync(string tableName, int recordId, DataAccessType accessType, object oldValues = null, object newValues = null)
{
var auditEntry = new AuditLogEntry
{
ActionType = "DATA_ACCESS",
TableName = tableName,
RecordId = recordId,
AccessType = accessType.ToString(),
OldValues = oldValues != null ? JsonSerializer.Serialize(oldValues) : null,
NewValues = newValues != null ? JsonSerializer.Serialize(newValues) : null
};
return await LogActionAsync(auditEntry);
}
public async Task<Result> LogBusinessActionAsync(string actionName, string entityType, int? entityId, Dictionary<string, object> parameters = null)
{
var auditEntry = new AuditLogEntry
{
ActionType = "BUSINESS_ACTION",
ActionName = actionName,
EntityType = entityType,
EntityId = entityId,
Parameters = parameters != null ? JsonSerializer.Serialize(parameters) : null
};
return await LogActionAsync(auditEntry);
}
public async Task<Result> LogSecurityEventAsync(SecurityEventType eventType, string description, Dictionary<string, object> details = null)
{
var auditEntry = new AuditLogEntry
{
ActionType = "SECURITY_EVENT",
SecurityEventType = eventType.ToString(),
Description = description,
Details = details != null ? JsonSerializer.Serialize(details) : null,
Severity = GetSeverityForSecurityEvent(eventType)
};
return await LogActionAsync(auditEntry);
}
}
// Audit interceptor for automatic logging
public class AuditInterceptor
{
private readonly AuditService _auditService;
public async Task LogMethodCallAsync(MethodInvocationContext context)
{
var auditAttribute = context.Method.GetCustomAttribute<AuditableAttribute>();
if (auditAttribute == null) return;
var parameters = context.Parameters?.ToDictionary(p => p.Key, p => p.Value);
await _auditService.LogBusinessActionAsync(
context.Method.Name,
context.TargetType.Name,
ExtractEntityId(context.Parameters),
parameters);
}
public async Task LogDataChangeAsync<T>(T entity, DataChangeType changeType, T oldEntity = default) where T : class
{
var entityType = typeof(T).Name;
var entityId = GetEntityId(entity);
await _auditService.LogDataAccessAsync(
entityType,
entityId,
ConvertChangeTypeToAccessType(changeType),
oldEntity,
entity);
}
}
// Usage in business logic
public class AccountBL : BaseBL
{
private readonly AuditService _auditService;
[Auditable]
public async Task<Result<Account>> SaveAccountAsync(Account account)
{
var oldAccount = account.I3D > 0 ? await GetAccountByIdAsync(account.I3D) : null;
// Save the account
var saveResult = await _accountRepository.SaveAsync(account);
if (saveResult.Status != ResultStatus.Success)
return saveResult;
// Log the change
await _auditService.LogDataAccessAsync(
"Account",
account.I3D,
oldAccount == null ? DataAccessType.Create : DataAccessType.Update,
oldAccount,
account);
return saveResult;
}
[Auditable]
public async Task<Result> DeleteAccountAsync(int accountId)
{
var account = await GetAccountByIdAsync(accountId);
var result = await _accountRepository.DeleteAsync(accountId);
if (result.Status == ResultStatus.Success)
{
await _auditService.LogDataAccessAsync("Account", accountId, DataAccessType.Delete, account, null);
}
return result;
}
}
```
### **2. GDPR Compliance Pattern**
```csharp
public class DataProtectionComplianceService
{
private readonly IAuditService _auditService;
private readonly IPersonalDataService _personalDataService;
public async Task<Result> ProcessDataDeletionRequestAsync(int customerId, string requestReason)
{
try
{
// Log the data deletion request
await _auditService.LogBusinessActionAsync(
"GDPR_DATA_DELETION_REQUEST",
"Customer",
customerId,
new Dictionary<string, object> { { "Reason", requestReason } });
// Identify all personal data related to customer
var personalDataResult = await _personalDataService.GetCustomerPersonalDataAsync(customerId);
if (personalDataResult.Status != ResultStatus.Success)
return Result.FromResult(personalDataResult);
// Anonymize or delete personal data
foreach (var dataLocation in personalDataResult.Data)
{
var anonymizationResult = await AnonymizePersonalDataAsync(dataLocation);
if (anonymizationResult.Status != ResultStatus.Success)
{
await _auditService.LogBusinessActionAsync(
"GDPR_DATA_DELETION_FAILED",
dataLocation.EntityType,
dataLocation.EntityId,
new Dictionary<string, object> { { "Error", anonymizationResult.Error } });
return anonymizationResult;
}
}
// Log successful completion
await _auditService.LogBusinessActionAsync(
"GDPR_DATA_DELETION_COMPLETED",
"Customer",
customerId,
new Dictionary<string, object> { { "DeletedDataCount", personalDataResult.Data.Count } });
return Result.AsSuccess();
}
catch (Exception ex)
{
await _auditService.LogSecurityEventAsync(
SecurityEventType.GdprComplianceFailure,
$"GDPR data deletion failed for customer {customerId}",
new Dictionary<string, object> { { "Exception", ex.Message } });
return Result.AsError($"Data deletion request processing failed: {ex.Message}");
}
}
public async Task<Result<PersonalDataExport>> ProcessDataExportRequestAsync(int customerId)
{
try
{
await _auditService.LogBusinessActionAsync(
"GDPR_DATA_EXPORT_REQUEST",
"Customer",
customerId);
var personalDataResult = await _personalDataService.GetCustomerPersonalDataAsync(customerId);
if (personalDataResult.Status != ResultStatus.Success)
return Result<PersonalDataExport>.FromResult(personalDataResult);
var exportData = new PersonalDataExport
{
CustomerId = customerId,
ExportDate = DateTime.UtcNow,
Data = personalDataResult.Data.ToDictionary(d => d.DataType, d => d.Value)
};
await _auditService.LogBusinessActionAsync(
"GDPR_DATA_EXPORT_COMPLETED",
"Customer",
customerId,
new Dictionary<string, object> { { "ExportedDataCount", exportData.Data.Count } });
return Result<PersonalDataExport>.AsSuccess(exportData);
}
catch (Exception ex)
{
return Result<PersonalDataExport>.AsError($"Data export request processing failed: {ex.Message}");
}
}
}
```
## Secure Communication Patterns
### **1. HTTPS and Certificate Management**
```csharp
public class SecureCommunicationService
{
public static HttpClient CreateSecureHttpClient(CertificateValidationMode validationMode = CertificateValidationMode.Default)
{
var handler = new HttpClientHandler();
switch (validationMode)
{
case CertificateValidationMode.Strict:
handler.ServerCertificateCustomValidationCallback = ValidateCertificateStrict;
break;
case CertificateValidationMode.AllowSelfSigned:
handler.ServerCertificateCustomValidationCallback = ValidateCertificateAllowSelfSigned;
break;
case CertificateValidationMode.Development:
handler.ServerCertificateCustomValidationCallback = (sender, cert, chain, errors) => true;
break;
}
var client = new HttpClient(handler);
client.DefaultRequestHeaders.Add("User-Agent", "CentronClient/1.0");
return client;
}
private static bool ValidateCertificateStrict(HttpRequestMessage request, X509Certificate2 certificate, X509Chain chain, SslPolicyErrors errors)
{
// Only allow certificates with no errors
return errors == SslPolicyErrors.None;
}
private static bool ValidateCertificateAllowSelfSigned(HttpRequestMessage request, X509Certificate2 certificate, X509Chain chain, SslPolicyErrors errors)
{
// Allow self-signed certificates but validate other aspects
if (errors == SslPolicyErrors.None)
return true;
if (errors == SslPolicyErrors.RemoteCertificateChainErrors)
{
// Check if the only error is self-signed certificate
foreach (X509ChainStatus status in chain.ChainStatus)
{
if (status.Status != X509ChainStatusFlags.UntrustedRoot)
return false;
}
return true;
}
return false;
}
}
```
### **2. API Security Pattern**
```csharp
public class ApiSecurityMiddleware
{
private readonly RequestDelegate _next;
private readonly IApiKeyValidator _apiKeyValidator;
private readonly IRateLimiter _rateLimiter;
public async Task InvokeAsync(HttpContext context)
{
// API Key validation
var apiKeyResult = await ValidateApiKeyAsync(context);
if (apiKeyResult.Status != ResultStatus.Success)
{
context.Response.StatusCode = 401;
await context.Response.WriteAsync("Unauthorized: Invalid API key");
return;
}
// Rate limiting
var rateLimitResult = await _rateLimiter.CheckRateLimitAsync(context);
if (!rateLimitResult.IsAllowed)
{
context.Response.StatusCode = 429;
context.Response.Headers.Add("Retry-After", rateLimitResult.RetryAfter.ToString());
await context.Response.WriteAsync("Rate limit exceeded");
return;
}
// Request size limiting
if (context.Request.ContentLength > 10_000_000) // 10MB limit
{
context.Response.StatusCode = 413;
await context.Response.WriteAsync("Request too large");
return;
}
// Add security headers
AddSecurityHeaders(context);
await _next(context);
}
private void AddSecurityHeaders(HttpContext context)
{
context.Response.Headers.Add("X-Content-Type-Options", "nosniff");
context.Response.Headers.Add("X-Frame-Options", "DENY");
context.Response.Headers.Add("X-XSS-Protection", "1; mode=block");
context.Response.Headers.Add("Strict-Transport-Security", "max-age=31536000; includeSubDomains");
context.Response.Headers.Add("Content-Security-Policy", "default-src 'self'");
}
}
```
## Security Best Practices and Guidelines
### **1. Input Sanitization and Validation**
- **All user inputs are validated and sanitized** before processing
- **SQL injection prevention** through parameterized queries and ORM usage
- **XSS protection** through output encoding and Content Security Policy
- **Command injection prevention** through input validation and sanitization
### **2. Authentication Security**
- **Multi-factor authentication** support for high-privilege accounts
- **Account lockout policies** to prevent brute force attacks
- **Password complexity requirements** with secure hashing algorithms
- **Session management** with secure tokens and proper expiration
### **3. Authorization Security**
- **Principle of least privilege** - users only get necessary permissions
- **Role-based access control** with granular permission management
- **Feature flags** for controlling access to application features
- **Regular permission audits** and access reviews
### **4. Data Protection Security**
- **Encryption at rest** for sensitive data using industry-standard algorithms
- **Encryption in transit** using TLS 1.2+ for all communications
- **Key management** with secure key storage and rotation policies
- **Data classification** and appropriate protection levels
### **5. Monitoring and Incident Response**
- **Security event logging** with centralized log management
- **Real-time threat detection** and automated response
- **Incident response procedures** with defined escalation paths
- **Regular security assessments** and penetration testing
## Conclusion
The Centron application implements comprehensive security patterns that provide:
- **Defense in Depth**: Multiple security layers protect against various threat vectors
- **Authentication Flexibility**: Support for multiple authentication mechanisms
- **Granular Authorization**: Fine-grained permission control at feature and data levels
- **Data Protection**: Strong encryption and data protection compliance (GDPR)
- **Audit Trail**: Complete logging of security events and data access
- **Secure Communication**: Encrypted communication channels and API security
- **Compliance**: Built-in support for regulatory compliance requirements
These security patterns ensure the application meets enterprise security standards while maintaining usability and performance.