mysql报错泄露表名、字段名、数据库版本及服务器路径,为报错注入提供关键线索;php需禁用mysqli/pdo错误透出并关闭display_errors,应用层须try/catch拦截,不返回任何错误详情。

生产环境必须关闭 SQL 错误回显,因为默认错误信息会直接暴露表名、字段名、数据库版本甚至服务器路径——这些正是攻击者发起报错注入(Error-Based Injection)的跳板。
MySQL 报错泄露什么信息?
典型错误如 Unknown column 'password' in 'field list' 或 Access denied for user 'webapp'@'10.0.2.5',已经把关键线索全送出去了:
-
password字段存在 → 猜中用户表结构 -
webapp账号名 + IP → 缩小爆破/横向移动范围 - 若用
extractvalue()触发报错,还能把database()、table_name直接打在错误提示里
PHP 层怎么关掉 mysqli/PDO 的错误透出?
只改 PHP 配置不够,驱动层必须同步设为静默模式:
- mysqli:运行时禁用严格模式,
mysqli_report(MYSQLI_REPORT_OFF);别用MYSQLI_REPORT_STRICT(它会让mysqli_error()返回完整 SQL) - PDO:创建实例后立刻设置
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_SILENT);绝不能用PDO::ERRMODE_EXCEPTION - 额外兜底:确保
display_errors = Off(php.ini),或运行时执行ini_set('display_errors', '0')
MySQL 服务端 log_error_verbosity 不是万能的
这个参数(MySQL 8.0.14+)只控制错误日志的详细程度,不影响返回给客户端的错误内容:
-
log_error_verbosity = 1→ 日志里不记 warning/info,但客户端照样收到Unknown column - 真正起效的是应用层拦截:所有
execute()必须包裹try/catch,捕获后只返回“操作失败”,不调用mysqli_error()或$e->getMessage() - 旧版 MySQL(
最容易被忽略的一点:ORM 框架(如 Laravel Eloquent)默认也会透出错误,除非你主动配置 APP_DEBUG=false 并重写异常渲染逻辑——框架不是免死金牌,它只是帮你写了 prepare,没帮你捂住嘴。










