Introduction
In 2025, data breaches cost organizations an average of $4.88 million per incident, with 83% of breaches involving web applications. As cybersecurity threats evolve, implementing robust encryption standards like TLS 1.3 and AES-256 has become non-negotiable for modern web applications.
This comprehensive guide walks you through implementing enterprise-grade security across a complete technology stack: React frontend, .NET Core microservices, and PostgreSQL database. You'll learn not just the "what" but the "how" with production-ready code examples.
What You'll Learn
How to configure TLS 1.3 for maximum security and performance
Implementing AES-256 encryption across your entire application stack
Best practices for key management and secure communication
Real-world code examples and configuration templates
Performance optimization techniques for encrypted applications
Understanding Modern Encryption Standards
TLS 1.3: The Security Revolution
TLS 1.3, ratified in 2018, represents the most significant upgrade to transport layer security in over a decade. Here's why it matters:
Key Improvements:
Reduced Handshake Latency: 1-RTT (Round Trip Time) vs 2-RTT in TLS 1.2
Perfect Forward Secrecy: Always enabled, not optional
Simplified Cipher Suites: Removed weak and deprecated algorithms
Enhanced Privacy: Encrypted handshake messages
Performance Benefits:
TLS 1.2 Handshake: ~100ms
TLS 1.3 Handshake: ~50ms
Result: 50% faster connection establishment
AES-256: Unbreakable Encryption
Advanced Encryption Standard with 256-bit keys is the gold standard for symmetric encryption:
Key Length: 256 bits (2^256 possible combinations)
Block Size: 128 bits
Rounds: 14 encryption rounds
Security Level: Approved for TOP SECRET information by NSA
Frontend Security: React Implementation
Setting Up HTTPS and TLS 1.3
First, let's configure your React development environment for secure communication:
package.json Configuration:
{
"name": "secure-react-app",
"scripts": {
"start": "HTTPS=true SSL_CRT_FILE=./certs/localhost.crt SSL_KEY_FILE=./certs/localhost.key react-scripts start",
"build": "react-scripts build"
},
"dependencies": {
"react": "^18.2.0",
"axios": "^1.4.0",
"crypto-js": "^4.1.1"
}
}
Environment Configuration (.env):
HTTPS=true
REACT_APP_API_BASE_URL=https://api.yourapp.com
REACT_APP_ENCRYPTION_ENABLED=true
SSL_CRT_FILE=./certs/localhost.crt
SSL_KEY_FILE=./certs/localhost.key
Implementing Client-Side Encryption
Create a secure encryption service for sensitive data:
services/EncryptionService.js:
import CryptoJS from 'crypto-js';
class EncryptionService {
constructor() {
this.algorithm = 'AES-256-GCM';
this.keySize = 256;
this.ivSize = 96; // 12 bytes for GCM
this.tagSize = 128; // 16 bytes
}
// Generate a secure encryption key
generateKey() {
return CryptoJS.lib.WordArray.random(this.keySize / 8).toString();
}
// Encrypt data using AES-256-GCM
encrypt(plaintext, key) {
try {
const iv = CryptoJS.lib.WordArray.random(this.ivSize / 8);
const encrypted = CryptoJS.AES.encrypt(plaintext, key, {
iv: iv,
mode: CryptoJS.mode.GCM,
padding: CryptoJS.pad.NoPadding
});
return {
ciphertext: encrypted.ciphertext.toString(),
iv: iv.toString(),
tag: encrypted.tag?.toString() || ''
};
} catch (error) {
console.error('Encryption failed:', error);
throw new Error('Data encryption failed');
}
}
// Decrypt data using AES-256-GCM
decrypt(encryptedData, key) {
try {
const decrypted = CryptoJS.AES.decrypt(
{
ciphertext: CryptoJS.enc.Hex.parse(encryptedData.ciphertext),
tag: CryptoJS.enc.Hex.parse(encryptedData.tag)
},
key,
{
iv: CryptoJS.enc.Hex.parse(encryptedData.iv),
mode: CryptoJS.mode.GCM,
padding: CryptoJS.pad.NoPadding
}
);
return decrypted.toString(CryptoJS.enc.Utf8);
} catch (error) {
console.error('Decryption failed:', error);
throw new Error('Data decryption failed');
}
}
}
export default new EncryptionService();
Secure API Communication
Implement secure HTTP client with proper TLS configuration:
services/ApiService.js:
import axios from 'axios';
import EncryptionService from './EncryptionService';
class ApiService {
constructor() {
this.client = axios.create({
baseURL: process.env.REACT_APP_API_BASE_URL,
timeout: 30000,
headers: {
'Content-Type': 'application/json',
'X-Requested-With': 'XMLHttpRequest',
},
});
this.setupInterceptors();
}
setupInterceptors() {
// Request interceptor for authentication and encryption
this.client.interceptors.request.use(
(config) => {
// Add authentication token
const token = this.getAuthToken();
if (token) {
config.headers.Authorization = `Bearer ${token}`;
}
// Encrypt sensitive data
if (config.data && this.shouldEncrypt(config.url)) {
const encryptionKey = this.getEncryptionKey();
config.data = {
encryptedData: EncryptionService.encrypt(
JSON.stringify(config.data),
encryptionKey
),
encrypted: true
};
}
return config;
},
(error) => Promise.reject(error)
);
// Response interceptor for decryption and error handling
this.client.interceptors.response.use(
(response) => {
// Decrypt response if needed
if (response.data?.encrypted) {
const encryptionKey = this.getEncryptionKey();
const decryptedData = EncryptionService.decrypt(
response.data.encryptedData,
encryptionKey
);
response.data = JSON.parse(decryptedData);
}
return response;
},
(error) => {
this.handleApiError(error);
return Promise.reject(error);
}
);
}
getAuthToken() {
return sessionStorage.getItem('authToken'); // Avoid localStorage for tokens
}
getEncryptionKey() {
return sessionStorage.getItem('encryptionKey');
}
shouldEncrypt(url) {
const encryptedEndpoints = ['/api/users', '/api/payments', '/api/sensitive-data'];
return encryptedEndpoints.some(endpoint => url.includes(endpoint));
}
handleApiError(error) {
if (error.response?.status === 401) {
// Handle unauthorized access
this.logout();
}
console.error('API Error:', error.response?.data || error.message);
}
logout() {
sessionStorage.clear();
window.location.href = '/login';
}
}
export default new ApiService();
Secure Component Implementation
Example of a secure form component with encryption:
components/SecureForm.jsx:
import React, { useState } from 'react';
import ApiService from '../services/ApiService';
import EncryptionService from '../services/EncryptionService';
const SecureForm = () => {
const [formData, setFormData] = useState({
email: '',
creditCard: '',
ssn: ''
});
const [loading, setLoading] = useState(false);
const [errors, setErrors] = useState({});
const handleInputChange = (e) => {
const { name, value } = e.target;
setFormData(prev => ({
...prev,
[name]: value
}));
// Clear error when user starts typing
if (errors[name]) {
setErrors(prev => ({
...prev,
[name]: ''
}));
}
};
const validateForm = () => {
const newErrors = {};
if (!formData.email.match(/^[^\s@]+@[^\s@]+\.[^\s@]+$/)) {
newErrors.email = 'Invalid email format';
}
if (!formData.creditCard.match(/^\d{16}$/)) {
newErrors.creditCard = 'Credit card must be 16 digits';
}
if (!formData.ssn.match(/^\d{3}-\d{2}-\d{4}$/)) {
newErrors.ssn = 'SSN must be in format XXX-XX-XXXX';
}
setErrors(newErrors);
return Object.keys(newErrors).length === 0;
};
const handleSubmit = async (e) => {
e.preventDefault();
if (!validateForm()) {
return;
}
setLoading(true);
try {
// Submit encrypted data
const response = await ApiService.client.post('/api/users/secure-data', {
email: formData.email,
creditCard: formData.creditCard,
ssn: formData.ssn
});
console.log('Data submitted successfully:', response.data);
// Clear form
setFormData({
email: '',
creditCard: '',
ssn: ''
});
alert('Data submitted successfully!');
} catch (error) {
console.error('Submission failed:', error);
alert('Submission failed. Please try again.');
} finally {
setLoading(false);
}
};
return (
<div className="secure-form-container">
<h2>Secure Data Entry Form</h2>
<form onSubmit={handleSubmit} className="secure-form">
<div className="form-group">
<label htmlFor="email">Email:</label>
<input
type="email"
id="email"
name="email"
value={formData.email}
onChange={handleInputChange}
required
autoComplete="off"
/>
{errors.email && <span className="error">{errors.email}</span>}
</div>
<div className="form-group">
<label htmlFor="creditCard">Credit Card:</label>
<input
type="password"
id="creditCard"
name="creditCard"
value={formData.creditCard}
onChange={handleInputChange}
placeholder="1234567890123456"
maxLength="16"
required
autoComplete="off"
/>
{errors.creditCard && <span className="error">{errors.creditCard}</span>}
</div>
<div className="form-group">
<label htmlFor="ssn">SSN:</label>
<input
type="password"
id="ssn"
name="ssn"
value={formData.ssn}
onChange={handleInputChange}
placeholder="123-45-6789"
maxLength="11"
required
autoComplete="off"
/>
{errors.ssn && <span className="error">{errors.ssn}</span>}
</div>
<button type="submit" disabled={loading} className="submit-button">
{loading ? 'Submitting...' : 'Submit Securely'}
</button>
</form>
</div>
);
};
export default SecureForm;
Backend Security: .NET Core Microservices
TLS 1.3 Configuration
Configure your ASP.NET Core application for TLS 1.3:
Program.cs:
using Microsoft.AspNetCore.Server.Kestrel.Core;
using Microsoft.AspNetCore.Server.Kestrel.Https;
using System.Security.Authentication;
using System.Security.Cryptography.X509Certificates;
var builder = WebApplication.CreateBuilder(args);
// Configure Kestrel for TLS 1.3
builder.WebHost.ConfigureKestrel(serverOptions =>
{
serverOptions.ConfigureHttpsDefaults(httpsOptions =>
{
httpsOptions.SslProtocols = SslProtocols.Tls13;
httpsOptions.ClientCertificateMode = ClientCertificateMode.NoCertificate;
httpsOptions.CheckCertificateRevocation = true;
// Load certificate from configuration
var certPath = builder.Configuration["Https:Certificate:Path"];
var certPassword = builder.Configuration["Https:Certificate:Password"];
if (!string.IsNullOrEmpty(certPath))
{
httpsOptions.ServerCertificate = new X509Certificate2(certPath, certPassword);
}
});
serverOptions.Limits.MaxConcurrentConnections = 100;
serverOptions.Limits.MaxConcurrentUpgradedConnections = 100;
serverOptions.Limits.MaxRequestBodySize = 10 * 1024 * 1024; // 10MB
});
// Add services
builder.Services.AddControllers();
builder.Services.AddHttpsRedirection(options =>
{
options.RedirectStatusCode = StatusCodes.Status308PermanentRedirect;
options.HttpsPort = 443;
});
// Add custom services
builder.Services.AddScoped<IEncryptionService, EncryptionService>();
builder.Services.AddScoped<IKeyManagementService, KeyManagementService>();
// Security headers middleware
builder.Services.AddHeaderSecurity();
var app = builder.Build();
// Configure pipeline
if (app.Environment.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseSecurityHeaders();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.MapControllers();
app.Run();
AES-256 Encryption Service
Implement a robust encryption service:
Services/EncryptionService.cs:
using System.Security.Cryptography;
using System.Text;
using System.Text.Json;
public interface IEncryptionService
{
Task<EncryptedData> EncryptAsync(string plaintext, string key);
Task<string> DecryptAsync(EncryptedData encryptedData, string key);
string GenerateKey();
}
public class EncryptedData
{
public string Ciphertext { get; set; } = string.Empty;
public string IV { get; set; } = string.Empty;
public string Tag { get; set; } = string.Empty;
}
public class EncryptionService : IEncryptionService
{
private const int KeySize = 256; // AES-256
private const int IVSize = 12; // 96 bits for GCM
private const int TagSize = 16; // 128 bits
public async Task<EncryptedData> EncryptAsync(string plaintext, string key)
{
if (string.IsNullOrEmpty(plaintext))
throw new ArgumentException("Plaintext cannot be null or empty", nameof(plaintext));
if (string.IsNullOrEmpty(key))
throw new ArgumentException("Key cannot be null or empty", nameof(key));
using var aes = new AesGcm(Convert.FromBase64String(key));
var plaintextBytes = Encoding.UTF8.GetBytes(plaintext);
var ciphertext = new byte[plaintextBytes.Length];
var iv = new byte[IVSize];
var tag = new byte[TagSize];
// Generate random IV
RandomNumberGenerator.Fill(iv);
// Encrypt
aes.Encrypt(iv, plaintextBytes, ciphertext, tag);
return new EncryptedData
{
Ciphertext = Convert.ToBase64String(ciphertext),
IV = Convert.ToBase64String(iv),
Tag = Convert.ToBase64String(tag)
};
}
public async Task<string> DecryptAsync(EncryptedData encryptedData, string key)
{
if (encryptedData == null)
throw new ArgumentNullException(nameof(encryptedData));
if (string.IsNullOrEmpty(key))
throw new ArgumentException("Key cannot be null or empty", nameof(key));
try
{
using var aes = new AesGcm(Convert.FromBase64String(key));
var ciphertext = Convert.FromBase64String(encryptedData.Ciphertext);
var iv = Convert.FromBase64String(encryptedData.IV);
var tag = Convert.FromBase64String(encryptedData.Tag);
var plaintext = new byte[ciphertext.Length];
// Decrypt
aes.Decrypt(iv, ciphertext, tag, plaintext);
return Encoding.UTF8.GetString(plaintext);
}
catch (Exception ex)
{
throw new CryptographicException("Decryption failed", ex);
}
}
public string GenerateKey()
{
var key = new byte[KeySize / 8]; // 32 bytes for AES-256
RandomNumberGenerator.Fill(key);
return Convert.ToBase64String(key);
}
}
Key Management Service
Implement secure key management:
Services/KeyManagementService.cs:
using Azure.Identity;
using Azure.Security.KeyVault.Secrets;
public interface IKeyManagementService
{
Task<string> GetEncryptionKeyAsync(string keyName);
Task StoreEncryptionKeyAsync(string keyName, string key);
Task<string> RotateKeyAsync(string keyName);
}
public class KeyManagementService : IKeyManagementService
{
private readonly SecretClient _secretClient;
private readonly IEncryptionService _encryptionService;
private readonly ILogger<KeyManagementService> _logger;
public KeyManagementService(
IConfiguration configuration,
IEncryptionService encryptionService,
ILogger<KeyManagementService> logger)
{
var keyVaultUrl = configuration["KeyVault:Url"];
_secretClient = new SecretClient(new Uri(keyVaultUrl), new DefaultAzureCredential());
_encryptionService = encryptionService;
_logger = logger;
}
public async Task<string> GetEncryptionKeyAsync(string keyName)
{
try
{
var secret = await _secretClient.GetSecretAsync(keyName);
return secret.Value.Value;
}
catch (Exception ex)
{
_logger.LogError(ex, "Failed to retrieve encryption key: {KeyName}", keyName);
throw;
}
}
public async Task StoreEncryptionKeyAsync(string keyName, string key)
{
try
{
await _secretClient.SetSecretAsync(keyName, key);
_logger.LogInformation("Encryption key stored successfully: {KeyName}", keyName);
}
catch (Exception ex)
{
_logger.LogError(ex, "Failed to store encryption key: {KeyName}", keyName);
throw;
}
}
public async Task<string> RotateKeyAsync(string keyName)
{
try
{
var newKey = _encryptionService.GenerateKey();
await StoreEncryptionKeyAsync($"{keyName}-new", newKey);
// In production, implement gradual key rotation
// Keep old key for decryption, use new key for encryption
_logger.LogInformation("Key rotated successfully: {KeyName}", keyName);
return newKey;
}
catch (Exception ex)
{
_logger.LogError(ex, "Failed to rotate key: {KeyName}", keyName);
throw;
}
}
}
Secure API Controller
Example controller with encryption middleware:
Controllers/SecureDataController.cs:
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
[ApiController]
[Route("api/[controller]")]
[Authorize]
public class SecureDataController : ControllerBase
{
private readonly IEncryptionService _encryptionService;
private readonly IKeyManagementService _keyManagement;
private readonly ILogger<SecureDataController> _logger;
public SecureDataController(
IEncryptionService encryptionService,
IKeyManagementService keyManagement,
ILogger<SecureDataController> logger)
{
_encryptionService = encryptionService;
_keyManagement = keyManagement;
_logger = logger;
}
[HttpPost("submit")]
public async Task<IActionResult> SubmitSecureData([FromBody] SecureDataRequest request)
{
try
{
// Validate request
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
// Get encryption key
var encryptionKey = await _keyManagement.GetEncryptionKeyAsync("user-data-key");
// Decrypt incoming data if encrypted
if (request.Encrypted)
{
var decryptedData = await _encryptionService.DecryptAsync(request.EncryptedData, encryptionKey);
request = JsonSerializer.Deserialize<SecureDataRequest>(decryptedData);
}
// Process the secure data
var result = await ProcessSecureData(request);
// Encrypt response if needed
var response = new SecureDataResponse
{
Success = true,
Message = "Data processed successfully",
Data = result
};
// Return encrypted response
var encryptedResponse = await _encryptionService.EncryptAsync(
JsonSerializer.Serialize(response),
encryptionKey
);
return Ok(new { EncryptedData = encryptedResponse, Encrypted = true });
}
catch (Exception ex)
{
_logger.LogError(ex, "Error processing secure data");
return StatusCode(500, new { Message = "Internal server error" });
}
}
private async Task<object> ProcessSecureData(SecureDataRequest request)
{
// Implement your business logic here
// This is where you would save to database, call other services, etc.
_logger.LogInformation("Processing secure data for user");
return new
{
ProcessedAt = DateTime.UtcNow,
Status = "Completed"
};
}
}
public class SecureDataRequest
{
public string Email { get; set; } = string.Empty;
public string CreditCard { get; set; } = string.Empty;
public string SSN { get; set; } = string.Empty;
public bool Encrypted { get; set; }
public EncryptedData? EncryptedData { get; set; }
}
public class SecureDataResponse
{
public bool Success { get; set; }
public string Message { get; set; } = string.Empty;
public object? Data { get; set; }
}
Database Security: PostgreSQL Encryption
PostgreSQL TLS Configuration
Configure PostgreSQL for secure connections:
postgresql.conf:
# Connection Settings
listen_addresses = '*'
port = 5432
max_connections = 200
# TLS/SSL Settings
ssl = on
ssl_cert_file = '/var/lib/postgresql/server.crt'
ssl_key_file = '/var/lib/postgresql/server.key'
ssl_ca_file = '/var/lib/postgresql/root.crt'
ssl_protocols = 'TLSv1.3'
ssl_ciphers = 'ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384'
ssl_prefer_server_ciphers = on
ssl_ecdh_curve = 'prime256v1'
# Security Settings
password_encryption = scram-sha-256
log_connections = on
log_disconnections = on
log_statement = 'all'
# Performance with Security
shared_preload_libraries = 'pg_stat_statements'
pg_hba.conf:
# TYPE DATABASE USER ADDRESS METHOD
local all postgres peer
hostssl all all 0.0.0.0/0 scram-sha-256
hostssl all all ::/0 scram-sha-256
Database Connection with TLS
Configure secure database connections in .NET Core:
appsettings.json:
{
"ConnectionStrings": {
"DefaultConnection": "Host=localhost;Port=5432;Database=secureapp;Username=appuser;Password=strongpassword;SSL Mode=Require;Trust Server Certificate=false;Include Error Detail=true;Timeout=30;Command Timeout=30"
},
"DatabaseSecurity": {
"EncryptSensitiveColumns": true,
"EncryptionKeyName": "db-encryption-key"
}
}
Column-Level Encryption
Implement transparent column encryption:
Models/EncryptedUser.cs:
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
public class User
{
[Key]
public int Id { get; set; }
[Required]
[EmailAddress]
public string Email { get; set; } = string.Empty;
[Encrypted]
public string? CreditCard { get; set; }
[Encrypted]
public string? SSN { get; set; }
public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
public DateTime UpdatedAt { get; set; } = DateTime.UtcNow;
}
[AttributeUsage(AttributeTargets.Property)]
public class EncryptedAttribute : Attribute
{
}
Data/EncryptionInterceptor.cs:
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Diagnostics;
using System.Reflection;
public class EncryptionInterceptor : SaveChangesInterceptor
{
private readonly IEncryptionService _encryptionService;
private readonly IKeyManagementService _keyManagement;
public EncryptionInterceptor(
IEncryptionService encryptionService,
IKeyManagementService keyManagement)
{
_encryptionService = encryptionService;
_keyManagement = keyManagement;
}
public override async ValueTask<InterceptionResult<int>> SavingChangesAsync(
DbContextEventData eventData,
InterceptionResult<int> result,
CancellationToken cancellationToken = default)
{
if (eventData.Context != null)
{
await EncryptEntities(eventData.Context);
}
return await base.SavingChangesAsync(eventData, result, cancellationToken);
}
private async Task EncryptEntities(DbContext context)
{
var encryptionKey = await _keyManagement.GetEncryptionKeyAsync("db-encryption-key");
var entities = context.ChangeTracker.Entries()
.Where(e => e.State == EntityState.Added || e.State == EntityState.Modified)
.ToList();
foreach (var entity in entities)
{
var properties = entity.Entity.GetType().GetProperties()
.Where(p => p.GetCustomAttribute<EncryptedAttribute>() != null);
foreach (var property in properties)
{
var value = property.GetValue(entity.Entity) as string;
if (!string.IsNullOrEmpty(value) && !IsAlreadyEncrypted(value))
{
var encryptedData = await _encryptionService.EncryptAsync(value, encryptionKey);
var encryptedValue = System.Text.Json.JsonSerializer.Serialize(encryptedData);
property.SetValue(entity.Entity, encryptedValue);
}
}
}
}
private bool IsAlreadyEncrypted(string value)
{
try
{
System.Text.Json.JsonSerializer.Deserialize<EncryptedData>(value);
return true;
}
catch
{
return false;
}
}
}
Data/ApplicationDbContext.cs:
using Microsoft.EntityFrameworkCore;
public class ApplicationDbContext : DbContext
{
private readonly IEncryptionService _encryptionService;
private readonly IKeyManagementService _keyManagement;
public ApplicationDbContext(
DbContextOptions<ApplicationDbContext> options,
IEncryptionService encryptionService,
IKeyManagementService keyManagement) : base(options)
{
_encryptionService = encryptionService;
_keyManagement = keyManagement;
}
public DbSet<User> Users { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.AddInterceptors(new EncryptionInterceptor(_encryptionService, _keyManagement));
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
// Configure entity mappings
modelBuilder.Entity<User>(entity =>
{