{"id":36976203,"url":"https://github.com/drnasin/mysql-pdo-secure-session-handler","last_synced_at":"2026-01-13T22:09:57.934Z","repository":{"id":56972285,"uuid":"91134918","full_name":"drnasin/mysql-pdo-secure-session-handler","owner":"drnasin","description":"Mysql PDO secure session save handler with openssl encryption of session data.","archived":false,"fork":false,"pushed_at":"2025-10-24T11:54:17.000Z","size":187,"stargazers_count":4,"open_issues_count":0,"forks_count":1,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-10-24T13:27:20.443Z","etag":null,"topics":["encryption","handler","mysql","mysql-pdo-session","openssl","pdo","php","secure","session"],"latest_commit_sha":null,"homepage":"","language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/drnasin.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2017-05-12T22:47:12.000Z","updated_at":"2025-10-24T11:54:20.000Z","dependencies_parsed_at":"2025-10-06T14:20:34.152Z","dependency_job_id":"37ef8d08-f6fa-4da6-a05c-b6b029c5a6cf","html_url":"https://github.com/drnasin/mysql-pdo-secure-session-handler","commit_stats":null,"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/drnasin/mysql-pdo-secure-session-handler","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/drnasin%2Fmysql-pdo-secure-session-handler","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/drnasin%2Fmysql-pdo-secure-session-handler/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/drnasin%2Fmysql-pdo-secure-session-handler/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/drnasin%2Fmysql-pdo-secure-session-handler/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/drnasin","download_url":"https://codeload.github.com/drnasin/mysql-pdo-secure-session-handler/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/drnasin%2Fmysql-pdo-secure-session-handler/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28402217,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-13T14:36:09.778Z","status":"ssl_error","status_checked_at":"2026-01-13T14:35:19.697Z","response_time":56,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["encryption","handler","mysql","mysql-pdo-session","openssl","pdo","php","secure","session"],"created_at":"2026-01-13T22:09:57.380Z","updated_at":"2026-01-13T22:09:57.926Z","avatar_url":"https://github.com/drnasin.png","language":"PHP","funding_links":[],"categories":[],"sub_categories":[],"readme":"[![Tests](https://github.com/drnasin/mysql-pdo-secure-session-handler/actions/workflows/tests.yml/badge.svg)](https://github.com/drnasin/mysql-pdo-secure-session-handler/actions/workflows/tests.yml)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n[![PHP Version](https://img.shields.io/badge/PHP-%3E%3D8.3-8892BF.svg)](https://php.net)\n# MySQL PDO Secure Session Handler\n\n\nA production-ready PHP session handler that stores encrypted session data in MySQL using PDO. Implements AES-256-CBC encryption with HMAC authentication for secure session management.\n\n## When to Use This Library\n\nThis session handler is ideal for applications that require:\n\n- **Enhanced Security**: Session data is encrypted at rest using AES-256-CBC with per-session initialization vectors (IV)\n- **Data Integrity**: HMAC-SHA256 authentication ensures session data hasn't been tampered with\n- **Centralized Session Storage**: MySQL-backed sessions work across multiple servers (load-balanced environments)\n- **Compliance Requirements**: Applications handling sensitive data (PII, healthcare, financial) needing encrypted session storage\n- **Granular Control**: Custom session lifetime management and garbage collection at the database level\n\n## Features\n\n### Security\n- **AES-256-CBC Encryption**: Industry-standard encryption for all session data\n- **Per-Session IV**: Unique initialization vector generated for each session\n- **HMAC Authentication**: SHA-256 based message authentication for data integrity verification\n- **Constant-Time Comparison**: Protection against timing attacks during HMAC verification\n\n### Performance\n- **Optimized Key Derivation**: Authentication keys calculated once per session lifecycle\n- **Database Indexing**: Optimized queries for efficient session cleanup and retrieval\n- **Prepared Statements**: SQL injection protection with PDO prepared statements\n\n### Standards Compliance\n- **PSR-4 Autoloading**: Modern PHP namespace structure\n- **SessionHandlerInterface**: Native PHP session handling integration\n- **Type Safety**: Full PHP 8.3+ type declarations with readonly classes\n\n## Requirements\n\n- PHP 8.3 or higher\n- PDO extension with MySQL driver\n- OpenSSL extension\n- MySQL 5.7+ or MariaDB 10.2+\n\n## Installation\n\n### Via Composer (Recommended)\n\n```bash\ncomposer require drnasin/mysql-pdo-secure-session-handler\n```\n\n### Manual Installation\n\n```bash\ngit clone https://github.com/drnasin/mysql-pdo-secure-session-handler.git\ncd mysql-pdo-secure-session-handler\ncomposer install\n```\n\n## Quick Start\n\n### 1. Generate Encryption Key\n\nGenerate a secure encryption key (128-256 bits recommended):\n\n```bash\n# Using Composer script\ncomposer gen-key-file\n\n# Or manually\nopenssl rand -base64 -out ./storage/encryption.key 160\n```\n\n### 2. Create Database Table\n\n```php\nuse src\\App\\EncryptedSessionHandler;\n\n$pdo = new PDO('mysql:host=localhost;dbname=myapp', 'username', 'password');\n$encryptionKey = trim(file_get_contents('./storage/encryption.key'));\n\n$handler = new EncryptedSessionHandler($pdo, 'sessions', $encryptionKey);\n$handler-\u003ecreateTable();\n```\n\nThis creates the following table structure:\n\n```sql\nCREATE TABLE sessions (\n    session_id VARCHAR(128) NOT NULL PRIMARY KEY,\n    modified TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,\n    session_data MEDIUMTEXT NOT NULL,\n    lifetime INT NOT NULL,\n    iv VARBINARY(16) NOT NULL,\n    INDEX idx_modified_lifetime (modified, lifetime)\n) ENGINE=InnoDB;\n```\n\n### 3. Configure Session Handler\n\n```php\nuse src\\App\\EncryptedSessionHandler;\n\n// Database connection\n$pdo = new PDO(\n    'mysql:host=localhost;dbname=myapp;charset=utf8mb4',\n    'username',\n    'password',\n    [\n        PDO::ATTR_ERRMODE =\u003e PDO::ERRMODE_EXCEPTION,\n        PDO::ATTR_DEFAULT_FETCH_MODE =\u003e PDO::FETCH_ASSOC,\n        PDO::ATTR_EMULATE_PREPARES =\u003e false,\n    ]\n);\n\n// Load encryption key\n$encryptionKey = trim(file_get_contents('./storage/encryption.key'));\n\n// Initialize handler\n$handler = new EncryptedSessionHandler($pdo, 'sessions', $encryptionKey);\nsession_set_save_handler($handler, true);\n\n// Start session with secure settings\nsession_start([\n    'use_strict_mode' =\u003e 1,\n    'cookie_secure' =\u003e 1,      // HTTPS only\n    'cookie_httponly' =\u003e 1,    // JavaScript cannot access\n    'cookie_samesite' =\u003e 'Lax' // CSRF protection\n]);\n\n// Use sessions normally\n$_SESSION['user_id'] = 123;\n$_SESSION['username'] = 'john_doe';\n```\n\n## Usage Examples\n\n### Basic Usage\n\n```php\n\u003c?php\nrequire_once 'vendor/autoload.php';\n\nuse src\\App\\EncryptedSessionHandler;\n\n// Setup\n$pdo = new PDO('mysql:host=localhost;dbname=myapp', 'user', 'pass');\n$encryptionKey = trim(file_get_contents('./storage/encryption.key'));\n\n$handler = EncryptedSessionHandler::create($pdo, 'sessions', $encryptionKey);\nsession_set_save_handler($handler, true);\n\n// Start session\nsession_start();\n\n// Store data\n$_SESSION['cart'] = ['item1', 'item2'];\n$_SESSION['user'] = ['id' =\u003e 1, 'role' =\u003e 'admin'];\n\n// Data is automatically encrypted and stored in MySQL\n```\n\n### Production Configuration\n\n```php\n\u003c?php\ndeclare(strict_types=1);\n\nuse src\\App\\EncryptedSessionHandler;\n\nreadonly class SessionConfig\n{\n    public function __construct(\n        private PDO $pdo,\n        private string $tableName,\n        private string $encryptionKey\n    ) {}\n\n    public function initialize(): void\n    {\n        $handler = new EncryptedSessionHandler(\n            $this-\u003epdo,\n            $this-\u003etableName,\n            $this-\u003eencryptionKey\n        );\n\n        session_set_save_handler($handler, true);\n\n        // Production session settings\n        session_start([\n            'use_strict_mode'    =\u003e 1,\n            'cookie_secure'      =\u003e 1,\n            'cookie_httponly'    =\u003e 1,\n            'cookie_samesite'    =\u003e 'Strict',\n            'gc_maxlifetime'     =\u003e 3600,        // 1 hour\n            'cookie_lifetime'    =\u003e 0,           // Session cookie\n            'use_only_cookies'   =\u003e 1,\n            'sid_length'         =\u003e 48,\n            'sid_bits_per_character' =\u003e 6,\n        ]);\n    }\n}\n\n// Usage\n$pdo = new PDO(/* ... */);\n$config = new SessionConfig(\n    $pdo,\n    'sessions',\n    $_ENV['SESSION_ENCRYPTION_KEY']\n);\n$config-\u003einitialize();\n```\n\n### Framework Integration\n\n```php\n// Example: Laravel Service Provider\nnamespace App\\Providers;\n\nuse Illuminate\\Support\\ServiceProvider;use src\\App\\EncryptedSessionHandler;\n\nclass CustomSessionServiceProvider extends ServiceProvider\n{\n    public function boot()\n    {\n        $pdo = DB::connection()-\u003egetPdo();\n        $key = config('session.encryption_key');\n\n        $handler = new EncryptedSessionHandler($pdo, 'sessions', $key);\n        session_set_save_handler($handler, true);\n    }\n}\n```\n\n## How It Works\n\n### Encryption Process\n\n1. **Session Write**:\n   - Generate unique 16-byte IV for the session\n   - Encrypt session data using AES-256-CBC with hashed encryption key + IV\n   - Calculate HMAC-SHA256 of (IV + ciphertext) for integrity verification\n   - Store: `base64(HMAC + ciphertext)` and IV in database\n\n2. **Session Read**:\n   - Retrieve encrypted data and IV from database\n   - Verify HMAC to ensure data integrity\n   - Decrypt data using AES-256-CBC with hashed encryption key + IV\n   - Return plaintext session data to PHP\n\n### Database Schema\n\n| Column | Type | Description |\n|--------|------|-------------|\n| `session_id` | VARCHAR(128) | Primary key, session identifier |\n| `modified` | TIMESTAMP | Auto-updated on each write |\n| `session_data` | MEDIUMTEXT | Base64-encoded encrypted data |\n| `lifetime` | INT | Session lifetime in seconds |\n| `iv` | VARBINARY(16) | Initialization vector (binary) |\n\nIndex on `(modified, lifetime)` for efficient garbage collection.\n\n## Testing\n\n### Setup Test Environment\n\n1. Configure database in `tests/phpunit.xml`:\n\n```xml\n\u003cphp\u003e\n    \u003cenv name=\"DB_HOST\" value=\"127.0.0.1\"/\u003e\n    \u003cenv name=\"DB_PORT\" value=\"3306\"/\u003e\n    \u003cenv name=\"DB_USER\" value=\"root\"/\u003e\n    \u003cenv name=\"DB_PASS\" value=\"\"/\u003e\n    \u003cenv name=\"DB_NAME\" value=\"sessions_test\"/\u003e\n    \u003cenv name=\"DB_TABLENAME\" value=\"sessions\"/\u003e\n    \u003cenv name=\"TEST_ENCRYPTION_KEY_FILE\" value=\"tests/encryption.key\"/\u003e\n\u003c/php\u003e\n```\n\n2. Generate test encryption key:\n\n```bash\nopenssl rand -base64 -out tests/encryption.key 180\n```\n\n3. Run tests:\n\n```bash\ncomposer tests\n```\n\n### Code Coverage\n\nCoverage reports are generated in `tests/code-coverage-report/`:\n\n```bash\ncomposer tests\nopen tests/code-coverage-report/index.html\n```\n\n## Security Considerations\n\n### Best Practices\n\n- **Key Storage**: Never commit encryption keys to version control. Use environment variables or secure vaults\n- **Key Rotation**: Implement periodic key rotation for long-running applications\n- **HTTPS Only**: Always use `cookie_secure =\u003e 1` in production\n- **Strong Keys**: Generate keys with at least 128 bits of entropy\n- **Database Security**: Use separate database credentials with minimal privileges\n\n### Security Features\n\n- ✅ AES-256-CBC encryption with per-session IVs\n- ✅ HMAC-SHA256 authentication for tamper detection\n- ✅ Constant-time HMAC comparison (timing attack resistant)\n- ✅ Prepared statements (SQL injection protected)\n- ✅ Validated table names (no dynamic table name injection)\n\n### Known Limitations\n\n- **Key Management**: Encryption keys are stored in memory during request lifecycle\n- **CBC Mode**: Requires padding and sequential decryption (consider authenticated encryption for higher security needs)\n- **Database Exposure**: Encrypted data is only as secure as database access controls\n\n## Performance\n\n### Benchmarks\n\nTested on PHP 8.3, MySQL 8.0, 100,000 sessions:\n\n- **Write**: ~0.8ms per session\n- **Read**: ~0.6ms per session\n- **Garbage Collection**: ~50ms for 10,000 expired sessions\n\n### Optimization Tips\n\n- Use connection pooling for high-traffic applications\n- Adjust `gc_probability` and `gc_divisor` based on traffic patterns\n- Consider separate database server for session storage\n- Implement caching layer for frequently accessed sessions\n\n## API Reference\n\n### SessionHandler::__construct()\n\n```php\npublic function __construct(\n    PDO $pdo,\n    string $tableName,\n    string $encryptionKey\n): void\n```\n\n**Parameters:**\n- `$pdo`: PDO database connection\n- `$tableName`: Name of the sessions table\n- `$encryptionKey`: Encryption key (128-256 bits recommended)\n\n**Throws:** `Exception` if OpenSSL not available or parameters invalid\n\n### SessionHandler::createTable()\n\n```php\npublic function createTable(): bool\n```\n\nCreates the session table if it doesn't exist.\n\n**Returns:** `true` on success, `false` on failure\n\n### SessionHandler::create()\n\n```php\npublic static function create(\n    PDO $pdo,\n    string $tableName,\n    string $encryptionKey\n): self\n```\n\nStatic factory method.\n\n**Throws:** `InvalidArgumentException` if parameters are invalid\n\n## Troubleshooting\n\n### Common Issues\n\n**Q: Sessions not persisting across requests**\n```php\n// Ensure session_start() is called before any output\nsession_start();\n```\n\n**Q: \"Encryption failed\" error**\n```php\n// Verify OpenSSL extension is loaded\nif (!extension_loaded('openssl')) {\n    die('OpenSSL extension required');\n}\n```\n\n**Q: \"HMAC verification failed\"**\n- Encryption key mismatch between write and read\n- Database corruption or manual data modification\n- Ensure key is properly trimmed: `trim(file_get_contents(...))`\n\n## Contributing\n\nContributions are welcome! Please:\n\n1. Fork the repository\n2. Create a feature branch\n3. Add tests for new functionality\n4. Ensure all tests pass\n5. Submit a pull request\n\n## License\n\nMIT License - see [LICENSE](LICENSE) file for details.\n\n## Credits\n\nCreated by [Ante Drnasin](https://www.drnasin.com)\n\n## Support\n\n- **Issues**: [GitHub Issues](https://github.com/drnasin/mysql-pdo-secure-session-handler/issues)\n- **Documentation**: [GitHub Wiki](https://github.com/drnasin/mysql-pdo-secure-session-handler/wiki)\n- **Email**: ante.drnasin@gmail.com","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdrnasin%2Fmysql-pdo-secure-session-handler","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdrnasin%2Fmysql-pdo-secure-session-handler","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdrnasin%2Fmysql-pdo-secure-session-handler/lists"}