api security

This commit is contained in:
Lain Iwakura 2025-06-16 01:48:41 +03:00
parent 9afe6dc04e
commit 16e16c5490
No known key found for this signature in database
GPG Key ID: C7C18257F2ADC6F8
2 changed files with 26 additions and 4 deletions

View File

@ -5,6 +5,16 @@ header('X-Frame-Options: DENY');
header('X-XSS-Protection: 1; mode=block'); header('X-XSS-Protection: 1; mode=block');
header('Content-Security-Policy: default-src \'self\''); header('Content-Security-Policy: default-src \'self\'');
session_start();
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
if (!isset($_SESSION['csrf_token']) || !isset($_SERVER['HTTP_X_CSRF_TOKEN']) ||
$_SESSION['csrf_token'] !== $_SERVER['HTTP_X_CSRF_TOKEN']) {
http_response_code(403);
die(json_encode(['error' => 'Invalid CSRF token']));
}
}
$config = require 'config.php'; $config = require 'config.php';
$db = new PDO( $db = new PDO(
"mysql:host={$config['db']['host']};dbname={$config['db']['name']}", "mysql:host={$config['db']['host']};dbname={$config['db']['name']}",
@ -18,7 +28,8 @@ if ($_SERVER['REQUEST_METHOD'] === 'GET') {
$limit = min(max(1, $limit), 100); $limit = min(max(1, $limit), 100);
try { try {
$stmt = $db->query("SELECT username, message, created_at, signature, is_encrypted FROM messages ORDER BY created_at DESC LIMIT $limit"); $stmt = $db->prepare("SELECT username, message, created_at, signature, is_encrypted FROM messages ORDER BY created_at DESC LIMIT ?");
$stmt->execute([$limit]);
$messages = $stmt->fetchAll(PDO::FETCH_ASSOC); $messages = $stmt->fetchAll(PDO::FETCH_ASSOC);
$filtered_messages = array_map(function($msg) { $filtered_messages = array_map(function($msg) {
@ -45,6 +56,14 @@ if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
die(json_encode(['error' => 'Method not allowed'])); die(json_encode(['error' => 'Method not allowed']));
} }
$ip = $_SERVER['REMOTE_ADDR'];
$stmt = $db->prepare("SELECT COUNT(*) FROM messages WHERE username = ? AND created_at > DATE_SUB(NOW(), INTERVAL 1 MINUTE)");
$stmt->execute([$ip]);
if ($stmt->fetchColumn() > 10) {
http_response_code(429);
die(json_encode(['error' => 'Too many requests']));
}
$input = json_decode(file_get_contents('php://input'), true); $input = json_decode(file_get_contents('php://input'), true);
if (!$input) { if (!$input) {
http_response_code(400); http_response_code(400);
@ -56,9 +75,9 @@ $message = $input['message'] ?? '';
$signature = $input['signature'] ?? ''; $signature = $input['signature'] ?? '';
$is_encrypted = !empty($input['encrypted']) ? 1 : 0; $is_encrypted = !empty($input['encrypted']) ? 1 : 0;
if (!$username || !$message) { if (!$username || !$message || strlen($username) > 50 || strlen($message) > 10000) {
http_response_code(400); http_response_code(400);
die(json_encode(['error' => 'Missing required fields'])); die(json_encode(['error' => 'Invalid input']));
} }
try { try {

View File

@ -17,6 +17,8 @@ CREATE TABLE users (
is_moderator TINYINT(1) NOT NULL DEFAULT 0, is_moderator TINYINT(1) NOT NULL DEFAULT 0,
login_attempts INT NOT NULL DEFAULT 0, login_attempts INT NOT NULL DEFAULT 0,
last_attempt TIMESTAMP NULL, last_attempt TIMESTAMP NULL,
is_blocked TINYINT(1) NOT NULL DEFAULT 0,
block_reason TEXT,
INDEX idx_username (username) INDEX idx_username (username)
); );
@ -24,5 +26,6 @@ CREATE TABLE registrations (
id INT AUTO_INCREMENT PRIMARY KEY, id INT AUTO_INCREMENT PRIMARY KEY,
ip VARCHAR(45) NOT NULL, ip VARCHAR(45) NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
INDEX idx_ip_created (ip, created_at) INDEX idx_ip_created (ip, created_at),
INDEX idx_created_at (created_at)
); );