PHP 怎么安全基线

wen PHP项目 1

PHP 安全基线加固指南

PHP 核心配置安全

基础安全配置(php.ini)

;========== 基本信息隐藏 ==========
expose_php = Off                    ; 隐藏PHP版本号
display_errors = Off                ; 不显示错误信息
log_errors = On                     ; 记录错误日志
error_reporting = E_ALL             ; 记录所有错误
;========== 资源限制 ==========
max_execution_time = 30             ; 最大执行时间(秒)
max_input_time = 60                 ; 输入解析时间
memory_limit = 128M                 ; 内存限制
post_max_size = 8M                  ; POST数据限制
upload_max_filesize = 2M            ; 上传文件大小
;========== 危险函数禁用 ==========
disable_functions = exec,system,passthru,shell_exec,proc_open,popen,curl_exec,curl_multi_exec,show_source,highlight_file,dl,proc_get_status,proc_close,proc_terminate,proc_nice
;========== 文件系统安全 ==========
allow_url_fopen = Off               ; 禁用远程文件打开
allow_url_include = Off             ; 禁止远程文件包含
open_basedir = /var/www/html:/tmp    ; 限定访问目录

会话安全配置

;========== Session安全 ==========
session.cookie_httponly = 1         ; 禁止JavaScript访问Cookie
session.cookie_secure = 1           ; 仅通过HTTPS传输
session.use_only_cookies = 1        ; 仅使用Cookie
session.name = PHPSESSID            ; 会话名称自定义
session.gc_maxlifetime = 1800       ; 会话过期时间(30分钟)
session.cookie_lifetime = 0         ; Cookie生命周期(浏览器关闭即失效)
session.sid_length = 48             ; 会话ID长度
session.sid_bits_per_character = 6  ; 会话ID复杂度
session.use_strict_mode = 1         ; 严格模式,拒绝未初始化的会话ID

文件上传安全

;========== 文件上传 ==========
file_uploads = On
upload_tmp_dir = /tmp/php_uploads    ; 上传临时目录(需要正确权限)
upload_max_filesize = 2M
max_file_uploads = 20

代码层面安全

输入验证与过滤

<?php
// 使用filter_var进行输入验证
$email = filter_var($_POST['email'], FILTER_VALIDATE_EMAIL);
if (!$email) {
    throw new Exception('非法邮箱格式');
}
// 使用PHP 8+的string类型约束
function processInput(string $input): string {
    // 参数类型强制转换
    return trim(htmlspecialchars($input, ENT_QUOTES, 'UTF-8'));
}
// 验证整数
$userId = filter_input(INPUT_GET, 'id', FILTER_VALIDATE_INT);
if ($userId === false || $userId === null) {
    throw new Exception('非法用户ID');
}
?>

SQL注入防护(重点)

<?php
// 使用PDO预处理语句(推荐)
$pdo = new PDO('mysql:host=localhost;dbname=test;charset=utf8mb4', $user, $pass);
$pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$stmt = $pdo->prepare('SELECT * FROM users WHERE email = :email AND status = :status');
$stmt->execute([
    ':email' => $email,
    ':status' => 'active'
]);
$result = $stmt->fetchAll(PDO::FETCH_ASSOC);
?>

XSS防护

<?php
// 输出编码函数
function escapeOutput($data) {
    return htmlspecialchars($data, ENT_QUOTES, 'UTF-8');
}
// 使用模板引擎自动转义(如Twig)
// 输出示例
echo escapeOutput($userInput);
// JSON输出时
header('Content-Type: application/json');
echo json_encode($data, JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_QUOT | JSON_HEX_AMP);
?>

CSRF防护

<?php
// 生成CSRF Token
function generateCsrfToken() {
    if (!isset($_SESSION['csrf_token'])) {
        $_SESSION['csrf_token'] = bin2hex(random_bytes(32));
    }
    return $_SESSION['csrf_token'];
}
// 验证CSRF Token
function validateCsrfToken($token) {
    return hash_equals($_SESSION['csrf_token'], $token);
}
// 在表单中加入Token
$csrfToken = generateCsrfToken();
echo '<input type="hidden" name="csrf_token" value="' . $csrfToken . '">';
// 验证请求
if (!validateCsrfToken($_POST['csrf_token'] ?? '')) {
    http_response_code(403);
    exit('CSRF Token验证失败');
}
?>

文件上传安全

<?php
// 文件上传安全处理
function secureUpload() {
    $allowedMimeTypes = ['image/jpeg', 'image/png', 'image/gif'];
    $allowedExtensions = ['jpg', 'jpeg', 'png', 'gif'];
    $maxSize = 2 * 1024 * 1024; // 2MB
    if ($_FILES['file']['error'] !== UPLOAD_ERR_OK) {
        throw new Exception('上传失败');
    }
    // 检查文件大小
    if ($_FILES['file']['size'] > $maxSize) {
        throw new Exception('文件过大');
    }
    // 检查MIME类型(仅作为辅助验证)
    $finfo = finfo_open(FILEINFO_MIME_TYPE);
    $mimeType = finfo_file($finfo, $_FILES['file']['tmp_name']);
    if (!in_array($mimeType, $allowedMimeTypes)) {
        throw new Exception('文件类型不允许');
    }
    // 检查文件内容真实性
    $imageInfo = getimagesize($_FILES['file']['tmp_name']);
    if ($imageInfo === false) {
        throw new Exception('文件不是有效的图片');
    }
    // 检查扩展名
    $extension = strtolower(pathinfo($_FILES['file']['name'], PATHINFO_EXTENSION));
    if (!in_array($extension, $allowedExtensions)) {
        throw new Exception('文件扩展名不允许');
    }
    // 重命名文件为随机名称
    $newFileName = bin2hex(random_bytes(16)) . '.' . $extension;
    $uploadPath = '/path/to/upload/' . $newFileName;
    if (!move_uploaded_file($_FILES['file']['tmp_name'], $uploadPath)) {
        throw new Exception('文件保存失败');
    }
    return $uploadPath;
}
?>

敏感信息保护

<?php
// 密码加密
$hashedPassword = password_hash($password, PASSWORD_DEFAULT); // 使用bcrypt
// 验证密码
if (password_verify($inputPassword, $hashedPassword)) {
    // 密码正确
}
// Token生成
function generateToken() {
    return bin2hex(random_bytes(32)); // 64位字符的随机Token
}
// 安全响应头
header('X-Content-Type-Options: nosniff');
header('X-Frame-Options: SAMEORIGIN');
header('X-XSS-Protection: 1; mode=block');
header('Strict-Transport-Security: max-age=31536000');
header('Content-Security-Policy: default-src \'self\'');
?>

日志记录

<?php
// 安全审计日志配置
class SecurityLogger {
    private $logFile;
    public function __construct($logFile) {
        $this->logFile = $logFile;
    }
    public function logSecurityEvent($event, $data = []) {
        $logEntry = [
            'timestamp' => date('Y-m-d H:i:s'),
            'event' => $event,
            'data' => $data,
            'ip' => $_SERVER['REMOTE_ADDR'] ?? 'unknown'
        ];
        $json = json_encode($logEntry);
        file_put_contents($this->logFile, $json . PHP_EOL, FILE_APPEND);
    }
}
?>

部署安全

Web服务器配置(Apache/Nginx)

# Nginx安全配置示例
server {
    # 禁止访问隐藏文件
    location ~ /\.(?!well-known).* {
        deny all;
    }
    # PHP处理配置
    location ~ \.php$ {
        include fastcgi_params;
        fastcgi_pass unix:/var/run/php-fpm.sock;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        # 限制请求大小
        client_max_body_size 8M;
    }
    # 缓存配置(可选)
    location ~* \.(jpg|jpeg|png|gif|ico|css|js)$ {
        expires 30d;
        add_header Cache-Control "public, max-age=2592000";
    }
    # 安全头部
    add_header X-Frame-Options "SAMEORIGIN" always;
    add_header X-Content-Type-Options "nosniff" always;
    add_header Referrer-Policy "strict-origin-when-cross-origin" always;
}

目录权限配置

# 安全文件权限
find /var/www/html -type f -exec chmod 644 {} \;
find /var/www/html -type d -exec chmod 755 {} \;
# 配置文件权限(重要配置文件)
chmod 600 /var/www/html/config/database.php
# 上传目录权限
mkdir -p /var/www/html/uploads
chmod 755 /var/www/html/uploads
chown www-data:www-data /var/www/html/uploads
# 日志目录权限
chmod 640 /var/www/html/logs/security.log
chown www-data:www-data /var/www/html/logs

运行时监控

安全监控脚本

<?php
// 异常行为检测
class SecurityMonitor {
    private $logFile = '/var/log/php_security.log';
    public function __construct() {
        $this->logFile = ini_get('error_log') ?: $this->logFile;
    }
    public function monitor() {
        // 检测异常请求
        $requestRate = $this->getRequestRate($_SERVER['REMOTE_ADDR'] ?? '');
        if ($requestRate > 100) {
            $this->logSecurityAlert('HIGH_REQUEST_RATE', ['ip' => $_SERVER['REMOTE_ADDR']]);
        }
        // 检测XSS攻击模式
        $userAgent = $_SERVER['HTTP_USER_AGENT'] ?? '';
        if (preg_match('/<script|javascript:|onerror|onload/i', $userAgent)) {
            $this->logSecurityAlert('XSS_ATTEMPT', ['ip' => $_SERVER['REMOTE_ADDR']]);
        }
    }
    private function getRequestRate($ip) {
        // 示例:从Redis/DB获取请求计数
        // return $rate;
        return 0;
    }
    private function logSecurityAlert($type, $data) {
        $entry = [
            'timestamp' => date('Y-m-d H:i:s'),
            'type' => $type,
            'data' => $data
        ];
        file_put_contents($this->logFile, json_encode($entry) . PHP_EOL, FILE_APPEND);
    }
}
?>

安全基线检查清单

检查项 要求 检查命令/方法
PHP版本 >= 8.0,及时更新补丁 php -v
错误显示 display_errors = Off php -i | grep display_errors
危险函数 已禁用 php -i | grep disable_functions
目录访问 配置open_basedir php -i | grep open_basedir
会话安全 session.cookie_httponly = 1 php -i | grep session.cookie
上传安全 限制大小和类型 php -i | grep upload_max
远程文件 allow_url_include = Off php -i | grep allow_url
文件权限 目录755,文件644 ls -la
Web容器 隐藏版本信息 检查响应头
依赖库 及时更新 composer audit

持续安全措施

  1. 定期安全审计:使用 WeDetect 等扫描工具进行代码审计
  2. 依赖更新:使用 composer audit 检查依赖漏洞
  3. 日志分析:定期分析安全日志,发现异常行为
  4. 安全测试:使用 OWASP ZAP 进行渗透测试
  5. 备份策略:定期备份代码和数据库
  6. Web Application Firewall (WAF):部署WAF进行应用层防护

这个安全基线提供了完整的PHP应用加固方案,建议根据实际环境调整参数,并定期更新安全策略。

PHP 怎么安全基线

抱歉,评论功能暂时关闭!