本文目录导读:

- 输入验证与输出转义(重中之重)
- 数据库安全(防 SQL 注入)
- 会话管理与认证安全(防会话劫持)
- 文件上传安全(防 Webshell)
- 错误处理与信息泄露
- 日志与监控(响应能力)
- 基础设施与配置(加固环境)
- 代码安全习惯(开发流程)
- 依赖库与供应链安全
- 特定框架的防护(以 Laravel 为例)
- 总结优先级
在 PHP 项目中进行安全防护,核心思路是纵深防御,不能只依赖单一手段,而应从开发流程、运行时配置、代码习惯和基础设施等多个层面入手。
以下是 PHP 项目安全防护的关键措施,按重要性和紧迫性排序:
输入验证与输出转义(重中之重)
这是防止 SQL 注入、XSS(跨站脚本攻击)和命令注入 的基石。
-
输入验证(Filter Input):
- 对所有的
$_GET、$_POST、$_REQUEST、$_COOKIE数据进行验证。 - 使用“白名单”机制:明确允许什么格式,而不是排除什么格式(黑名单容易被绕过)。
- 使用
filter_var()验证邮箱、URL、整数;使用正则表达式验证复杂格式(如手机号、身份证)。 - 注意: 验证是用来判断数据是否符合业务逻辑,不要将验证作为防止注入的唯一手段,因为他可能被绕过。
- 对所有的
-
输出转义(Escape Output):
- 在将数据输出到 HTML 页面时,必须进行 HTML 实体转义。
- 使用
htmlspecialchars($data, ENT_QUOTES, 'UTF-8')将<、>、、、&转义,这是防止 XSS 的最直接手段。 - 上下文区分: 如果是输出到 JavaScript 代码块,需要用
json_encode()并加上JSON_HEX_TAG等标志;如果是输出到 URL 中,需要用urlencode()。
数据库安全(防 SQL 注入)
- 强制使用预处理语句(Prepared Statements):
- 必须使用 PDO 或 MySQLi 的预处理语句和参数绑定。严禁拼接 SQL 字符串。
- 示例(PDO):
$stmt = $pdo->prepare("SELECT * FROM users WHERE email = :email"); $stmt->execute([':email' => $email]); $user = $stmt->fetch();
- 最小权限原则:
- 数据库连接用户不要使用
root或最高权限账号。 - 为应用创建只具备
SELECT, INSERT, UPDATE, DELETE权限的账号,禁止DROP、CREATE等操作。
- 数据库连接用户不要使用
会话管理与认证安全(防会话劫持)
- 会话 ID 加固:
- 设置
session.cookie_httponly = 1(防止 JS 读取 Cookie 窃取 Session)。 - 设置
session.cookie_secure = 1(仅通过 HTTPS 传输,防止中间人窃听)。 - 设置
session.use_strict_mode = 1(拒绝未初始化的 Session ID)。
- 设置
- 防止固定会话攻击:
- 用户登录成功后(权限变更时),必须调用
session_regenerate_id(true)重新生成 Session ID,销毁旧会话。
- 用户登录成功后(权限变更时),必须调用
- 密码存储:
- 禁止使用明文或 MD5 存储密码。
- 使用
password_hash()加密,使用password_verify()验证,目前推荐使用 Bcrypt 或 Argon2 算法。
文件上传安全(防 Webshell)
这是 PHP 项目最容易被忽略的高危漏洞点。
- 白名单后缀: 只允许特定扩展名(如
jpg, png, gif, pdf),禁止直接拼接黑名单(攻击者会尝试php5, phtml, pht等变种)。 - MIME 类型检查: 使用
finfo_file()(读取文件头魔数)校验真实文件类型,不能只信表单里的$_FILES[...][“type”]。 - 重命名文件: 上传后重新生成随机文件名(如
date(‘U’).rand(1000,9999).’.jpg’),避免用户自定义文件名包含危险字符。 - 存储位置: 将上传目录置于 Web 根目录之外,通过 PHP 脚本读取并输出(加头文件),或者配置 Nginx/Apache 禁止该目录执行 PHP 代码。
错误处理与信息泄露
- 关闭生产环境错误显示:
- 在
php.ini中设置display_errors = Off,避免将路径、数据库结构等细节暴露给攻击者。 - 开启
log_errors = On,将错误记录到服务器日志中。
- 在
- 自定义错误页面: 返回 404 或 500 页面时,不要包含堆栈跟踪信息。
日志与监控(响应能力)
- 记录关键行为: 记录登录失败、密码重置、权限修改、支付等敏感操作的日志。
- 日志脱敏: 日志中不要记录明文密码或完整的信用卡号。
- 入侵检测: 监控日志中的异常请求(如大量 500 错误、POST 到静态文件目录等)。
基础设施与配置(加固环境)
- 启用 HTTPS: 全站强制跳转 HTTPS,防止数据在传输中被窃听或篡改。
- 安全头部(Headers): 在 Nginx/Apache 或 PHP 中设置:
X-Frame-Options: SAMEORIGIN(防点击劫持)。X-Content-Type-Options: nosniff(防 MIME 嗅探)。Content-Security-Policy: default-src 'self'(限制资源加载源,防 XSS)。
- 依赖管理:
- 定期更新 PHP 版本、框架(Laravel、ThinkPHP 等)及 Composer 包。
- 扫描
composer.lock中的 CVE 漏洞。
代码安全习惯(开发流程)
- 关闭危险函数: 在
php.ini的disable_functions中禁用高风险函数(视业务而定):disable_functions = exec,shell_exec,system,passthru,proc_open,popen
- CSRF(跨站请求伪造)防护:
- 对表单提交(POST 请求)校验 Token。
- 框架中自带中间件(如 Laravel 的
@csrf),直接使用。
- 避免使用反序列化用户输入: 如果必须使用
unserialize(),对传入数据做签名校验或限制allowed_classes,防止 PHP 对象注入。
依赖库与供应链安全
- 使用 Composer 时,必须锁定版本(
composer.lock)。 - 定期运行
composer audit或使用 Snyk 扫描依赖包漏洞。 - 不随意引入不知名的第三方包。
特定框架的防护(以 Laravel 为例)
- 如果你使用 Laravel,确保启用
\Illuminate\Foundation\Http\Middleware\PreventRequestsDuringMaintenance时不要暴露维护模式信息。 - 使用 Laravel 的
Validated请求特性,避免直接使用$request->all()赋值给模型(防止 Mass Assignment)。
总结优先级
如果资源有限,请务必优先执行以下三项:
- 预处理语句(PDO 预处理防 SQL 注入)。
htmlspecialchars输出转义(防 XSS)。password_hash密码加密(防脱库泄露)。
这三项能抵挡掉 80% 以上的自动化攻击,其余措施建议按需逐步完善,并配合定期安全扫描(如 OWASP ZAP)进行自查。