1. SQL 注入防护
措施:
// 使用预处理语句$stmt = $conn->prepare("SELECT * FROM articles WHERE id = ?");$stmt->bind_param("i", $id);$stmt->execute();// 或使用 real_escape_string$username = $conn->real_escape_string($_POST['username']);
实现位置:
2. XSS 防护
措施:
// 输出转义functione($str) {returnhtmlspecialchars($str ?? '', ENT_QUOTES, 'UTF-8');}// 使用echoe($userInput);
3. CSRF 防护
措施:
// 生成 Tokenif (empty($_SESSION['csrf_token'])) {$_SESSION['csrf_token'] = bin2hex(random_bytes(32));}// 表单中添加<input type="hidden" name="csrf_token" value="<?php echo $_SESSION['csrf_token']; ?>">// 验证 Tokenif (!hash_equals($_SESSION['csrf_token'], $_POST['csrf_token'])) {die('CSRF 验证失败');}
实现位置:
4. 密码安全
措施:
// 密码加密(bcrypt)$hashedPassword = password_hash($password, PASSWORD_DEFAULT, ['cost' => 12]);// 密码验证if (password_verify($password, $hashedPassword)) {// 验证成功}// 检查是否需要重新哈希if (password_needs_rehash($hash, PASSWORD_DEFAULT, ['cost' => 12])) {// 重新哈希}
实现位置:
5. Session 安全
措施:
// Session 配置ini_set('session.cookie_httponly', 1); // 禁止 JS 访问 Cookieini_set('session.cookie_secure', 0); // HTTPS 时为 1ini_set('session.use_strict_mode', 1); // 防止会话固定ini_set('session.cookie_samesite', 'Strict'); // 防止 CSRFini_set('session.gc_maxlifetime', 3600); // 1 小时过期// 定期重新生成 Session IDsession_regenerate_id(true);
实现位置:
6. 登录失败限制
措施:
// 记录失败尝试functionrecordLoginAttempt($ip, $username, $success) {if (!$success) {// 记录失败$conn->query("INSERT INTO login_attempts (ip, username, attempt_time) VALUES ('$ip', '$username', NOW())");// 检查是否超过限制(5 次/15 分钟)$result = $conn->query("SELECT COUNT(*) as count FROM login_attempts WHERE ip = '$ip' AND attempt_time > DATE_SUB(NOW(), INTERVAL 15 MINUTE)");if ($result->fetch_assoc()['count'] >= 5) {return ['success' => false, 'message' => '尝试次数过多,请 15 分钟后再试']; } }}
实现位置:
7. 文件上传安全
措施:
functionuploadFile($file, $options = []) {// 检查文件类型$ext = strtolower(pathinfo($file['name'], PATHINFO_EXTENSION));$allowedTypes = ['jpg', 'jpeg', 'png', 'gif', 'webp'];if (!in_array($ext, $allowedTypes)) {return ['success' => false, 'message' => '不支持的文件类型']; }// 验证 MIME 类型$finfo = finfo_open(FILEINFO_MIME_TYPE);$mimeType = finfo_file($finfo, $file['tmp_name']);$allowedMimes = ['image/jpeg', 'image/png', 'image/gif', 'image/webp'];if (!in_array($mimeType, $allowedMimes)) {return ['success' => false, 'message' => '文件类型不匹配']; }// 生成安全文件名$newName = bin2hex(random_bytes(16)) . '.' . $ext;// 移动文件move_uploaded_file($file['tmp_name'], $destination);}
实现位置:
8. 目录权限控制
措施:
# 目录权限cache/ 755 # 可写logs/ 755 # 可写uploads/ 755 # 可写# 文件权限includes/config.php 640 # 仅所有者可写*.php 644 # 只读
敏感文件保护:
# .htaccess(Apache)<FilesMatch "\.(sql|log|ini|sh|py)$">Orderallow,denyDeny from all</FilesMatch># Nginx 配置location ~ \.(sql|log|ini|sh|py)$ {denyall;}
9. 错误处理
措施:
// 生产环境关闭错误显示ini_set('display_errors', 0);ini_set('log_errors', 1);ini_set('error_log', '/path/to/error.log');// 自定义错误处理set_error_handler(function($errno, $errstr, $errfile, $errline) {error_log("[$errno] $errstr in $errfile on line $errline");returntrue;});// 自定义异常处理set_exception_handler(function($exception) {error_log("Uncaught exception: " . $exception->getMessage());http_response_code(500);echo'服务器错误,请稍后重试';exit;});
实现位置:
10. 后台目录配置化
措施:
// includes/config.phpdefine('ADMIN_DIR', 'manage'); // 可修改为任何名字// 使用<a href="/<?php echo ADMIN_DIR; ?>/dashboard.php">面板</a>
好处: