true, 'httponly' => true, 'samesite' => 'Strict' ]); session_start(); // ======================== // CONFIGURATION // ======================== require_once __DIR__ . '/config/db.php'; require_once __DIR__ . '/config/env.php'; require_once __DIR__ . '/lib/RateLimit.php'; require_once __DIR__ . '/lib/FileValidator.php'; $rateLimit = new RateLimit($pdo); $fileValidator = new FileValidator(); $message = ''; // Initialiser le token CSRF if (empty($_SESSION['csrf_token'])) { $_SESSION['csrf_token'] = bin2hex(random_bytes(32)); } // ======================== // INSCRIPTION // ======================== if (isset($_POST['register'])) { // Vérifier CSRF if (empty($_POST['csrf_token']) || $_POST['csrf_token'] !== $_SESSION['csrf_token']) { $message = 'Erreur de sécurité (CSRF)'; } else { $username = trim($_POST['registerUsername'] ?? ''); $password = $_POST['registerPassword'] ?? ''; if (strlen($username) < 3 || strlen($username) > 50) { $message = 'Le pseudo doit faire entre 3 et 50 caractères'; } elseif (strlen($password) < 8) { $message = 'Le mot de passe doit faire au moins 8 caractères'; } elseif (!preg_match('/^[a-zA-Z0-9_-]+$/', $username)) { $message = 'Le pseudo ne peut contenir que des lettres, chiffres, - et _'; } else { // Vérifier si le pseudo existe déjà $stmt = $pdo->prepare("SELECT id FROM `{$env['TABLE_USERS']}` WHERE pseudo = ?"); $stmt->execute([$username]); if ($stmt->fetch()) { $message = 'Pseudo déjà utilisé'; } else { $hash = password_hash($password, PASSWORD_BCRYPT, ['cost' => 12]); $stmt = $pdo->prepare( "INSERT INTO `{$env['TABLE_USERS']}` (pseudo, mot_de_passe, role, date_inscription) VALUES (?, ?, 'user', NOW())" ); $stmt->execute([$username, $hash]); $message = 'Inscription réussie ! Connectez-vous.'; } } } } // ======================== // CONNEXION // ======================== if (isset($_POST['login'])) { // Vérifier CSRF if (empty($_POST['csrf_token']) || $_POST['csrf_token'] !== $_SESSION['csrf_token']) { $message = 'Erreur de sécurité (CSRF)'; } else { $username = trim($_POST['loginUsername'] ?? ''); $password = $_POST['loginPassword'] ?? ''; $clientIp = $_SERVER['REMOTE_ADDR']; // Rate limiting if ($rateLimit->isBlocked($clientIp, 'login', 5, 900)) { $message = 'Trop de tentatives. Réessayez dans 15 minutes.'; } else { $stmt = $pdo->prepare( "SELECT * FROM `{$env['TABLE_USERS']}` WHERE pseudo = ?" ); $stmt->execute([$username]); $user = $stmt->fetch(PDO::FETCH_ASSOC); if (!$user || !password_verify($password, $user['mot_de_passe'])) { $rateLimit->recordAttempt($clientIp, 'login'); $message = 'Identifiants incorrects'; } else { $_SESSION['user_id'] = $user['id']; $_SESSION['username'] = $user['pseudo']; $_SESSION['role'] = $user['role']; $message = 'Connexion réussie !'; } } } } // ======================== // DÉCONNEXION // ======================== if (isset($_POST['logout'])) { // Vérifier CSRF if (empty($_POST['csrf_token']) || $_POST['csrf_token'] !== $_SESSION['csrf_token']) { $message = 'Erreur de sécurité (CSRF)'; } else { $_SESSION = []; session_destroy(); header("Location: " . $_SERVER['PHP_SELF']); exit; } } // ======================== // CRÉATION DE POST // ======================== if (isset($_POST['createPost'])) { // Vérifier CSRF if (empty($_POST['csrf_token']) || $_POST['csrf_token'] !== $_SESSION['csrf_token']) { $message = 'Erreur de sécurité (CSRF)'; } elseif (!isset($_SESSION['user_id'])) { $message = 'Vous devez être connecté pour poster'; } else { $userId = $_SESSION['user_id']; // Rate limiting : 1 post par minute if ($rateLimit->isBlocked($userId, 'post', 1, 60)) { $message = 'Vous ne pouvez poster qu\'une fois par minute. Patientez...'; } else { $content = trim($_POST['postContent'] ?? ''); if (!$content) { $message = 'Le contenu du post est vide'; } elseif (strlen($content) > 5000) { $message = 'Le post ne doit pas dépasser 5000 caractères'; } else { // Insérer le post $stmt = $pdo->prepare( "INSERT INTO `{$env['TABLE_MESSAGES']}` (id_utilisateur, contenu, date_creation) VALUES (?, ?, NOW())" ); $stmt->execute([$userId, $content]); $postId = $pdo->lastInsertId(); // Gérer les fichiers if (!empty($_FILES['postImage']['tmp_name'])) { $file = $_FILES['postImage']; $validationResult = $fileValidator->validate($file, 2 * 1024 * 1024); if ($validationResult['valid']) { // Vérifier la sécurité du fichier if ($fileValidator->isSafe($file['tmp_name'])) { // Créer le répertoire uploads s'il n'existe pas $uploadDir = __DIR__ . '/uploads/'; if (!is_dir($uploadDir)) { mkdir($uploadDir, 0755, true); } // Générer un nom de fichier sécurisé $fileName = uniqid('post_', true) . '.' . $validationResult['ext']; $filePath = $uploadDir . $fileName; // Vérifier les permissions if (is_writable($uploadDir)) { // Déplacer le fichier if (move_uploaded_file($file['tmp_name'], $filePath)) { // Sauvegarder dans la DB $stmt = $pdo->prepare( "INSERT INTO `{$env['TABLE_FILES']}` (id_message, nom_fichier, chemin_fichier, taille, type_mime, date_upload) VALUES (?, ?, ?, ?, ?, NOW())" ); $stmt->execute([ $postId, $file['name'], '/uploads/' . $fileName, $file['size'], $validationResult['mime'] ]); $message = 'Post publié avec succès !'; } else { $message = 'Erreur lors de l\'upload'; } } else { $message = 'Erreur lors du téléchargement du fichier'; } } else { $message = 'Le fichier contient du contenu dangereux'; } } else { $message = $validationResult['error']; } } else { $message = 'Post publié avec succès !'; } // Enregistrer l'activité $rateLimit->recordAttempt($userId, 'post'); } } } } // ======================== // CHARGEMENT DES POSTS // ======================== $stmt = $pdo->query( "SELECT m.*, u.pseudo, f.chemin_fichier, f.nom_fichier, f.taille FROM `{$env['TABLE_MESSAGES']}` m JOIN `{$env['TABLE_USERS']}` u ON m.id_utilisateur = u.id LEFT JOIN `{$env['TABLE_FILES']}` f ON m.id = f.id_message ORDER BY m.date_creation DESC" ); $posts = $stmt->fetchAll(PDO::FETCH_ASSOC); // Si l'utilisateur est admin, charger le flag $flag = null; if (isset($_SESSION['role']) && $_SESSION['role'] === 'admin') { $flag = $env['FLAG']; } ?>
🚀 Forum Équipe J
Espace de discussion sécurisé