Skip to content

隐藏 PHP

隐藏 PHP 的存在可以减少攻击面,使攻击者难以识别服务器技术栈。虽然隐藏 PHP 不能替代真正的安全措施,但作为纵深防御的一部分,可以有效降低自动化扫描工具的识别率。本节讲解隐藏 PHP 版本信息、文件扩展名伪装和 Web 服务器配置等技巧。

前置知识

阅读本节前,建议先了解:安全总则HTTP 头处理

基础概念

为什么要隐藏 PHP

原因说明
减少攻击面攻击者不知道使用 PHP,就不会尝试 PHP 特定的攻击
防止自动化扫描扫描工具通常基于已知签名识别技术栈
增加攻击难度攻击者需要额外时间识别目标
信息泄露防护版本信息可能暴露已知漏洞

重要提醒

隐藏 PHP 只是辅助手段,不能替代真正的安全措施。即使完全隐藏了 PHP,如果代码存在漏洞,攻击者仍然可以利用。安全来自好的编码实践,而非隐藏技术。

隐藏 PHP 版本信息

expose_php 配置

ini
; php.ini
expose_php = Off
php
<?php

// 运行时设置
ini_set('expose_php', '0');

// 移除已设置的 X-Powered-By 头
header_remove('X-Powered-By');

Web 服务器隐藏

apache
# Apache httpd.conf 或 .htaccess

# 隐藏 Apache 版本
ServerTokens Prod
ServerSignature Off

# 移除 PHP 签名
<IfModule mod_php5.c>
    php_value expose_php Off
</IfModule>
nginx
# nginx.conf

# 隐藏 Nginx 版本
server_tokens off;

# 移除 PHP 签名
fastcgi_hide_header X-Powered-By;

移除其他信息泄露头

php
<?php

declare(strict_types=1);

/**
 * 移除所有信息泄露头
 */
function removeInformationHeaders(): void
{
    // PHP 签名
    header_remove('X-Powered-By');

    // 服务器签名(可能由 Web 服务器设置)
    // header_remove('Server'); // 通常无法移除,需在 Web 服务器配置

    // 其他可能的签名
    header_remove('X-AspNet-Version');
    header_remove('X-AspNetMvc-Version');

    // 确保不在代码中添加自定义签名头
}

文件扩展名伪装

使用 .html 扩展名解析 PHP

apache
# Apache 配置
<FilesMatch "\.html$">
    SetHandler application/x-httpd-php
</FilesMatch>

# 或在 .htaccess
AddHandler application/x-httpd-php .html .htm
nginx
# Nginx 配置
location ~ \.html$ {
    fastcgi_pass unix:/var/run/php-fpm.sock;
    fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    include fastcgi_params;
}

使用自定义扩展名

apache
# 将 .phtml 解析为 PHP
<FilesMatch "\.phtml$">
    SetHandler application/x-httpd-php
</FilesMatch>

# 将 .api 解析为 PHP
<FilesMatch "\.api$">
    SetHandler application/x-httpd-php
</FilesMatch>

PHP-FPM 配置

ini
; php-fpm pool 配置
; security.limit_extensions 控制允许的 PHP 文件扩展名
security.limit_extensions = .php .html .phtml

隐藏源代码

禁止访问 .phps 和源文件

apache
# 禁止访问 .phps(高亮源代码文件)
<FilesMatch "\.phps$">
    Order allow,deny
    Deny from all
</FilesMatch>

# 禁止访问 .bak, .inc, .old 等备份文件
<FilesMatch "\.(bak|inc|old|orig|save|swp|sql|log|ini|env|yml|yaml)$">
    Order allow,deny
    Deny from all
</FilesMatch>

# 禁止访问 .git 目录
<DirectoryMatch "^\.git">
    Order allow,deny
    Deny from all
</DirectoryMatch>

# 禁止访问隐藏文件
<DirectoryMatch "^\.">
    Order allow,deny
    Deny from all
</DirectoryMatch>
nginx
# Nginx 配置
location ~ /\.(env|log|ini|sh|sql|bak|swp|git|svn|hg) {
    deny all;
    return 404;
}

location ~ \.phps$ {
    deny all;
    return 404;
}

location ~* \.(bak|inc|old|orig|save|swp|sql|log|ini|env|yml|yaml)$ {
    deny all;
    return 404;
}

自定义错误页面

避免暴露 PHP 路径

php
<?php

declare(strict_types=1);

// 错误页面不暴露 PHP 信息
// php.ini
// display_errors = Off

// 自定义 404 页面
if (!file_exists($requestedFile)) {
    http_response_code(404);
    include __DIR__ . '/errors/404.html'; // 自定义 HTML 页面
    exit;
}

// 自定义 500 页面
set_exception_handler(function (Throwable $e): void {
    error_log("{$e->getMessage()} in {$e->getFile()}:{$e->getLine()}");
    http_response_code(500);
    include __DIR__ . '/errors/500.html';
    exit;
});
apache
# Apache 自定义错误页面
ErrorDocument 404 /errors/404.html
ErrorDocument 500 /errors/500.html
ErrorDocument 403 /errors/403.html

# 确保错误页面本身是静态 HTML

入口文件隐藏

统一入口(Front Controller Pattern)

apache
# Apache URL 重写,所有请求通过 index.php 处理
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php [QSA,L]

# 禁止直接访问其他 PHP 文件
<FilesMatch "^(?!index\.php$).+\.php$">
    Order allow,deny
    Deny from all
</FilesMatch>
nginx
# Nginx 配置
location / {
    try_files $uri $uri/ /index.php?$query_string;
}

# 禁止直接访问除 index.php 外的 PHP 文件
location ~ ^/(?!index\.php$).*\.php$ {
    deny all;
    return 404;
}

注意事项

1. 安全通过隐匿

php
<?php

// "Security through obscurity" 不是真正的安全
// 攻击者可以通过以下方式识别 PHP:
// - Cookie 格式(PHPSESSID)
// - HTTP 头特征
// - 错误页面特征
// - 文件扩展名
// - 目录结构特征(/vendor/, /public/)
// - 响应时间特征

// 因此,隐藏 PHP 是辅助措施,核心安全靠编码实践

2. 反向代理安全

nginx
# 使用 Nginx 反向代理 PHP-FPM 时
# 确保移除 PHP 添加的头部
fastcgi_hide_header 'X-Powered-By';
fastcgi_hide_header 'X-Accel-Redirect';
fastcgi_hide_header 'X-Accel-Buffering';
fastcgi_hide_header 'X-Accel-Charset';
fastcgi_hide_header 'X-Accel-Expires';
fastcgi_hide_header 'X-Accel-Limit-Rate';

最佳实践

1. 信息泄露防护清单

- [x] expose_php = Off
- [x] ServerTokens Prod (Apache)
- [x] server_tokens off (Nginx)
- [x] 移除 X-Powered-By 头
- [x] display_errors = Off
- [x] 自定义错误页面
- [x] 禁止访问敏感文件类型
- [x] 禁止访问 .git 等版本控制目录
- [x] 禁止目录列表(Options -Indexes)

下一节

继续学习:保持更新

参考链接