3afe3b7698
Fixes critical pre-existing issues found during review: bulk_action.php had no auth check at all (unauthenticated download/delete of any qrcode) and built a table name from unwhitelisted user input (SQL injection); the QR generator classes wrote files from unvalidated filename/format, allowing path traversal and arbitrary file writes. Also pins chillerlan/php-qrcode to 5.0.5 since master now requires PHP 8.4, breaking the PHP 8.3 build. - CSRF tokens on all POST forms and the bulk_action.php JSON endpoint - Login rate limiting (5 attempts / 15 min) via new login_attempts table - Hardened sessions: httponly/samesite cookies, 30 min idle timeout, session regeneration on login - Forced password change for the default superadmin/superadmin account - Server-side validation in Users/DynamicQrcode/Qrcode classes - Audit log table for auth, user, and qrcode actions - Checked-in db schema (db/init.sql, migrations/) instead of relying on an opaque prebuilt db image - Production docker-compose with Nginx + php-fpm instead of the PHP dev server
58 lines
2.2 KiB
SQL
58 lines
2.2 KiB
SQL
-- Fase 1 security hardening migratie.
|
|
-- Voer uit tegen een bestaande database (gebruikt de originele
|
|
-- giandonatoinverso/php-dynamic-qr-code-db image of een oudere init.sql).
|
|
-- Kolommen/tabellen worden alleen toegevoegd als ze nog niet bestaan.
|
|
|
|
SET @db := DATABASE();
|
|
|
|
SET @col_exists := (
|
|
SELECT COUNT(*) FROM information_schema.COLUMNS
|
|
WHERE TABLE_SCHEMA = @db AND TABLE_NAME = 'users' AND COLUMN_NAME = 'must_change_password'
|
|
);
|
|
SET @sql := IF(@col_exists = 0,
|
|
'ALTER TABLE `users` ADD COLUMN `must_change_password` TINYINT(1) NOT NULL DEFAULT 0',
|
|
'SELECT 1');
|
|
PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
|
|
|
|
SET @col_exists := (
|
|
SELECT COUNT(*) FROM information_schema.COLUMNS
|
|
WHERE TABLE_SCHEMA = @db AND TABLE_NAME = 'users' AND COLUMN_NAME = 'password_changed_at'
|
|
);
|
|
SET @sql := IF(@col_exists = 0,
|
|
'ALTER TABLE `users` ADD COLUMN `password_changed_at` DATETIME DEFAULT NULL',
|
|
'SELECT 1');
|
|
PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
|
|
|
|
-- Bestaand superadmin account met het fabriekswachtwoord (superadmin/superadmin)
|
|
-- moet bij eerstvolgende login het wachtwoord wijzigen.
|
|
UPDATE `users`
|
|
SET `must_change_password` = 1
|
|
WHERE `username` = 'superadmin'
|
|
AND `password` = '$2y$10$xpZc5KC.aU2XHkcqhuZGFuAnqmtL4Unt8MysOyylceq.19XIyoZpG';
|
|
|
|
CREATE TABLE IF NOT EXISTS `login_attempts` (
|
|
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
|
|
`username` varchar(50) NOT NULL,
|
|
`ip_address` varchar(45) NOT NULL,
|
|
`success` tinyint(1) NOT NULL DEFAULT 0,
|
|
`attempted_at` datetime NOT NULL,
|
|
PRIMARY KEY (`id`),
|
|
KEY `username_attempted_at` (`username`, `attempted_at`),
|
|
KEY `ip_attempted_at` (`ip_address`, `attempted_at`)
|
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
|
|
|
CREATE TABLE IF NOT EXISTS `audit_log` (
|
|
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
|
|
`user_id` int(25) DEFAULT NULL,
|
|
`username` varchar(50) DEFAULT NULL,
|
|
`action` varchar(50) NOT NULL,
|
|
`target_type` varchar(30) DEFAULT NULL,
|
|
`target_id` varchar(50) DEFAULT NULL,
|
|
`ip_address` varchar(45) DEFAULT NULL,
|
|
`user_agent` varchar(255) DEFAULT NULL,
|
|
`created_at` datetime NOT NULL,
|
|
PRIMARY KEY (`id`),
|
|
KEY `created_at` (`created_at`),
|
|
KEY `user_id` (`user_id`)
|
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|