Skip to content

Security Guide ​

This guide covers security best practices, vulnerability reporting, and secure usage patterns for the ziegel library ecosystem.

Overview ​

Security is a fundamental concern in the ziegel framework. This guide provides comprehensive information about security considerations, best practices, and how to use ziegel libraries securely in your applications.

Security Features ​

Core Security Components ​

Input Validation ​

typescript
import { ArgumentException, ValidationException } from '@breadstone/ziegel-core';

export class UserValidator {
    static validateEmail(email: string): void {
        if (!email) {
            throw new ArgumentException('Email is required', 'email');
        }

        if (!RegexPatterns.email.test(email)) {
            throw new ValidationException('Invalid email format', 'email');
        }

        // Additional security checks
        if (email.length > 254) {
            throw new ValidationException('Email address too long', 'email');
        }
    }

    static validatePassword(password: string): void {
        const result = PasswordStrengthValidator.validate(password);

        if (!result.isStrong) {
            throw new ValidationException(
                `Password does not meet security requirements: ${result.weaknesses.join(', ')}`,
                'password'
            );
        }
    }
}

Secure String Handling ​

typescript
import { SecureString, CryptoHelper } from '@breadstone/ziegel-core';

// Secure password handling
export class AuthenticationService {
    async authenticateUser(username: string, password: SecureString): Promise<AuthResult> {
        try {
            // Hash password securely
            const hashedPassword = await CryptoHelper.hashPassword(password.value);

            // Compare with stored hash
            const user = await this.userRepository.findByUsername(username);
            if (!user || !await CryptoHelper.verifyPassword(password.value, user.passwordHash)) {
                throw new UnauthorizedException('Invalid credentials');
            }

            return new AuthResult(user, this.generateSecureToken(user));
        } finally {
            // Clear sensitive data from memory
            password.dispose();
        }
    }

    private generateSecureToken(user: User): string {
        return CryptoHelper.generateSecureToken({
            userId: user.id,
            roles: user.roles,
            expiresAt: DateTime.now().addHours(24)
        });
    }
}

Encryption and Hashing ​

typescript
import { SHA256, AES, RSA } from '@breadstone/ziegel-core';

export class EncryptionService {
    // Hash sensitive data
    static hashSensitiveData(data: string): string {
        const salt = CryptoHelper.generateSalt();
        return SHA256.hash(data + salt);
    }

    // Encrypt data at rest
    static encryptData(data: string, key: string): string {
        return AES.encrypt(data, key);
    }

    // Decrypt data
    static decryptData(encryptedData: string, key: string): string {
        return AES.decrypt(encryptedData, key);
    }

    // Generate secure keys
    static generateSecureKey(): string {
        return CryptoHelper.generateRandomBytes(32).toString('hex');
    }
}

HTTP Security ​

Secure HTTP Client Configuration ​

typescript
import { HttpClient, SecurityInterceptor } from '@breadstone/ziegel-platform-http';

// Configure secure HTTP client
const httpClient = new HttpClient({
    baseUrl: 'https://api.example.com',
    timeout: 30000,
    security: {
        // Enable HTTPS only
        allowInsecureConnections: false,

        // Certificate validation
        validateCertificates: true,

        // Security headers
        headers: {
            'X-Content-Type-Options': 'nosniff',
            'X-Frame-Options': 'DENY',
            'X-XSS-Protection': '1; mode=block',
            'Strict-Transport-Security': 'max-age=31536000; includeSubDomains'
        }
    }
});

// Add security interceptor
httpClient.addInterceptor(new SecurityInterceptor({
    sanitizeHeaders: true,
    logSecurityEvents: true,
    preventCSRF: true
}));

Authentication Interceptor ​

typescript
export class AuthenticationInterceptor implements HttpInterceptor {
    constructor(
        private readonly tokenProvider: ITokenProvider,
        private readonly logger: ILogger
    ) {}

    async request(request: HttpRequest): Promise<HttpRequest> {
        try {
            const token = await this.tokenProvider.getValidToken();

            if (token) {
                // Add authorization header
                request.headers['Authorization'] = `Bearer ${token}`;

                // Add security headers
                request.headers['X-Requested-With'] = 'XMLHttpRequest';
                request.headers['X-API-Version'] = '1.0';
            }

            return request;
        } catch (error) {
            this.logger.error('Authentication failed', error);
            throw new UnauthorizedException('Authentication required');
        }
    }

    async response(response: HttpResponse): Promise<HttpResponse> {
        // Check for security-related response headers
        if (response.status === 401) {
            await this.tokenProvider.clearToken();
            throw new UnauthorizedException('Token expired or invalid');
        }

        return response;
    }
}

Request Sanitization ​

typescript
export class RequestSanitizer {
    static sanitizeQueryParameters(params: Record<string, any>): Record<string, any> {
        const sanitized: Record<string, any> = {};

        for (const [key, value] of Object.entries(params)) {
            // Validate parameter names
            if (!this.isValidParameterName(key)) {
                throw new SecurityException(`Invalid parameter name: ${key}`);
            }

            // Sanitize values
            sanitized[key] = this.sanitizeValue(value);
        }

        return sanitized;
    }

    static sanitizeHeaders(headers: Record<string, string>): Record<string, string> {
        const sanitized: Record<string, string> = {};
        const allowedHeaders = [
            'content-type', 'authorization', 'accept', 'x-api-key'
        ];

        for (const [key, value] of Object.entries(headers)) {
            const lowerKey = key.toLowerCase();

            if (allowedHeaders.includes(lowerKey)) {
                sanitized[key] = this.sanitizeHeaderValue(value);
            }
        }

        return sanitized;
    }

    private static sanitizeValue(value: any): any {
        if (typeof value === 'string') {
            // Remove potentially dangerous characters
            return value.replace(/[<>\"']/g, '');
        }

        return value;
    }

    private static isValidParameterName(name: string): boolean {
        // Only allow alphanumeric characters and underscores
        return /^[a-zA-Z0-9_]+$/.test(name);
    }
}

Data Security ​

Secure Data Repository ​

typescript
export class SecureUserRepository implements IUserRepository {
    constructor(
        private readonly dataSource: IDataSource,
        private readonly encryptionService: IEncryptionService,
        private readonly auditLogger: IAuditLogger
    ) {}

    async getById(id: string): Promise<User> {
        // Validate input
        if (!Guid.isValid(id)) {
            throw new ArgumentException('Invalid user ID format', 'id');
        }

        try {
            const encryptedData = await this.dataSource.query(
                'SELECT * FROM users WHERE id = @id',
                { id }
            );

            if (!encryptedData) {
                throw new NotFoundException(`User ${id} not found`);
            }

            // Decrypt sensitive fields
            const user = this.decryptUserData(encryptedData);

            // Log access for audit trail
            await this.auditLogger.logDataAccess({
                operation: 'READ',
                table: 'users',
                recordId: id,
                timestamp: DateTime.now()
            });

            return user;
        } catch (error) {
            await this.auditLogger.logSecurityEvent({
                type: 'DATA_ACCESS_FAILED',
                details: `Failed to retrieve user ${id}`,
                error: error.message
            });
            throw error;
        }
    }

    async save(user: User): Promise<void> {
        // Validate user data
        this.validateUserData(user);

        // Encrypt sensitive fields
        const encryptedData = this.encryptUserData(user);

        try {
            await this.dataSource.execute(
                'INSERT OR UPDATE users SET email = @email, password_hash = @passwordHash WHERE id = @id',
                encryptedData
            );

            await this.auditLogger.logDataAccess({
                operation: 'WRITE',
                table: 'users',
                recordId: user.id,
                timestamp: DateTime.now()
            });
        } catch (error) {
            await this.auditLogger.logSecurityEvent({
                type: 'DATA_WRITE_FAILED',
                details: `Failed to save user ${user.id}`,
                error: error.message
            });
            throw error;
        }
    }

    private encryptUserData(user: User): any {
        return {
            id: user.id,
            email: this.encryptionService.encrypt(user.email),
            passwordHash: user.passwordHash, // Already hashed
            createdAt: user.createdAt
        };
    }

    private decryptUserData(encryptedData: any): User {
        return new User({
            id: encryptedData.id,
            email: this.encryptionService.decrypt(encryptedData.email),
            passwordHash: encryptedData.passwordHash,
            createdAt: encryptedData.createdAt
        });
    }
}

SQL Injection Prevention ​

typescript
export class SecureQueryBuilder {
    private parameters: Map<string, any> = new Map();
    private query: string = '';

    select(fields: string[]): this {
        // Validate field names to prevent injection
        const validFields = fields.filter(field => this.isValidFieldName(field));
        this.query += `SELECT ${validFields.join(', ')} `;
        return this;
    }

    where(field: string, operator: string, value: any): this {
        if (!this.isValidFieldName(field)) {
            throw new SecurityException(`Invalid field name: ${field}`);
        }

        if (!this.isValidOperator(operator)) {
            throw new SecurityException(`Invalid operator: ${operator}`);
        }

        const paramName = `param_${this.parameters.size}`;
        this.parameters.set(paramName, value);

        this.query += `WHERE ${field} ${operator} @${paramName} `;
        return this;
    }

    build(): { query: string; parameters: Record<string, any> } {
        return {
            query: this.query,
            parameters: Object.fromEntries(this.parameters)
        };
    }

    private isValidFieldName(field: string): boolean {
        // Only allow alphanumeric characters and underscores
        return /^[a-zA-Z0-9_]+$/.test(field);
    }

    private isValidOperator(operator: string): boolean {
        const allowedOperators = ['=', '!=', '<', '>', '<=', '>=', 'LIKE', 'IN'];
        return allowedOperators.includes(operator.toUpperCase());
    }
}

Configuration Security ​

Secure Configuration Management ​

typescript
import { ConfigurationManager, SecureConfigurationProvider } from '@breadstone/ziegel-platform-configuration';

export class SecurityConfiguration {
    private readonly config: ConfigurationManager;

    constructor() {
        this.config = new ConfigurationManager([
            new SecureConfigurationProvider({
                encryption: {
                    enabled: true,
                    algorithm: 'AES-256-GCM',
                    keySource: 'environment' // or 'vault', 'file'
                },
                validation: {
                    required: ['JWT_SECRET', 'DATABASE_URL', 'ENCRYPTION_KEY'],
                    format: {
                        'JWT_SECRET': /^[A-Za-z0-9+/=]{32,}$/,
                        'DATABASE_URL': /^[a-zA-Z]+:\/\/.+$/
                    }
                }
            })
        ]);
    }

    getJwtSecret(): string {
        const secret = this.config.getValue<string>('JWT_SECRET');
        if (!secret || secret.length < 32) {
            throw new SecurityException('JWT secret must be at least 32 characters');
        }
        return secret;
    }

    getDatabaseConnectionString(): string {
        const connectionString = this.config.getValue<string>('DATABASE_URL');

        // Ensure HTTPS/TLS is used
        if (!connectionString.startsWith('postgres://') && !connectionString.startsWith('postgresql://')) {
            throw new SecurityException('Database connection must use secure protocol');
        }

        return connectionString;
    }

    getEncryptionKey(): string {
        return this.config.getValue<string>('ENCRYPTION_KEY');
    }
}

Environment Variable Security ​

typescript
export class SecureEnvironment {
    private static readonly SENSITIVE_KEYS = [
        'JWT_SECRET', 'DATABASE_PASSWORD', 'API_KEY', 'ENCRYPTION_KEY'
    ];

    static getSecureValue(key: string): string {
        const value = process.env[key];

        if (!value) {
            throw new ConfigurationException(`Required environment variable ${key} not found`);
        }

        // Validate sensitive values
        if (this.SENSITIVE_KEYS.includes(key)) {
            this.validateSensitiveValue(key, value);
        }

        return value;
    }

    static validateEnvironment(): void {
        const missing: string[] = [];

        for (const key of this.SENSITIVE_KEYS) {
            if (!process.env[key]) {
                missing.push(key);
            }
        }

        if (missing.length > 0) {
            throw new ConfigurationException(
                `Missing required environment variables: ${missing.join(', ')}`
            );
        }
    }

    private static validateSensitiveValue(key: string, value: string): void {
        switch (key) {
            case 'JWT_SECRET':
                if (value.length < 32) {
                    throw new SecurityException('JWT secret must be at least 32 characters');
                }
                break;
            case 'DATABASE_PASSWORD':
                if (value.length < 12) {
                    throw new SecurityException('Database password must be at least 12 characters');
                }
                break;
            default:
                if (value.length < 16) {
                    throw new SecurityException(`${key} must be at least 16 characters`);
                }
        }
    }
}

Logging and Monitoring ​

Security Event Logging ​

typescript
export class SecurityAuditLogger {
    constructor(
        private readonly logger: ILogger,
        private readonly alertService: IAlertService
    ) {}

    logAuthenticationAttempt(event: AuthenticationEvent): void {
        this.logger.info('Authentication attempt', {
            userId: event.userId,
            ipAddress: this.sanitizeIpAddress(event.ipAddress),
            userAgent: this.sanitizeUserAgent(event.userAgent),
            success: event.success,
            timestamp: event.timestamp
        });

        // Alert on suspicious activity
        if (!event.success) {
            this.checkForBruteForceAttack(event);
        }
    }

    logDataAccess(event: DataAccessEvent): void {
        this.logger.info('Data access', {
            operation: event.operation,
            table: event.table,
            recordId: event.recordId,
            userId: event.userId,
            timestamp: event.timestamp
        });

        // Alert on sensitive data access
        if (this.isSensitiveTable(event.table)) {
            this.alertService.sendSecurityAlert({
                type: 'SENSITIVE_DATA_ACCESS',
                details: `User ${event.userId} accessed ${event.table} table`,
                severity: 'MEDIUM'
            });
        }
    }

    logSecurityViolation(violation: SecurityViolation): void {
        this.logger.error('Security violation detected', {
            type: violation.type,
            details: violation.details,
            userId: violation.userId,
            ipAddress: this.sanitizeIpAddress(violation.ipAddress),
            timestamp: violation.timestamp
        });

        // Immediate alert for security violations
        this.alertService.sendSecurityAlert({
            type: 'SECURITY_VIOLATION',
            details: violation.details,
            severity: 'HIGH'
        });
    }

    private checkForBruteForceAttack(event: AuthenticationEvent): void {
        // Implementation for detecting brute force attacks
        // This would typically involve rate limiting and IP tracking
    }

    private isSensitiveTable(table: string): boolean {
        const sensitiveTables = ['users', 'payments', 'personal_data'];
        return sensitiveTables.includes(table);
    }

    private sanitizeIpAddress(ip: string): string {
        // Mask part of IP for privacy while keeping it useful for security
        return ip.replace(/(\d+\.\d+\.\d+)\.\d+/, '$1.xxx');
    }

    private sanitizeUserAgent(userAgent: string): string {
        // Remove potentially sensitive information
        return userAgent.replace(/\(.*?\)/g, '(...)');
    }
}

Rate Limiting and Throttling ​

typescript
import { RateLimiter } from '@breadstone/ziegel-platform-http';

export class SecurityRateLimiter {
    private readonly limiters = new Map<string, RateLimiter>();

    constructor() {
        // Different limits for different operations
        this.limiters.set('auth', new RateLimiter({
            maxRequests: 5,
            windowMs: 15 * 60 * 1000, // 15 minutes
            skipSuccessfulRequests: true
        }));

        this.limiters.set('api', new RateLimiter({
            maxRequests: 100,
            windowMs: 60 * 1000, // 1 minute
            skipSuccessfulRequests: false
        }));

        this.limiters.set('password-reset', new RateLimiter({
            maxRequests: 3,
            windowMs: 60 * 60 * 1000, // 1 hour
            skipSuccessfulRequests: true
        }));
    }

    async checkLimit(operation: string, identifier: string): Promise<void> {
        const limiter = this.limiters.get(operation);
        if (!limiter) {
            throw new Error(`Unknown operation: ${operation}`);
        }

        const allowed = await limiter.checkLimit(identifier);
        if (!allowed) {
            throw new TooManyRequestsException(
                `Rate limit exceeded for ${operation}`,
                limiter.getResetTime(identifier)
            );
        }
    }
}

Error Handling Security ​

typescript
export class SecureErrorHandler {
    static handleError(error: Error, context: string): never {
        // Log full error details for debugging
        console.error(`Error in ${context}:`, error);

        // Return sanitized error to client
        if (error instanceof ValidationException) {
            throw new ValidationException(error.message, error.field);
        }

        if (error instanceof UnauthorizedException) {
            throw new UnauthorizedException('Access denied');
        }

        if (error instanceof NotFoundException) {
            throw new NotFoundException('Resource not found');
        }

        // Don't leak internal error details
        throw new InternalServerErrorException('An unexpected error occurred');
    }

    static sanitizeErrorForClient(error: Error): ClientError {
        // Remove stack traces and internal details
        return {
            message: this.getSafeErrorMessage(error),
            code: this.getErrorCode(error),
            timestamp: new Date().toISOString()
        };
    }

    private static getSafeErrorMessage(error: Error): string {
        const safeErrors = [
            'ValidationException',
            'UnauthorizedException',
            'NotFoundException',
            'TooManyRequestsException'
        ];

        if (safeErrors.includes(error.constructor.name)) {
            return error.message;
        }

        return 'An unexpected error occurred';
    }
}

Best Practices ​

Input Validation ​

typescript
// Always validate and sanitize inputs
export class InputValidator {
    static validateUserInput(input: UserInput): void {
        // Check for required fields
        if (!input.email || !input.name) {
            throw new ValidationException('Email and name are required');
        }

        // Validate format
        if (!RegexPatterns.email.test(input.email)) {
            throw new ValidationException('Invalid email format');
        }

        // Check length limits
        if (input.name.length > 100) {
            throw new ValidationException('Name too long');
        }

        // Sanitize input
        input.name = this.sanitizeString(input.name);
        input.email = input.email.toLowerCase().trim();
    }

    private static sanitizeString(input: string): string {
        // Remove potentially dangerous characters
        return input.replace(/[<>\"'&]/g, '').trim();
    }
}

Secure Defaults ​

typescript
// Use secure defaults in configuration
export class SecureDefaults {
    static readonly HTTP_CLIENT_CONFIG = {
        timeout: 30000,
        maxRedirects: 3,
        validateCertificates: true,
        allowInsecureConnections: false
    };

    static readonly PASSWORD_REQUIREMENTS = {
        minLength: 12,
        requireUppercase: true,
        requireLowercase: true,
        requireNumbers: true,
        requireSpecialChars: true,
        preventCommonPasswords: true
    };

    static readonly SESSION_CONFIG = {
        secure: true,
        httpOnly: true,
        sameSite: 'strict',
        maxAge: 24 * 60 * 60 * 1000 // 24 hours
    };
}

Security Checklist ​

Development ​

  • [ ] Input validation on all user inputs
  • [ ] Output encoding for all dynamic content
  • [ ] Parameterized queries for database access
  • [ ] Secure error handling without information leakage
  • [ ] Proper authentication and authorization
  • [ ] Session management security
  • [ ] HTTPS enforcement
  • [ ] Security headers implementation

Testing ​

  • [ ] Security unit tests
  • [ ] Input validation testing
  • [ ] Authentication bypass testing
  • [ ] SQL injection testing
  • [ ] XSS prevention testing
  • [ ] CSRF protection testing

Deployment ​

  • [ ] Environment variable validation
  • [ ] Secure configuration management
  • [ ] Security monitoring setup
  • [ ] Rate limiting configuration
  • [ ] Audit logging enabled
  • [ ] Security headers configured

Vulnerability Reporting ​

Reporting Security Issues ​

If you discover a security vulnerability in ziegel:

  1. Do not create a public GitHub issue
  2. Send an email to: awehlert@breadstone.de
  3. Include detailed information about the vulnerability
  4. Allow time for investigation and resolution

Response Process ​

  1. Acknowledgment: We'll acknowledge receipt within 24 hours
  2. Investigation: We'll investigate and assess the issue
  3. Resolution: We'll develop and test a fix
  4. Disclosure: We'll coordinate responsible disclosure

Security Updates ​

Security updates are published as:

  • Patch releases for minor vulnerabilities
  • Emergency releases for critical vulnerabilities
  • Security advisories for all vulnerabilities

Subscribe to security notifications to stay informed about security updates.

Compliance ​

Data Protection ​

ziegel libraries are designed to support compliance with:

  • GDPR (General Data Protection Regulation)
  • CCPA (California Consumer Privacy Act)
  • SOX (Sarbanes-Oxley Act)
  • HIPAA (Health Insurance Portability and Accountability Act)

Industry Standards ​

The framework follows security standards including:

  • OWASP Top 10
  • ISO 27001
  • NIST Cybersecurity Framework
  • CIS Controls

By following this security guide and implementing the recommended practices, you can build secure applications with the ziegel framework. Remember that security is an ongoing process, not a one-time implementation.