Skip to content

Security Hardening Guide

Version: 1.0 Last Updated: 2026-01-18


Overview

This guide provides comprehensive security hardening recommendations for Cesivi Server in production environments. It covers authentication, network security, data protection, and operational security practices.

Related Documentation: - SECURITY_BEST_PRACTICES.md - General security best practices - SECURITY_DEPLOYMENT_CHECKLIST.md - Security deployment checklist - PRODUCTION_DEPLOYMENT_CHECKLIST.md - Production deployment guide


Table of Contents

  1. Authentication Security
  2. Transport Security (HTTPS/TLS)
  3. API Security
  4. Database Security
  5. Network Security
  6. Security Headers
  7. Secret Management
  8. Logging and Auditing
  9. Security Monitoring
  10. Hardening Checklist

Authentication Security

1.1: Disable Basic Authentication in Production

Risk: Basic authentication sends credentials in Base64 (easily decoded). Vulnerable to credential theft over unencrypted connections.

Recommendation: Disable Basic authentication in production environments.

Configuration:

{
  "Cesivi": {
    "Authentication": {
      "EnableBasicAuth": false,
      "EnableNtlm": true,
      "EnableBearer": true
    }
  }
}

Alternative: Use Windows Authentication (NTLM/Kerberos) or Bearer tokens with OAuth2/OIDC.

1.2: Implement Strong Password Policies

Requirements: - Minimum 12 characters - Mix of uppercase, lowercase, numbers, symbols - No dictionary words or common patterns - Password expiration every 90 days - Password history (prevent reuse of last 5 passwords)

Implementation:

// Add to authentication middleware
services.Configure<PasswordPolicy>(options =>
{
    options.MinimumLength = 12;
    options.RequireUppercase = true;
    options.RequireLowercase = true;
    options.RequireDigit = true;
    options.RequireSymbol = true;
    options.PasswordExpirationDays = 90;
    options.PasswordHistoryCount = 5;
});

1.3: Enable Multi-Factor Authentication (MFA)

Recommendation: Require MFA for administrative accounts and sensitive operations.

Integration Options: - Azure AD (supports MFA out of the box) - TOTP-based (Google Authenticator, Microsoft Authenticator) - SMS-based (less secure, use as fallback) - Hardware tokens (YubiKey, etc.)

Configuration Example:

{
  "Cesivi": {
    "Authentication": {
      "MFA": {
        "Enabled": true,
        "RequireForAdmins": true,
        "RequireForAll": false,
        "Provider": "AzureAD"
      }
    }
  }
}

1.4: Implement Account Lockout Policy

Protection: Prevents brute-force attacks on user accounts.

Recommendation: - Lock account after 5 failed login attempts - Lockout duration: 15-30 minutes - Alert admins on repeated lockouts

Configuration:

{
  "Cesivi": {
    "Authentication": {
      "AccountLockout": {
        "Enabled": true,
        "MaxFailedAttempts": 5,
        "LockoutDurationMinutes": 30,
        "AlertOnLockout": true
      }
    }
  }
}

1.5: API Key Rotation

Best Practice: Rotate API keys every 90 days or immediately after potential compromise.

Implementation: 1. Generate new API key 2. Distribute to clients with 30-day migration window 3. Monitor usage of old key 4. Revoke old key after migration complete

Example Rotation Script:

# Generate new API key
$newKey = New-Guid
$expirationDate = (Get-Date).AddDays(30)

# Update database
Invoke-SqlCmd -Query @"
UPDATE ApiKeys
SET IsActive = 0,
    ExpirationDate = '$expirationDate',
    RevokedDate = NULL
WHERE KeyValue = '$oldKey';

INSERT INTO ApiKeys (KeyValue, IsActive, CreatedDate, ExpirationDate)
VALUES ('$newKey', 1, GETDATE(), NULL);
"@

# Notify clients
Send-MailMessage -To $clients -Subject "API Key Rotation Required" `
    -Body "Your API key will expire on $expirationDate. New key: $newKey"


Transport Security (HTTPS/TLS)

2.1: Enforce HTTPS

Requirement: All production traffic MUST use HTTPS (TLS 1.2 or higher).

Configuration:

{
  "Cesivi": {
    "Security": {
      "RequireHttps": true,
      "HttpsPort": 443,
      "RedirectHttpToHttps": true
    }
  }
}

ASP.NET Core Middleware:

// In Program.cs or Startup.cs
app.UseHttpsRedirection();
app.UseHsts(); // HTTP Strict Transport Security

// Kestrel configuration
builder.WebHost.ConfigureKestrel(options =>
{
    options.AddServerHeader = false; // Hide server version
    options.Limits.MaxRequestBodySize = 52428800; // 50 MB max
});

2.2: TLS Configuration

Minimum TLS Version: TLS 1.2 (TLS 1.3 preferred if supported by clients)

Cipher Suites: Use only strong, modern cipher suites.

Recommended Cipher Suites: - TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 - TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 - TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256

Disable Weak Ciphers: - No SSL v2/v3 - No TLS 1.0/1.1 - No RC4, MD5, DES, 3DES

Windows Server Configuration:

# Disable TLS 1.0 and 1.1
New-Item 'HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.0\Server' -Force
New-ItemProperty -Path 'HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.0\Server' -Name 'Enabled' -Value 0 -PropertyType 'DWord'

New-Item 'HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.1\Server' -Force
New-ItemProperty -Path 'HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.1\Server' -Name 'Enabled' -Value 0 -PropertyType 'DWord'

# Enable TLS 1.2 and 1.3
New-Item 'HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.2\Server' -Force
New-ItemProperty -Path 'HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.2\Server' -Name 'Enabled' -Value 1 -PropertyType 'DWord'

# Restart required
Restart-Computer -Force

2.3: SSL Certificate Management

Best Practices: - Use certificates from trusted CA (Let's Encrypt, DigiCert, etc.) - Enable automatic renewal (Let's Encrypt: 60-day renewal) - Use wildcard certificates for multiple subdomains - Store private keys securely (hardware security module preferred)

Certificate Validation:

# Verify certificate
openssl s_client -connect cesivi.example.com:443 -showcerts

# Check expiration
openssl x509 -in cert.pem -noout -enddate

# Test SSL configuration
curl -I https://cesivi.example.com


API Security

3.1: Rate Limiting

Protection: Prevent API abuse and DDoS attacks.

Recommendation: - 100 requests/minute per IP for anonymous users - 1000 requests/minute per IP for authenticated users - 10,000 requests/minute per IP for trusted API clients

Implementation:

// Add to Program.cs
builder.Services.AddRateLimiter(options =>
{
    options.AddFixedWindowLimiter("api", config =>
    {
        config.Window = TimeSpan.FromMinutes(1);
        config.PermitLimit = 100;
        config.QueueLimit = 10;
    });
});

app.UseRateLimiter();

3.2: Input Validation

Requirement: Validate all user input to prevent injection attacks.

Common Attacks: - SQL Injection - Cross-Site Scripting (XSS) - XML External Entity (XXE) - LDAP Injection - Command Injection

Validation Rules:

// Example: List title validation
public class ListTitleValidator
{
    private static readonly Regex ValidTitlePattern = new Regex(@"^[a-zA-Z0-9\s\-_]{1,255}$");

    public static bool IsValid(string title)
    {
        if (string.IsNullOrWhiteSpace(title)) return false;
        if (title.Length > 255) return false;
        if (!ValidTitlePattern.IsMatch(title)) return false;

        // Reject known malicious patterns
        var blacklist = new[] { "<script", "javascript:", "onerror=", "../../" };
        return !blacklist.Any(pattern => title.Contains(pattern, StringComparison.OrdinalIgnoreCase));
    }
}

3.3: Output Encoding

Requirement: Encode all output to prevent XSS attacks.

Encoding Types: - HTML encoding: &lt;, &gt;, &amp;, &quot; - JavaScript encoding: \x3c, \x3e, \x27, \x22 - URL encoding: %3C, %3E, %27, %22

ASP.NET Core Automatic Encoding:

// Razor views automatically HTML-encode
@Model.UserInput  // Safe by default

// Explicit encoding
@Html.Encode(Model.UserInput)

3.4: CORS Configuration

Requirement: Restrict Cross-Origin Resource Sharing to trusted domains only.

Production Configuration:

{
  "Cesivi": {
    "Cors": {
      "AllowedOrigins": [
        "https://intranet.example.com",
        "https://portal.example.com"
      ],
      "AllowedMethods": ["GET", "POST", "PUT", "DELETE"],
      "AllowedHeaders": ["Authorization", "Content-Type", "Accept"],
      "AllowCredentials": true,
      "MaxAge": 3600
    }
  }
}

DO NOT use wildcards in production:

{
  "AllowedOrigins": ["*"]  // ❌ INSECURE - allows any origin
}


Database Security

4.1: Connection String Encryption

Requirement: Never store database credentials in plain text.

Options: 1. Environment Variables (basic) 2. Azure Key Vault (recommended for Azure deployments) 3. Windows DPAPI (Windows servers) 4. HashiCorp Vault (multi-cloud)

Using Environment Variables:

# Set environment variable
export CESIVI_DB_CONNECTION="Server=localhost;Database=CesiviDB;User=cesivi_app;Password=STRONG_PASSWORD"

# Reference in appsettings
{
  "ConnectionStrings": {
    "DefaultConnection": "${CESIVI_DB_CONNECTION}"
  }
}

Using Azure Key Vault:

// Program.cs
builder.Configuration.AddAzureKeyVault(
    new Uri("https://cesivi-keyvault.vault.azure.net/"),
    new DefaultAzureCredential()
);

// appsettings.json
{
  "ConnectionStrings": {
    "DefaultConnection": "#{ConnectionString}#"  // Retrieved from Key Vault
  }
}

4.2: Principle of Least Privilege

Database User Permissions:

Application User (cesivi_app): - SELECT, INSERT, UPDATE, DELETE on application tables only - EXECUTE on stored procedures - NO DROP, CREATE, ALTER permissions - NO sa or db_owner role

Migration User (cesivi_migration): - CREATE, ALTER, DROP on application schema - Used only during deployment - Credentials not accessible to application

SQL Example:

-- Create application user with limited permissions
CREATE USER cesivi_app WITH PASSWORD = 'STRONG_PASSWORD';

-- Grant only required permissions
GRANT SELECT, INSERT, UPDATE, DELETE ON SCHEMA::cesivi TO cesivi_app;
GRANT EXECUTE ON SCHEMA::cesivi TO cesivi_app;

-- Deny dangerous permissions
DENY CREATE TABLE TO cesivi_app;
DENY DROP TO cesivi_app;
DENY ALTER TO cesivi_app;

4.3: Database Encryption

Recommendation: Enable encryption at rest and in transit.

SQL Server TDE (Transparent Data Encryption):

-- Enable TDE
USE master;
CREATE MASTER KEY ENCRYPTION BY PASSWORD = 'STRONG_PASSWORD';

CREATE CERTIFICATE TDECert WITH SUBJECT = 'TDE Certificate';

USE CesiviDB;
CREATE DATABASE ENCRYPTION KEY
WITH ALGORITHM = AES_256
ENCRYPTION BY SERVER CERTIFICATE TDECert;

ALTER DATABASE CesiviDB SET ENCRYPTION ON;

Connection Encryption:

{
  "ConnectionStrings": {
    "DefaultConnection": "Server=localhost;Database=CesiviDB;Encrypt=true;TrustServerCertificate=false;"
  }
}


Network Security

5.1: Firewall Rules

Principle: Deny all traffic by default, allow only required traffic.

Inbound Rules:

# Allow HTTPS (443)
iptables -A INPUT -p tcp --dport 443 -j ACCEPT

# Allow HTTP (80) for redirect to HTTPS
iptables -A INPUT -p tcp --dport 80 -j ACCEPT

# Allow database (only from application server)
iptables -A INPUT -p tcp -s 10.0.1.5 --dport 5432 -j ACCEPT

# Allow SSH (admin only, non-standard port)
iptables -A INPUT -p tcp -s 203.0.113.0/24 --dport 2222 -j ACCEPT

# Deny all other traffic
iptables -P INPUT DROP
iptables -P FORWARD DROP
iptables -P OUTPUT ACCEPT

Windows Firewall:

# Allow HTTPS
New-NetFirewallRule -DisplayName "Cesivi HTTPS" -Direction Inbound -Protocol TCP -LocalPort 443 -Action Allow

# Allow HTTP for redirect
New-NetFirewallRule -DisplayName "Cesivi HTTP" -Direction Inbound -Protocol TCP -LocalPort 80 -Action Allow

# Block all other inbound by default
Set-NetFirewallProfile -DefaultInboundAction Block

5.2: IP Whitelisting

Recommendation: Restrict administrative endpoints to known IP ranges.

Configuration:

{
  "Cesivi": {
    "Security": {
      "IpWhitelist": {
        "Enabled": true,
        "AdminEndpoints": [
          "/_diagnostics/*",
          "/_health/*",
          "/admin/*"
        ],
        "AllowedIpRanges": [
          "10.0.0.0/8",       // Internal network
          "203.0.113.0/24"    // Admin VPN
        ]
      }
    }
  }
}

Middleware Implementation:

app.Use(async (context, next) =>
{
    var path = context.Request.Path.Value;
    var isAdminEndpoint = adminEndpoints.Any(pattern => path.StartsWith(pattern));

    if (isAdminEndpoint)
    {
        var remoteIp = context.Connection.RemoteIpAddress;
        if (!IsIpAllowed(remoteIp, allowedRanges))
        {
            context.Response.StatusCode = 403;
            await context.Response.WriteAsync("Access denied");
            return;
        }
    }

    await next();
});

5.3: Reverse Proxy Configuration

Recommendation: Use reverse proxy (nginx, IIS ARR) for additional security layer.

Nginx Configuration:

server {
    listen 443 ssl http2;
    server_name cesivi.example.com;

    # SSL configuration
    ssl_certificate /etc/ssl/certs/cesivi.crt;
    ssl_certificate_key /etc/ssl/private/cesivi.key;
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers HIGH:!aNULL:!MD5;

    # Security headers
    add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
    add_header X-Frame-Options "SAMEORIGIN" always;
    add_header X-Content-Type-Options "nosniff" always;
    add_header X-XSS-Protection "1; mode=block" always;

    # Rate limiting
    limit_req_zone $binary_remote_addr zone=api:10m rate=100r/m;
    limit_req zone=api burst=20 nodelay;

    # Proxy to application
    location / {
        proxy_pass http://localhost:5000;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;

        # Timeouts
        proxy_connect_timeout 60s;
        proxy_send_timeout 60s;
        proxy_read_timeout 60s;
    }

    # Block malicious requests
    location ~* /(wp-admin|phpmyadmin|admin\.php) {
        return 404;
    }
}


Security Headers

6.1: HTTP Strict Transport Security (HSTS)

Purpose: Force browsers to use HTTPS for all requests.

Configuration:

app.Use(async (context, next) =>
{
    context.Response.Headers.Add("Strict-Transport-Security", "max-age=31536000; includeSubDomains; preload");
    await next();
});

6.2: Content Security Policy (CSP)

Purpose: Prevent XSS attacks by controlling resource loading.

Configuration:

app.Use(async (context, next) =>
{
    context.Response.Headers.Add("Content-Security-Policy",
        "default-src 'self'; " +
        "script-src 'self' 'unsafe-inline'; " +
        "style-src 'self' 'unsafe-inline'; " +
        "img-src 'self' data: https:; " +
        "font-src 'self' data:; " +
        "connect-src 'self'; " +
        "frame-ancestors 'none';");
    await next();
});

6.3: X-Frame-Options

Purpose: Prevent clickjacking attacks.

Configuration:

app.Use(async (context, next) =>
{
    context.Response.Headers.Add("X-Frame-Options", "SAMEORIGIN");
    await next();
});

6.4: X-Content-Type-Options

Purpose: Prevent MIME-type sniffing.

Configuration:

app.Use(async (context, next) =>
{
    context.Response.Headers.Add("X-Content-Type-Options", "nosniff");
    await next();
});

6.5: X-XSS-Protection

Purpose: Enable browser XSS filters (legacy, CSP preferred).

Configuration:

app.Use(async (context, next) =>
{
    context.Response.Headers.Add("X-XSS-Protection", "1; mode=block");
    await next();
});


Secret Management

7.1: Never Commit Secrets to Git

Common Mistakes: - Hardcoded passwords in code - Connection strings in appsettings.json - API keys in configuration files - Private keys in repository

Prevention:

# Add to .gitignore
appsettings.Production.json
appsettings.*.json
*.key
*.pfx
secrets/

7.2: Use Secret Management Tools

Options: 1. Azure Key Vault (Azure cloud) 2. AWS Secrets Manager (AWS cloud) 3. HashiCorp Vault (multi-cloud, on-prem) 4. ASP.NET Core Secret Manager (development only)

Development (Secret Manager):

# Initialize secrets
dotnet user-secrets init --project Cesivi.Server

# Set secret
dotnet user-secrets set "ConnectionStrings:DefaultConnection" "Server=localhost;Database=CesiviDB;User=sa;Password=DevPassword123"

# Secrets stored in user profile, not in repository

7.3: Rotate Secrets Regularly

Rotation Schedule: - Database passwords: Every 90 days - API keys: Every 90 days - SSL certificates: Every 365 days (automate with Let's Encrypt) - Service account passwords: Every 180 days


Logging and Auditing

8.1: Security Event Logging

Events to Log: - Failed login attempts (with IP, username, timestamp) - Successful logins (with IP, username, timestamp) - Permission changes (who changed, what changed, when) - API key usage (key ID, endpoint, timestamp) - Administrative actions (user creation, deletion, config changes) - Database schema changes - Suspicious activity (SQL injection attempts, XSS attempts)

Example:

_logger.LogWarning("Failed login attempt: User={Username}, IP={IpAddress}, Timestamp={Timestamp}",
    username, remoteIp, DateTime.UtcNow);

_logger.LogInformation("Successful login: User={Username}, IP={IpAddress}, Timestamp={Timestamp}",
    username, remoteIp, DateTime.UtcNow);

_logger.LogWarning("Suspicious activity detected: Type={AttackType}, IP={IpAddress}, Payload={Payload}",
    "SQLInjection", remoteIp, sanitizedPayload);

8.2: Log Retention

Recommendation: - Security logs: 1 year minimum - Audit logs: 7 years (compliance requirements) - Application logs: 90 days - Debug logs: 7 days

Storage: - Use centralized logging (ELK, Splunk, Azure Monitor) - Encrypt logs at rest - Restrict access to logs (need-to-know basis)

8.3: Log Sanitization

Requirement: Never log sensitive data (passwords, credit cards, PII).

Example:

// ❌ BAD: Logs password
_logger.LogInformation("User login: {Username}, Password: {Password}", username, password);

// ✅ GOOD: Sanitized
_logger.LogInformation("User login: {Username}", username);

// ✅ GOOD: Redacted sensitive fields
var sanitized = new
{
    request.Username,
    Password = "***REDACTED***",
    request.IpAddress
};
_logger.LogInformation("Login request: {Request}", sanitized);


Security Monitoring

9.1: Intrusion Detection

Recommendation: Deploy intrusion detection system (IDS) to monitor network traffic.

Tools: - Snort (open-source) - Suricata (open-source) - Azure Sentinel (cloud) - AWS GuardDuty (cloud)

9.2: Security Metrics

Monitor: - Failed login attempts (alert if > 10/minute from single IP) - API error rate (alert if > 5%) - Unusual traffic patterns (alert if traffic spikes > 200%) - Certificate expiration (alert 30 days before expiration) - Database connection failures (alert if > 5/minute)

Alerting Example:

# Prometheus alerting rule
groups:
  - name: security
    rules:
      - alert: HighFailedLoginRate
        expr: rate(failed_logins_total[5m]) > 10
        for: 5m
        annotations:
          summary: "High failed login rate detected"
          description: "{{ $value }} failed logins/second from IP {{ $labels.ip }}"

9.3: Vulnerability Scanning

Recommendation: Run vulnerability scans monthly (or after each deployment).

Tools: - OWASP ZAP (web app scanner) - Nessus (network scanner) - Qualys (cloud scanner) - Snyk (dependency scanner)

CI/CD Integration:

# GitHub Actions example
- name: Security Scan
  uses: zaproxy/action-full-scan@v0.4.0
  with:
    target: 'https://cesivi.example.com'


Hardening Checklist

Authentication & Authorization

  • [ ] Basic authentication disabled in production
  • [ ] Strong password policy enforced (12+ chars, complexity)
  • [ ] Multi-factor authentication enabled for admins
  • [ ] Account lockout policy configured (5 failed attempts)
  • [ ] API keys rotated every 90 days
  • [ ] Session timeout configured (30 minutes idle)

Transport Security

  • [ ] HTTPS enforced (no HTTP traffic)
  • [ ] TLS 1.2+ only (TLS 1.0/1.1 disabled)
  • [ ] SSL certificate from trusted CA
  • [ ] SSL certificate auto-renewal configured
  • [ ] Strong cipher suites configured

API Security

  • [ ] Rate limiting enabled (100 req/min default)
  • [ ] Input validation on all endpoints
  • [ ] Output encoding to prevent XSS
  • [ ] CORS restricted to trusted domains only
  • [ ] API versioning implemented

Database Security

  • [ ] Connection strings encrypted (Key Vault, etc.)
  • [ ] Database user has minimal permissions (no sa/db_owner)
  • [ ] Separate migration user (not used by app)
  • [ ] Database encryption enabled (TDE)
  • [ ] Connection encryption enabled (Encrypt=true)

Network Security

  • [ ] Firewall rules configured (deny by default)
  • [ ] IP whitelisting for admin endpoints
  • [ ] Reverse proxy configured (nginx/IIS ARR)
  • [ ] DDoS protection enabled (Cloudflare, Azure DDoS)

Security Headers

  • [ ] HSTS enabled (max-age=31536000)
  • [ ] Content-Security-Policy configured
  • [ ] X-Frame-Options set to SAMEORIGIN
  • [ ] X-Content-Type-Options set to nosniff
  • [ ] X-XSS-Protection enabled

Secret Management

  • [ ] No secrets committed to Git
  • [ ] Secrets stored in Key Vault/Secrets Manager
  • [ ] Secret rotation schedule defined
  • [ ] Secrets not logged or exposed

Logging & Monitoring

  • [ ] Security events logged (logins, permission changes)
  • [ ] Audit logs retained (1+ year)
  • [ ] Sensitive data not logged (passwords, PII)
  • [ ] Centralized logging configured (ELK, Splunk)
  • [ ] Alerting configured for security events

Operational Security

  • [ ] Intrusion detection system deployed
  • [ ] Vulnerability scanning monthly
  • [ ] Penetration testing annually
  • [ ] Security incident response plan documented
  • [ ] Security training for development team

Last Updated: 2026-01-18 Version: 1.0 For Support: See README.md