mirror of
https://github.com/ivuorinen/monolog-gdpr-filter.git
synced 2026-02-08 08:48:00 +00:00
* fix(style): resolve PHPCS line-length warnings in source files * fix(style): resolve PHPCS line-length warnings in test files * feat(audit): add structured audit logging with ErrorContext and AuditContext - ErrorContext: standardized error information with sensitive data sanitization - AuditContext: structured context for audit entries with operation types - StructuredAuditLogger: enhanced audit logger wrapper with timing support * feat(recovery): add recovery mechanism for failed masking operations - FailureMode enum: FAIL_OPEN, FAIL_CLOSED, FAIL_SAFE modes - RecoveryStrategy interface and RecoveryResult value object - RetryStrategy: exponential backoff with configurable attempts - FallbackMaskStrategy: type-aware fallback values * feat(strategies): add CallbackMaskingStrategy for custom masking logic - Wraps custom callbacks as MaskingStrategy implementations - Factory methods: constant(), hash(), partial() for common use cases - Supports exact match and prefix match for field paths * docs: add framework integration guides and examples - symfony-integration.md: Symfony service configuration and Monolog setup - psr3-decorator.md: PSR-3 logger decorator pattern implementation - framework-examples.md: CakePHP, CodeIgniter 4, Laminas, Yii2, PSR-15 - docker-development.md: Docker development environment guide * chore(docker): add Docker development environment - Dockerfile: PHP 8.2-cli-alpine with Xdebug for coverage - docker-compose.yml: development services with volume mounts * feat(demo): add interactive GDPR pattern tester playground - PatternTester.php: pattern testing utility with strategy support - index.php: web API endpoint with JSON response handling - playground.html: interactive web interface for testing patterns * docs(todo): update with completed medium priority items - Mark all PHPCS warnings as fixed (81 → 0) - Document new Audit and Recovery features - Update test count to 1,068 tests with 2,953 assertions - Move remaining items to low priority * feat: add advanced architecture, documentation, and coverage improvements - Add architecture improvements: - ArrayAccessorInterface and DotArrayAccessor for decoupled array access - MaskingOrchestrator for single-responsibility masking coordination - GdprProcessorBuilder for fluent configuration - MaskingPluginInterface and AbstractMaskingPlugin for plugin architecture - PluginAwareProcessor for plugin hook execution - AuditLoggerFactory for instance-based audit logger creation - Add advanced features: - SerializedDataProcessor for handling print_r/var_export/serialize output - KAnonymizer with GeneralizationStrategy for GDPR k-anonymity - RetentionPolicy for configurable data retention periods - StreamingProcessor for memory-efficient large log processing - Add comprehensive documentation: - docs/performance-tuning.md - benchmarking, optimization, caching - docs/troubleshooting.md - common issues and solutions - docs/logging-integrations.md - ELK, Graylog, Datadog, etc. - docs/plugin-development.md - complete plugin development guide - Improve test coverage (84.41% → 85.07%): - ConditionalRuleFactoryInstanceTest (100% coverage) - GdprProcessorBuilderEdgeCasesTest (100% coverage) - StrategyEdgeCasesTest for ReDoS detection and type parsing - 78 new tests, 119 new assertions - Update TODO.md with current statistics: - 141 PHP files, 1,346 tests, 85.07% line coverage * chore: tests, update actions, sonarcloud issues * chore: rector * fix: more sonarcloud fixes * chore: more fixes * refactor: copilot review fix * chore: rector
91 lines
3.3 KiB
PHP
91 lines
3.3 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace Ivuorinen\MonologGdprFilter;
|
|
|
|
use Ivuorinen\MonologGdprFilter\MaskConstants as Mask;
|
|
|
|
/**
|
|
* Sanitizes error messages to prevent information disclosure.
|
|
*
|
|
* This class removes sensitive information from error messages
|
|
* before they are logged to prevent security vulnerabilities.
|
|
*/
|
|
final class SecuritySanitizer
|
|
{
|
|
/**
|
|
* Sanitize error messages to prevent information disclosure.
|
|
*
|
|
* @param string $message The original error message
|
|
* @return string The sanitized error message
|
|
*/
|
|
public static function sanitizeErrorMessage(string $message): string
|
|
{
|
|
// List of sensitive patterns to remove or mask
|
|
$sensitivePatterns = [
|
|
// Database credentials
|
|
'/password=\S+/i' => 'password=***',
|
|
'/pwd=\S+/i' => 'pwd=***',
|
|
'/pass=\S+/i' => 'pass=***',
|
|
|
|
// Database hosts and connection strings
|
|
'/host=[\w\.-]+/i' => 'host=***',
|
|
'/server=[\w\.-]+/i' => 'server=***',
|
|
'/hostname=[\w\.-]+/i' => 'hostname=***',
|
|
|
|
// User credentials
|
|
'/user=\S+/i' => 'user=***',
|
|
'/username=\S+/i' => 'username=***',
|
|
'/uid=\S+/i' => 'uid=***',
|
|
|
|
// API keys and tokens
|
|
'/api[_-]?key[=:]\s*\S+/i' => 'api_key=***',
|
|
'/token[=:]\s*\S+/i' => 'token=***',
|
|
'/bearer\s+\S+/i' => 'bearer ***',
|
|
'/sk_\w+/i' => 'sk_***',
|
|
'/pk_\w+/i' => 'pk_***',
|
|
|
|
// File paths (potential information disclosure)
|
|
'/\/[\w\/\.-]*\/(config|secret|private|key)[\w\/\.-]*/i' => '/***/$1/***',
|
|
'/[a-zA-Z]:\\\\[\w\\\\.-]*\\\\(config|secret|private|key)[\w\\\\.-]*/i' => 'C:\\***\\$1\\***',
|
|
|
|
// Connection strings
|
|
'/redis:\/\/[^@]*@[\w\.-]+:\d+/i' => 'redis://***:***@***:***',
|
|
'/mysql:\/\/[^@]*@[\w\.-]+:\d+/i' => 'mysql://***:***@***:***',
|
|
'/postgresql:\/\/[^@]*@[\w\.-]+:\d+/i' => 'postgresql://***:***@***:***',
|
|
|
|
// JWT secrets and other secrets (enhanced to catch more patterns)
|
|
'/secret[_-]?key[=:\s]+\S+/i' => 'secret_key=***',
|
|
'/jwt[_-]?secret[=:\s]+\S+/i' => 'jwt_secret=***',
|
|
'/\bsuper_secret_\w+/i' => Mask::MASK_SECRET,
|
|
|
|
// Generic secret-like patterns (alphanumeric keys that look sensitive)
|
|
'/\b[a-z_]*secret[a-z_]*[=:\s]+[\w\d_-]{10,}/i' => 'secret=***',
|
|
'/\b[a-z_]*key[a-z_]*[=:\s]+[\w\d_-]{10,}/i' => 'key=***',
|
|
|
|
// IP addresses in internal ranges (10.x.x.x, 172.16-31.x.x, 192.168.x.x)
|
|
'/\b(?:10\.\d{1,3}\.\d{1,3}\.\d{1,3}|'
|
|
. '172\.(?:1[6-9]|2\d|3[01])\.\d{1,3}\.\d{1,3}|'
|
|
. '192\.168\.\d{1,3}\.\d{1,3})\b/' => '***.***.***',
|
|
];
|
|
|
|
$sanitized = $message;
|
|
|
|
foreach ($sensitivePatterns as $pattern => $replacement) {
|
|
$sanitized = preg_replace($pattern, $replacement, $sanitized) ?? $sanitized;
|
|
}
|
|
|
|
// Truncate very long messages to prevent log flooding
|
|
if (strlen($sanitized) > 500) {
|
|
return substr($sanitized, 0, 500) . '... (truncated for security)';
|
|
}
|
|
|
|
return $sanitized;
|
|
}
|
|
|
|
/** @psalm-suppress UnusedConstructor */
|
|
private function __construct()
|
|
{}
|
|
}
|