如何为PHP项目做代码审计?

wen PHP项目 7

本文目录导读:

如何为PHP项目做代码审计?

  1. 审计前的准备工作
  2. 核心审计清单:以漏洞类型为导向
  3. 实战审计步骤
  4. 最实用的工具组合
  5. 常见误区
  6. 输出审计报告

为PHP项目做代码审计是一项系统性的工作,需要结合自动化工具手动审查,以下是针对PHP项目安全审计的完整方法论,涵盖常见漏洞、检测技巧及最佳实践:


审计前的准备工作

  1. 环境搭建:

    • 本地化部署: 将PHP项目及其依赖(如MySQL、Redis、Composer包)完整运行在本地或隔离的容器中。
    • 开启错误报告:php.ini 中设置 display_errors = On 并设置 error_reporting = E_ALL,便于发现潜在错误。
    • 启用Xdebug: 用于单步调试和变量跟踪。
  2. 工具准备:

    • 静态分析工具:
      • RIPS(已停止维护但经典): 适合PHP历史项目。
      • Phan / PHPStan / Psalm: 代码质量检查,也能发现部分类型相关漏洞。
      • SonarQube + PHP插件: 全面代码质量和安全问题扫描。
      • Semgrep: 规则驱动的轻量级静态分析。
    • 依赖检查工具: composer audit(用于发现已知漏洞的第三方包)、SnykOWASP Dependency-Check
    • IDE/编辑器集成: PhpStorm(内置代码检查和PSR规范)、VS Code + PHP Intelephense。
  3. 获取代码结构:

    • 理解项目使用的框架(Laravel、ThinkPHP、Symfony、Yii等)或原生开发模式。
    • 识别入口文件(index.phprouter.phppublic/)。
    • 查看依赖管理文件(composer.jsonpackage.jsoncomposer.lock)。

核心审计清单:以漏洞类型为导向

SQL注入

  • 检查点:
    • 原生SQL写法(最危险): mysqli_query("SELECT * FROM users WHERE id = " . $_GET['id'])
      • 修复: 强制使用参数化查询(PDO的prepare / execute 或 MySQLi的 bind_param)。
    • ORM框架的误用:
      • Laravel的 DB::select("select * from users where id = ?", [$id])(安全)。
      • 但如果是 DB::select("select * from users where id = $id")(不安全)。
      • ThinkPHP的 where('id', $id)(一般安全) vs where('id = ' . $id)(不安全)。
    • 存储过程调用: 检查是否对传入参数进行了转义。
    • 盲注检测: 观察 timesleep 函数是否出现在SQL查询逻辑中。

跨站脚本攻击(XSS)

  • 检查点:
    • 输出点: echo $_GET['name']print_r<?=$var?> 且未使用 htmlspecialchars()htmlentities() 或模板引擎转义。
    • 上下文陷阱:
      • HTML上下文: 使用 htmlspecialchars($var, ENT_QUOTES, 'UTF-8')
      • HTML属性上下文: <a href="<?=$url?>"> 需额外处理单/双引号转义。
      • JavaScript上下文: <script>var x = '<?=$var?>';</script> 极易被注入,应使用JSON编码(json_encode)。
      • CSS/URL上下文: 谨慎拼接用户输入。
    • 存储型XSS: 用户输入写入数据库后未转义直接显示(如评论、用户名)。
    • 富文本XSS: 使用HTMLPurifier等白名单过滤器处理。

文件包含漏洞(LFI/RFI)

  • 检查点:
    • include($_GET['page'])require_once "files/" . $user_input
    • 使用 file_get_contents()fopen()include_once 直接拼接用户路径。
    • 危险函数: includeinclude_oncerequirerequire_oncefile_get_contentsfopenfread
    • 检测伪协议: 代码是否允许 php://inputphp://filterzip://phar:// 等。
  • 修复: 限制文件路径为白名单,或使用 realpath() 规范化路径。

文件上传漏洞

  • 检查点:
    • 文件类型检测: 仅校验 $_FILES['file']['type'](客户端MIME,可篡改)而不对服务端 getimagesize()exif_imagetype() 验证。
    • 黑名单绕过: 仅拦截 .php.php5.phtml,但允许 .pht.php7.shtml.phar.inc 等。
    • 上传路径: 是否允许覆盖系统文件(如 ../config.php)。
    • 二次渲染: 图片文件尾部隐藏PHP代码(可绕过getimagesize())。
    • WebShell检测: 检查上传后文件是否可访问。
  • 修复: 使用白名单扩展名、重命名文件(UUID)、将文件放在web根目录外或限制执行权限。

命令注入(OS Command Injection)

  • 检查点:
    • exec("ping -c 4 " . $_GET['ip'])(直接拼接双引号、反引号、、、)。
    • system()passthru()shell_exec()proc_open()popen() 等函数。
    • PHP内部命令执行: eval()assert()preg_replace('/e/')(已废弃)、create_function()array_map() 带用户回调。
  • 修复: 对输入进行严格白名单校验,或使用 escapeshellarg() / escapeshellcmd()

逻辑漏洞 & 访问控制

  • 检查点:
    • 权限缺失: 后台/管理页面是否允许未登录或低权限用户访问(如 admin.php未做if (isAdmin())检查)。
    • IDOR(不安全的直接对象引用): delete.php?id=123,用户可遍历ID删除他人数据(检查$user->id == $owner_id)。
    • CRSF(跨站请求伪造): 关键操作(改密、转账)是否没有 TokenReferer 验证。
    • 会话管理: session_id 是否可预测,session 是否在 https 下设置了 SecureHttpOnly 标志。
    • 密码安全: 使用 md5()sha1() 而不加 salt

不安全的配置

  • php.ini:
    • display_errors = On(生产环境应关闭)。
    • allow_url_include = On(应关闭,防止RFI)。
    • magic_quotes_gpc = On(已废弃,不应依赖)。
    • session.use_strict_mode = 0(应开启)。
  • 框架/中间件:
    • debug 模式在生产环境开启。
    • .env 文件未添加到 .gitignore 且暴露了数据库密码。
    • log 文件(如 storage/logs/laravel.log)可被直接访问。

实战审计步骤

  1. 全局依赖审计:
    • 运行 composer audit 检查 composer.lock 中的已知漏洞。
  2. 入口文件与路由审计:
    • index.php 或框架路由文件(如 routes/web.php)开始,追踪用户数据的流向。
  3. 敏感函数搜索:
    • 使用grep或代码分析工具搜索以下危险函数(按优先级):
      • evalpreg_replace(带/e)、assertcreate_function(命令执行)
      • includerequirefile_get_contents(文件包含)
      • shell_execexecsystempassthrupopen(命令执行)
      • mysql_querymysqli_queryPDO::query(无预处理)
      • unserialize(反序列化漏洞)
      • header(未过滤回车换行注入)
  4. 数据流追踪:
    • 输入: 所有 $_GET$_POST$_COOKIE$_FILES$_SERVER$_REQUEST
    • 传递: 这些变量如何经过函数处理?是否被 json_decodebase64_decodeunserialize 处理?
    • 输出: 执行 echoprint<?= 的位置。
  5. 自动化工具扫描:
    • 使用 Semgrep(强烈推荐) 运行规则(如 p/php-security)。
    • RIPSSonarQube 生成报告,然后手动验证真/假漏洞。
  6. 手动深入审查:
    • 针对高风险的SQL/XSS/文件上传区域,逐行阅读逻辑。
    • 检查框架自定义过滤器(如Laravel中定制的 Request 规则)是否覆盖了所有场景。

最实用的工具组合

阶段 工具 用途
静态分析 Semgrep 自定义规则,精准发现模式匹配漏洞
静态分析 PhpStorm + Intelephense IDE实时提示、类型推断、超简化数据流追踪
已知漏洞 composer audit 快速检查第三方库漏洞
Web扫描 Burp Suite 手动拦截修改请求、重放测试、SQL/XSS盲注测试
环境检测 PHPStan (level 5+) 检测未定义变量、类型混淆(可能导致逻辑漏洞)

常见误区

  1. 依赖框架过滤器: 不要认为Laravel的 csrfvalidation 完全阻止了XSS,框架只过滤用户输入但不会自动对输出做HTML转义。
  2. 过度信任 addslashes() 在GBK编码下,addslashes() 绕过经典案例(宽字节注入)。
  3. 忽视 unserialize() 反序列化漏洞在PHP中非常普遍,检查所有使用 unserialize 的地方。
  4. 忽略文件上传的二次利用: 上传一张图片后,文件名、路径信息可能被用于其他漏洞(如包含、移动、重命名)。

输出审计报告

一份标准的PHP审计报告应包含:

  1. 漏洞摘要: 按严重程度(Critical/High/Medium/Low)分类。
  2. 详细描述: 问题位置、代码片段、测试步骤(如复制Burp请求)。
  3. 危害分析: 此漏洞可能造成的影响(数据泄露、服务器沦陷等)。
  4. 修复建议: 具体代码修改方案(如替换函数名、增加过滤条件)。

对PHP代码审计,静态分析帮你快速定位可疑的“危险函数”,动态测试(抓包+手动尝试) 验证漏洞是否能被利用,而业务逻辑理解才决定该漏洞的实际危害。

抱歉,评论功能暂时关闭!