如何用PHP项目实现安全测试?

wen java案例 3

本文目录导读:

如何用PHP项目实现安全测试?

  1. 静态代码分析(SAST):检测代码层面的漏洞
  2. 动态分析(DAST / 运行时测试):模拟攻击行为
  3. 依赖漏洞扫描(SCA)
  4. CI/CD集成(GitHub Actions示例)
  5. 编写安全测试用例(自定义渗透测试)
  6. 常用工具对比
  7. 重要原则

在PHP项目中实现安全测试,通常需要结合静态代码分析(不运行代码)、动态分析(运行时检测)以及依赖漏洞扫描,以下是一套可落地的实践方案,从工具选择到具体命令,适合集成到CI/CD流程中。


静态代码分析(SAST):检测代码层面的漏洞

PHPStan / Psalm(找逻辑错误,非安全专用但可配置规则)

# 安装
composer require --dev phpstan/phpstan
# 运行(默认级别0,建议级别max)
vendor/bin/phpstan analyse src --level=9
  • 能发现:未定义变量、类型不匹配、死代码(可能隐藏安全风险)
  • 局限性:不直接检测SQL注入、XSS(需配合扩展规则)

PHP CodeSniffer + Security规则(编码规范与安全)

composer require --dev squizlabs/php_codesniffer
# 检测安全相关规则(如使用内置的Generic.PHP.ForbiddenFunctions)
vendor/bin/phpcs --standard=PHPCS src/ --sniffs=Generic.PHP.ForbiddenFunctions
  • 可禁止eval()extract($_GET)等危险函数

RIPS / PhpSecurity(专门的PHP安全扫描器)

工具: Progpilot (开源替代)

git clone https://github.com/designsecurity/progpilot
cd progpilot && php progpilot.phar -h
# 扫描目录
php progpilot.phar scan -f /path/to/project/src
  • 检测:SQL注入、XSS、文件包含、命令注入、反序列化等
  • 示例输出:
    [Vulnerability] SQL Injection in /var/www/src/User.php:45 (parameter: $id)

CodeQL(GitHub出品,功能强大但需搭建环境)

  • 编写QL查询规则,检测复杂的跨文件漏洞
  • 适合大型项目或安全团队使用

动态分析(DAST / 运行时测试):模拟攻击行为

OWASP ZAP(免费开源的Web安全扫描器)

# Docker方式运行(无图形界面)
docker run -u zap -p 8080:8080 -v $(pwd):/zap/wrk:rw owasp/zap2docker-stable \
  zap-full-scan.py -t http://your-php-app.local -r /zap/wrk/report.html
  • 自动爬取页面,发送恶意Payload(SQL注入、XSS、CSRF等)
  • 输出HTML报告,包含漏洞等级和修复建议

Wapiti(轻量级命令行扫描器)

# 安装
pip install wapiti3
# 扫描PHP应用
wapiti -u http://your-php-app.local --scope folder -o /tmp/wapiti_report
  • 支持GET/POST参数模糊测试,检测文件包含、命令执行

自定义Fuzz脚本(使用PHPUnit或cURL编写)

// 简单示例:用PHPUnit发送异常参数
public function testSQLInjection()
{
    $client = new GuzzleHttp\Client();
    $response = $client->get('/user?id=1\' OR 1=1--');
    $this->assertStringNotContainsString('Welcome admin', $response->getBody());
}

依赖漏洞扫描(SCA)

Composer审计(原生)

# Composer 2.4+ 自带审计功能
composer audit
  • 检查composer.lock中已知有CVE漏洞的包
  • 输出漏洞列表及受影响的版本

OWASP Dependency-Check(支持PHP的第三方工具有限)

# 使用Java版本扫描composer.lock(需额外配置)
dependency-check --scan composer.lock --format HTML
  • 注意:PHP生态的漏洞库不如Java/NPM完善,但能覆盖主流包

GitHub Dependabot / GitLab Dependency Scan

  • 在CI中启用自动检测,收到更新提醒

CI/CD集成(GitHub Actions示例)

# .github/workflows/security.yml
name: Security Scan
on: [push, pull_request]
jobs:
  security:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - name: Setup PHP
        uses: shivammathur/setup-php@v2
        with:
          php-version: '8.2'
      - name: Install dependencies
        run: composer install --no-dev
      - name: Composer audit
        run: composer audit --no-dev
      - name: Run PHPStan
        run: vendor/bin/phpstan analyse src --level=9
      - name: Run Progpilot
        run: |
          wget https://raw.githubusercontent.com/designsecurity/progpilot/main/progpilot.phar
          php progpilot.phar scan -f src
      # 可选:需要App运行中
      - name: DAST with OWASP ZAP
        run: |
          # 启动应用容器(示例)
          docker compose up -d app
          sleep 10
          # 执行扫描
          docker run -u zap -v $(pwd):/zap/wrk:rw owasp/zap2docker-stable \
            zap-full-scan.py -t http://app:80 -r /zap/wrk/zap_report.html
      - name: Upload reports
        uses: actions/upload-artifact@v3
        with:
          name: security-reports
          path: |
            composer.lock
            *.html

编写安全测试用例(自定义渗透测试)

XSS、SQL注入、SSRF测试用例

// tests/Security/InputValidationTest.php
class InputValidationTest extends TestCase
{
    public function testNoXSSInUserInput()
    {
        $payload = '<script>alert(1)</script>';
        $response = $this->get('/search?q='.urlencode($payload));
        $this->assertStringNotContainsString($payload, $response->getBody());
        // 正确做法:验证输出已转义
        $this->assertStringContainsString('&lt;script&gt;alert(1)&lt;/script&gt;', $response->getBody());
    }
    public function testSQLiProtection()
    {
        $payload = "1' OR '1'='1";
        $response = $this->get('/user?id='.$payload);
        $this->assertEquals(404, $response->getStatusCode()); // 应返回无结果
    }
}

文件上传漏洞测试

public function testFileUploadEvades()
{
    $client = new GuzzleHttp\Client();
    $response = $client->post('/upload', [
        'multipart' => [
            ['name' => 'file', 'contents' => '<?php system($_GET["cmd"]); ?>', 'filename' => 'shell.php']
        ]
    ]);
    $this->assertStringNotContainsString('shell.php', $response->getBody());
    // 验证文件未被移动到公开目录
    $this->assertFileDoesNotExist('/var/www/uploads/shell.php');
}

常用工具对比

工具 类型 检测能力 安装复杂度 误报率
Progpilot SAST SQL注入、XSS、文件包含
PHPStan + 安全规则 SAST 逻辑问题、危险函数 中低
OWASP ZAP DAST SQL注入、XSS、CSRF
composer audit SCA 依赖漏洞 极低
CodeQL SAST 复杂跨文件漏洞

重要原则

  1. 不要依赖单一工具:SAST + DAST + SCA组合使用
  2. 误报处理:建立白名单,持续优化规则(尤其是Progpilot可能产生很多误报)
  3. 安全测试前置:在代码提交时(pre-commit hook)先运行快速的SAST检查
  4. 关注OWASP Top 10:将SQL注入、XSS、反序列化、SSRF等作为测试重点

建议先快速集成composer auditPHPStan(10分钟内可完成),然后根据项目风险逐步添加Progpilot和OWASP ZAP,安全测试不是一次性的,需要纳入日常开发流程。

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