Files
2026-09-16 23:20:08 +07:00

211 lines
8.2 KiB
PHP

<?php
// core/security.php
// 1. Session Security Configuration
// Must be called BEFORE session_start()
function configure_secure_session() {
if (session_status() === PHP_SESSION_NONE) {
ini_set('session.cookie_httponly', 1);
ini_set('session.cookie_samesite', 'Lax');
ini_set('session.use_only_cookies', 1);
ini_set('session.cookie_secure', isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on' ? 1 : 0);
}
}
// 2. HTTP Security Headers
function send_security_headers() {
header("X-Frame-Options: SAMEORIGIN");
header("X-XSS-Protection: 1; mode=block");
header("X-Content-Type-Options: nosniff");
header("Strict-Transport-Security: max-age=31536000; includeSubDomains");
header("Referrer-Policy: strict-origin-when-cross-origin");
}
// 3. CSRF Protection
function generate_csrf_token() {
if (empty($_SESSION['csrf_token'])) {
$_SESSION['csrf_token'] = bin2hex(random_bytes(32));
}
return $_SESSION['csrf_token'];
}
function verify_csrf_token($token) {
if (empty($_SESSION['csrf_token']) || empty($token)) {
return false;
}
return hash_equals($_SESSION['csrf_token'], $token);
}
// 4. Rate Limiting (Anti-Brute Force)
function check_rate_limit($conn, $ip) {
try {
// Create table if not exists (Auto-healing)
$sql_create = "CREATE TABLE IF NOT EXISTS sys_login_attempts (
id INT AUTO_INCREMENT PRIMARY KEY,
ip_address VARCHAR(45) NOT NULL,
username VARCHAR(255) NOT NULL,
attempt_time DATETIME NOT NULL
)";
$conn->query($sql_create);
// Clean up old attempts
$conn->query("DELETE FROM sys_login_attempts WHERE attempt_time <= (NOW() - INTERVAL 15 MINUTE)");
// Count recent failed attempts for this IP
$stmt = $conn->prepare("SELECT COUNT(*) as count FROM sys_login_attempts WHERE ip_address = ? AND attempt_time > (NOW() - INTERVAL 15 MINUTE)");
if ($stmt) {
$stmt->bind_param("s", $ip);
$stmt->execute();
$res = $stmt->get_result();
$row = $res->fetch_assoc();
$stmt->close();
if ($row && $row['count'] >= 5) {
return false; // Blocked
}
}
} catch (Throwable $e) {
error_log("check_rate_limit Error: " . $e->getMessage());
}
return true; // Allowed
}
function record_failed_login($conn, $ip, $username) {
try {
$stmt = $conn->prepare("INSERT INTO sys_login_attempts (ip_address, username, attempt_time) VALUES (?, ?, NOW())");
if ($stmt) {
$stmt->bind_param("ss", $ip, $username);
$stmt->execute();
$stmt->close();
// Check if exactly 5 to send notification
$stmt2 = $conn->prepare("SELECT COUNT(*) as count FROM sys_login_attempts WHERE ip_address = ? AND attempt_time > (NOW() - INTERVAL 15 MINUTE)");
if ($stmt2) {
$stmt2->bind_param("s", $ip);
$stmt2->execute();
$res = $stmt2->get_result();
$row = $res->fetch_assoc();
$stmt2->close();
if ($row && $row['count'] == 5) {
send_ban_notification($ip, $username);
}
}
}
} catch (Throwable $e) {
error_log("record_failed_login Error: " . $e->getMessage());
}
}
function clear_failed_logins($conn, $ip) {
try {
$stmt = $conn->prepare("DELETE FROM sys_login_attempts WHERE ip_address = ?");
if ($stmt) {
$stmt->bind_param("s", $ip);
$stmt->execute();
$stmt->close();
}
} catch (Throwable $e) {
error_log("clear_failed_logins Error: " . $e->getMessage());
}
}
function send_ban_notification($ip, $username) {
require_once(__DIR__."/settings.php");
$settings = get_app_settings();
$message = "⚠️ แจ้งเตือนความปลอดภัย\n";
$message .= "มีการระงับการใช้งาน IP Address (Ban IP)\n";
$message .= "IP: {$ip}\n";
$message .= "Username ที่พยายามเข้าสู่ระบบ: {$username}\n";
$message .= "เวลา: " . date("Y-m-d H:i:s");
// Line Notify
if (!empty($settings['line_notify_enable']) && $settings['line_notify_enable'] == '1' && !empty($settings['line_notify_token'])) {
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "https://notify-api.line.me/api/notify");
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, "message=" . urlencode($message));
$headers = array('Content-type: application/x-www-form-urlencoded', 'Authorization: Bearer ' . $settings['line_notify_token']);
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_exec($ch);
curl_close($ch);
}
// Telegram Notify
if (!empty($settings['telegram_notify_enable']) && $settings['telegram_notify_enable'] == '1' && !empty($settings['telegram_bot_token']) && !empty($settings['telegram_chat_id'])) {
$bot_token = $settings['telegram_bot_token'];
$chat_id = $settings['telegram_chat_id'];
$url = "https://api.telegram.org/bot{$bot_token}/sendMessage";
$post_fields = array(
'chat_id' => $chat_id,
'text' => $message
);
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $post_fields);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_exec($ch);
curl_close($ch);
}
}
function send_test_notification($target = 'all') {
require_once(__DIR__."/settings.php");
$settings = get_app_settings();
$message = "🔔 ทดสอบระบบแจ้งเตือน HOSxP Web Service\n";
$message .= "ระบบของคุณสามารถส่งการแจ้งเตือนได้ตามปกติ!\n";
$message .= "เวลา: " . date("Y-m-d H:i:s");
$results = [];
// Line Notify
if (($target === 'all' || $target === 'line') && !empty($settings['line_notify_enable']) && $settings['line_notify_enable'] == '1' && !empty($settings['line_notify_token'])) {
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "https://notify-api.line.me/api/notify");
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, "message=" . urlencode($message));
$headers = array('Content-type: application/x-www-form-urlencoded', 'Authorization: Bearer ' . $settings['line_notify_token']);
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$res = curl_exec($ch);
$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
$results['line'] = ($http_code == 200);
}
// Telegram Notify
if (($target === 'all' || $target === 'telegram') && !empty($settings['telegram_notify_enable']) && $settings['telegram_notify_enable'] == '1' && !empty($settings['telegram_bot_token']) && !empty($settings['telegram_chat_id'])) {
$bot_token = $settings['telegram_bot_token'];
$chat_id = $settings['telegram_chat_id'];
$url = "https://api.telegram.org/bot{$bot_token}/sendMessage";
$post_fields = array(
'chat_id' => $chat_id,
'text' => $message
);
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $post_fields);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$res = curl_exec($ch);
$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
$results['telegram'] = ($http_code == 200);
}
return $results;
}
?>