shubraVeil/includes/Security.php

235 lines
7.5 KiB
PHP
Raw Normal View History

2024-12-25 13:05:50 +02:00
<?php
class Security {
private static $instance = null;
private $rate_limit_file;
private static $encryptionKey = 'your-secure-encryption-key-here';
private function __construct() {
$this->rate_limit_file = __DIR__ . '/../cache/rate_limits.json';
if (!file_exists($this->rate_limit_file)) {
if (!is_dir(dirname($this->rate_limit_file))) {
mkdir(dirname($this->rate_limit_file), 0755, true);
}
file_put_contents($this->rate_limit_file, '{}');
}
}
public static function getInstance() {
if (self::$instance === null) {
self::$instance = new self();
}
return self::$instance;
}
public static function sanitizeInput($data) {
if (is_array($data)) {
return array_map([self::class, 'sanitizeInput'], $data);
}
return htmlspecialchars(strip_tags(trim($data)), ENT_QUOTES, 'UTF-8');
}
public static function validateRecaptcha($response) {
$url = 'https://www.google.com/recaptcha/api/siteverify';
$data = [
'secret' => RECAPTCHA_SECRET_KEY,
'response' => $response
];
$options = [
'http' => [
'header' => "Content-type: application/x-www-form-urlencoded\r\n",
'method' => 'POST',
'content' => http_build_query($data)
]
];
$context = stream_context_create($options);
$result = file_get_contents($url, false, $context);
$result_json = json_decode($result, true);
return isset($result_json['success']) && $result_json['success'] === true;
}
public function checkRateLimit($ip, $endpoint, $limit = 60, $window = 3600) {
$limits = json_decode(file_get_contents($this->rate_limit_file), true);
$now = time();
$key = $ip . ':' . $endpoint;
if (!isset($limits[$key])) {
$limits[$key] = ['count' => 0, 'window_start' => $now];
}
if ($now - $limits[$key]['window_start'] > $window) {
$limits[$key] = ['count' => 0, 'window_start' => $now];
}
$limits[$key]['count']++;
file_put_contents($this->rate_limit_file, json_encode($limits));
return $limits[$key]['count'] <= $limit;
}
public static function generateCSRFToken() {
if (!isset($_SESSION['csrf_token'])) {
$_SESSION['csrf_token'] = bin2hex(random_bytes(32));
}
return $_SESSION['csrf_token'];
}
public static function verifyCSRFToken($token) {
return isset($_SESSION['csrf_token']) && hash_equals($_SESSION['csrf_token'], $token);
}
public static function encrypt($data) {
$iv = random_bytes(16);
$encrypted = openssl_encrypt(
$data,
'AES-256-CBC',
self::$encryptionKey,
0,
$iv
);
return base64_encode($iv . $encrypted);
}
public static function decrypt($data) {
$data = base64_decode($data);
$iv = substr($data, 0, 16);
$encrypted = substr($data, 16);
return openssl_decrypt(
$encrypted,
'AES-256-CBC',
self::$encryptionKey,
0,
$iv
);
}
public static function hashPassword($password) {
return password_hash($password, PASSWORD_DEFAULT);
}
public static function verifyPassword($password, $hash) {
return password_verify($password, $hash);
}
2024-12-25 14:31:31 +02:00
public static function sanitize_input($data) {
$data = trim($data);
$data = stripslashes($data);
$data = htmlspecialchars($data, ENT_QUOTES, 'UTF-8');
return $data;
}
public static function generate_csrf_token() {
if (empty($_SESSION['csrf_token'])) {
$_SESSION['csrf_token'] = bin2hex(random_bytes(32));
}
return $_SESSION['csrf_token'];
}
public static function verify_csrf_token($token) {
return isset($_SESSION['csrf_token']) && hash_equals($_SESSION['csrf_token'], $token);
}
public static function check_rate_limit($key, $limit = 5, $period = 300) {
$cache_key = "rate_limit:{$key}";
$current = isset($_SESSION[$cache_key]) ? $_SESSION[$cache_key] : ['count' => 0, 'timestamp' => time()];
if (time() - $current['timestamp'] > $period) {
$current = ['count' => 1, 'timestamp' => time()];
} else {
$current['count']++;
}
$_SESSION[$cache_key] = $current;
return $current['count'] <= $limit;
}
public static function is_password_strong($password) {
// Minimum 8 characters
if (strlen($password) < 8) return false;
// Must contain at least one uppercase letter
if (!preg_match('/[A-Z]/', $password)) return false;
// Must contain at least one lowercase letter
if (!preg_match('/[a-z]/', $password)) return false;
// Must contain at least one number
if (!preg_match('/[0-9]/', $password)) return false;
// Must contain at least one special character
if (!preg_match('/[!@#$%^&*()\-_=+{};:,<.>]/', $password)) return false;
return true;
}
public static function is_file_upload_safe($file) {
$allowed_types = ['image/jpeg', 'image/png', 'image/webp'];
$max_size = 5 * 1024 * 1024; // 5MB
// Check file type
if (!in_array($file['type'], $allowed_types)) {
return false;
}
// Check file size
if ($file['size'] > $max_size) {
return false;
}
// Check if file is actually an image
if (!getimagesize($file['tmp_name'])) {
return false;
}
return true;
}
public static function set_secure_headers() {
header('X-Content-Type-Options: nosniff');
header('X-Frame-Options: SAMEORIGIN');
header('X-XSS-Protection: 1; mode=block');
header('Referrer-Policy: strict-origin-when-cross-origin');
header("Content-Security-Policy: default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval' https://www.google.com/recaptcha/ https://www.gstatic.com/recaptcha/; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; connect-src 'self'");
}
public static function secure_session_start() {
ini_set('session.cookie_httponly', 1);
ini_set('session.cookie_secure', 1);
ini_set('session.use_only_cookies', 1);
ini_set('session.cookie_samesite', 'Strict');
session_start();
}
public static function log_security_event($event_type, $details) {
$log_file = __DIR__ . '/../logs/security.log';
$timestamp = date('Y-m-d H:i:s');
$ip = $_SERVER['REMOTE_ADDR'];
$user = isset($_SESSION['user_id']) ? $_SESSION['user_id'] : 'anonymous';
$log_entry = sprintf(
"[%s] %s - IP: %s, User: %s, Details: %s\n",
$timestamp,
$event_type,
$ip,
$user,
json_encode($details)
);
error_log($log_entry, 3, $log_file);
}
public static function init_security() {
self::secure_session_start();
self::set_secure_headers();
// Force HTTPS
if (!isset($_SERVER['HTTPS']) || $_SERVER['HTTPS'] !== 'on') {
header('Location: https://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI']);
exit();
}
}
2024-12-25 13:05:50 +02:00
}