PHP安全靠每次写$_GET、$_POST、mysqli_query前问“数据可信吗”来实践:SQL注入须用预处理,XSS输出必调htmlspecialchars,文件上传需白名单+内容检测+路径隔离,且不同上下文须按对应规则处理。

PHP安全不是靠背概念学会的,而是靠在每次写 $_GET、$_POST、mysqli_query 之前多问一句“这数据可信吗”练出来的。
别再拼SQL:用 prepare() 和 execute() 替代字符串拼接
几乎所有 PHP SQL 注入漏洞都源于把用户输入直接塞进查询语句。比如写 "SELECT * FROM users WHERE name = '" . $_GET['name'] . "'",攻击者输个 ' OR '1'='1 就能绕过验证。
- 必须用 PDO 或 MySQLi 的预处理机制,例如:
$stmt = $pdo->prepare('SELECT * FROM users WHERE id = ?');然后$stmt->execute([$id]); - 不要试图用
addslashes()或mysql_real_escape_string()(已废弃)来“修补”拼接逻辑——它们不解决根本问题,且在多字节编码、宽字符等场景下会失效 - 注意:预处理只保护“值”,不保护表名、字段名、ORDER BY 子句等动态结构;这些必须走白名单校验或硬编码
输出到 HTML 前,无条件调用 htmlspecialchars()
XSS 不是“用户乱输导致的意外”,而是你把没过滤的 $_POST['bio'] 直接 echo 进页面时亲手放行的。
- 只要数据要进 HTML 文本内容(比如
<div>xxx</div>),就必须用:htmlspecialchars($input, ENT_QUOTES, 'UTF-8') - 如果输出到 HTML 属性里(如
<input value="xxx">),ENT_QUOTES参数不能省,否则单引号逃逸可能破坏属性边界 - 不要依赖浏览器自动转义——Chrome 不会帮你防
<script>,strip_tags()也拦不住<img src=x onerror=alert(1)>
文件上传必须做三件事:类型白名单 + 内容检测 + 路径隔离
仅靠检查 $_FILES['file']['type'] 或扩展名后缀(如 .jpg)完全不可信——MIME 类型由客户端伪造,后缀可被重命名绕过。
立即学习“PHP免费学习笔记(深入)”;
- 第一步:用
finfo_file()检查文件真实内容类型,只允许白名单中的类型(如image/jpeg、image/png) - 第二步:重命名文件(如用
uniqid() . '.jpg'),绝不用原始$_FILES['file']['name'] - 第三步:上传目录禁止执行 PHP,例如 Apache 中配置
<Files "*.php"> Require all denied</Files>,或把文件存到 Web 根目录外
真正容易被忽略的点是上下文切换:同一段用户输入,在 SQL 查询里要参数化,在 HTML 输出里要 htmlspecialchars,在 URL 中要 rawurlencode,在 JavaScript 字符串里得用 JSON 编码再输出——没有“一招通用”,只有“在哪用,就按哪的规则处理”。



















