应用层报错泄露数据库版本、路径信息,统一错误页面
当网站开启调试模式或默认错误展示后,数据库版本、脚本路径、表名甚至配置片段都可能直接暴露给访客。
这类问题在安全扫描中常被标记为“信息泄露”,其实不需要改业务代码,通过统一错误页面和关闭调试开关就能解决。
下面按新手可操作的方式说明如何定位泄露点、隐藏敏感信息,并验证最终效果。
先判断应用层报错从哪里来
在动手之前,先确认报错是来自 Web 服务器(如 Nginx)还是应用框架(如 ThinkPHP、Laravel、Spring Boot)。
最简单的办法是直接访问一个不存在的路由或故意触发异常,观察页面内容:
- 如果页面显示 Nginx 错误码和 Nginx 版本,说明是 Web 服务器层泄露。
- 如果显示数据库连接错误、SQL 语句、框架版本,说明是应用层捕获异常后未做统一处理。
- 如果显示 PHP 文件绝对路径,比如
/www/wwwroot/site/config.php,通常是display_errors开启,或框架处于调试模式。
多数情况下,数据库版本和路径信息同时出现,是因为应用层把异常堆栈直接输出到浏览器。
下面分别处理。
关闭调试并开启统一错误页面:PHP 示例
如果网站使用 PHP 开发,先修改 php.ini 里的两个关键项:
display_errors = Off
log_errors = On
error_log = /www/wwwroot/your_site/logs/php_error.log
display_errors = Off 表示不让错误直接显示到用户浏览器;log_errors = On 会将这些错误记录到指定日志,方便你后续排查。
改完记得重启 PHP-FPM:
# 宝塔面板中可重载 PHP 服务
systemctl reload php-fpm
接着在项目入口文件(如 index.php)顶部设置统一异常处理,简单示例:
set_exception_handler(function ($e) {
http_response_code(500);
echo '系统繁忙,请稍后重试';
error_log($e->getMessage());
});
这样用户看到的只是通用错误页,详细异常信息只写入服务器日志。
框架级统一错误页:以 ThinkPHP 和 Laravel 为例
如果项目使用主流框架,不需要自己写异常处理函数,框架已经预留了统一错误页机制。
ThinkPHP 6 中,
在 config/app.php 将 'show_error_msg' => true,
同时把 app_debug 设为 false。show_error_msg 开启后,
框架会展示简洁的官方错误页,
不再输出异常堆栈。
Laravel 中,把 .env 的 APP_DEBUG 设为 false,系统会渲染 resources/views/errors/500.blade.php 等模板文件。
你可以自定义该文件内容,比如显示“服务器开小差了”,不会泄露任何数据库版本或路径。
如果你的项目是 Java Spring Boot,
把 application.yml 里 server.error.include-message 设为 never,
并设置 server.error.whitelabel.enabled=false,
然后自定义 /error 控制器页面。
统一错误页面在 Nginx 层面的兜底
虽然应用层已经处理,但 Nginx 在遇到 401、403、404、500 等状态码时仍可能输出默认页面。
建议在站点配置文件中添加自定义错误页:
server {
listen 80;
server_name example.com;
# 关键:关闭 Nginx 版本号显示
server_tokens off;
error_page 401 /error_401.html;
error_page 403 /error_403.html;
error_page 404 /error_404.html;
error_page 500 502 503 504 /error_50x.html;
location = /error_401.html {
root /www/wwwroot/your_site/errors;
internal;
}
location = /error_403.html {
root /www/wwwroot/your_site/errors;
internal;
}
location = /error_404.html {
root /www/wwwroot/your_site/errors;
internal;
}
location = /error_50x.html {
root /www/wwwroot/your_site/errors;
internal;
}
}
server_tokens off 用于隐藏 Nginx 版本号,避免服务器版本信息直接暴露。
先创建 /www/wwwroot/your_site/errors 目录,放入对应的静态 HTML 文件,然后执行 nginx -t 检查配置,再 /etc/init.d/nginx reload 或 systemctl reload nginx 生效。
避坑清单:这些设置经常被忽略
- 只调 Nginx 不管框架:应用层报错仍会输出数据库信息。必须先把框架调试模式关闭。
- 改了配置却没重启服务:PHP 和 Nginx 的配置都需要重启或重载才能生效。
- 日志目录不存在:如果指定了
error_log但目录未创建,PHP 可能无法写日志。记得给目录授予写权限。 - 错误页面本身泄露路径:自定义错误页中不要包含完整绝对路径,建议使用相对链接。
- 404 页面选择不当:不要让 404 页面自动跳转到首页,这会影响用户定位错误资源。直接在错误页写“页面不存在”即可。
另外注意,统一错误页不等于 401 页面单独设计。
401 状态码对应未认证访问,可以在应用层或 Nginx 层单独定制,避免把 401 与 500 混用。
验证泄露是否真正修复
配置完成后,按下面几步验证效果:
- 触发数据库错误:临时访问一个错误的数据库连接或执行一条错误 SQL,观察浏览器是否只显示通用错误页。
- 查看响应头:按
F12打开浏览器开发者工具,查看网络响应头,确认没有X-Powered-By: PHP/x.x或Server: nginx/x.x.x字段。若有,继续关闭expose_php和server_tokens。 - 访问不存在的路径:确认页面状态码是 404,且内容是你自定义的 404 页面。
- 查看日志文件:确认错误详情确实写入了服务器日志,但未出现在页面上。
完成上述操作后,数据库版本和路径信息不会再直接暴露给访客。
以后遇到安全扫描提示类似漏洞,优先检查 display_errors、APP_DEBUG 和框架错误处理配置,往往比反复修改权限更有效。