php安全防护需从输入、输出、数据库、文件、会话五环节持续设防:输入用filter_var验证+清洗,数据库用pdo参数绑定,输出必用htmlspecialchars(ent_quotes,'utf-8'),文件上传须校验mime、扩展名与内容并存于web根目录外,会话需启用httponly和secure标志。

PHP安全防护不是加一层“壳”就完事,而是从输入、输出、数据库、文件、会话五个关键环节持续设防。不升级到 PHP 8.3、不设 disable_functions、不强制 htmlspecialchars() 转义输出,哪怕用了预处理语句,照样可能被绕过。
用 filter_var() 做输入过滤,但别只信它
用户提交的邮箱、URL、整数等基础类型,filter_var() 是第一道防线,但它只验证格式,不清理内容。比如 FILTER_VALIDATE_EMAIL 会放过 test@example.com<script></script> 这种带 XSS 载荷的“合法邮箱”。
- 对邮箱、URL、IP 等明确结构的数据,用
filter_var($input, FILTER_VALIDATE_*)判断是否可接受 - 对自由文本(如评论、昵称),必须搭配
FILTER_SANITIZE_SPECIAL_CHARS或更严格的白名单清洗逻辑 -
$_GET['id']是数字?别只用is_numeric()—— 它会把123e4当数字,而数据库字段是INT时可能被截断或隐式转换出问题;改用filter_var($_GET['id'], FILTER_VALIDATE_INT) - 注意:
filter_input()比直接读$_POST更安全,因为它能统一处理来源和默认值
PDO 预处理语句必须绑定参数,不能拼接占位符
很多人以为写了 prepare("SELECT * FROM users WHERE id = ?") 就安全了,但如果后续用字符串拼接把变量塞进 SQL,等于白做。预处理的安全性完全依赖“参数与 SQL 结构彻底分离”。
- 正确写法:
$stmt->execute([$id]);或$stmt->bindValue(':id', $id, PDO::PARAM_INT); - 错误写法:
$sql = "SELECT * FROM users WHERE id = " . $_GET['id'];或$sql = "SELECT * FROM users WHERE id = {$_GET['id']}";—— 即使前面调用了prepare(),这种拼接也直接废掉防护 - 命名参数(
:email)比问号(?)更易维护,尤其多参数时;但注意bindParam()是引用绑定,循环中重用同一变量要小心值被覆盖 - 如果必须动态表名或字段名(如排序字段),不能用参数占位符,得走白名单校验:
in_array($_GET['sort'], ['name', 'created_at'], true)
输出 HTML 前必须用 htmlspecialchars(),且指定 ENT_QUOTES 和 UTF-8
很多 XSS 漏洞出现在“我以为这个变量是干净的”时刻。数据库里存的是原始字符串,前端 echo 出来就是攻击入口。不转义,<script></script> 就真执行了。
- 永远用:
htmlspecialchars($user_input, ENT_QUOTES, 'UTF-8')——ENT_QUOTES能转义单双引号,防止属性注入(如title="<?php echo $xss ?>") - 不要省略第三个参数
'UTF-8':PHP 默认用 ISO-8859-1,遇到中文或 emoji 可能出错或被绕过 - 在 HTML 属性里输出?必须加引号包裹,且确保
htmlspecialchars()在引号内执行,否则无效 - 富文本场景不能靠
htmlspecialchars()解决,得用HTMLPurifier或类似库做白名单过滤,而不是黑名单删标签
上传文件必须检查三要素:MIME、扩展名、内容
仅靠 $_FILES['file']['type'] 判断类型毫无意义——浏览器传什么它就报什么,攻击者改个请求头就能伪造成 image/jpeg。真正可信的只有服务端对文件内容的检测。
- 第一步:用
finfo_open(FILEINFO_MIME_TYPE)读取真实 MIME 类型,再与白名单比对(如['image/jpeg', 'image/png']) - 第二步:用
pathinfo($file['name'], PATHINFO_EXTENSION)提取扩展名,再小写后匹配白名单(注意大小写绕过) - 第三步:重命名文件,用
random_bytes(16)+bin2hex()生成随机名,**绝不保留原始文件名** - 最关键:把上传后的文件存到 Web 根目录之外(如
/var/uploads/),并通过代理脚本提供访问,避免直接执行风险
最常被忽略的一点:所有防护都依赖配置落地。比如 session.cookie_httponly=On 和 session.cookie_secure=On 必须在 php.ini 或运行时用 ini_set() 显式开启,否则 session cookie 仍可被 JS 读取或明文传输。安全不是某个函数调用,而是整个执行链路的约束闭环。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











