生产环境必须关闭app_debug,否则错误页、sql日志、变量dump会直接暴露数据库密码、表结构、控制器路径和服务器文件系统层级;需同步设show_error_msg=false、清空trace配置、限制runtime目录权限。

开启 DebugBar 后生产环境没关,风险不是“可能泄露”,而是默认就会暴露核心敏感信息。
ThinkPHP 5.1 的 DebugBar(即页面底部调试工具栏)依赖 APP_DEBUG = true 才能加载。一旦开启,它不只是显示执行时间或 SQL 数量,而是会主动触发一整套调试基础设施,直接把服务器内部结构推到前端。
错误页直接暴露数据库密码和表结构
当路由出错、SQL 报错或模板解析失败时,页面会完整显示:
- 数据库连接配置(含
hostname、username、password、database) - 所有执行过的 SQL 语句及绑定参数(比如
WHERE id = ?后面跟着真实的123) - 控制器类的绝对路径(如
/www/wwwroot/app/controller/User.php) - 服务器操作系统类型、PHP 版本、扩展列表
日志文件变成攻击地图runtime/log/ 下生成的 .log 文件会记录:
- 每次请求的完整 GET/POST 参数(含登录密码、token、密钥)
- 模板编译失败时的原始 HTML 片段(含注释、隐藏字段名)
- PDO 预处理过程中的内存地址和驱动状态
Trace 面板即使隐藏也仍在运行
就算你在 config/app.php 里设了 'show_page_trace' => false,只要 APP_DEBUG = true,Trace 数据仍在内存中生成并缓存。攻击者可通过构造特定 URL(如加 ?t=123456789 触发缓存键碰撞)或利用未授权接口读取 trace 缓存内容。
第三方中间件或扩展可能放大风险
例如用了旧版 JWT 验证中间件,它在 debug 模式下会把 $payload 原样 dump 到 trace 区;或者自定义的日志钩子,在 App::event('log') 中把 $data 全量写入 trace —— 这些都不会因“没开面板”而停止。
怎么确认真关了
别只看配置文件,实测三步:
- 访问一个不存在的路径(如
/xyz),响应必须是简洁 404 页面,不能有堆栈、SQL 或变量 dump - 在控制器里写
undefined_function();,页面只能显示“页面错误!请稍后再试~”,不能出现Call to undefined function及文件行号 - 运行
php -r "var_dump(\think\facade\App::debug());",输出必须是bool(false),而不是string(5) "false"
关掉 APP_DEBUG 是底线,不是终点。还要同步检查:
-
show_error_msg是否设为false -
trace配置是否清空(留空或注释都会 fallback 到默认驱动) -
runtime/目录权限是否限制为644且 Web 无法直接访问











