本文目录导读:

- 静态代码分析(SAST):检测代码层面的漏洞
- 动态分析(DAST / 运行时测试):模拟攻击行为
- 依赖漏洞扫描(SCA)
- CI/CD集成(GitHub Actions示例)
- 编写安全测试用例(自定义渗透测试)
- 常用工具对比
- 重要原则
在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('<script>alert(1)</script>', $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 | 复杂跨文件漏洞 | 高 | 低 |
重要原则
- 不要依赖单一工具:SAST + DAST + SCA组合使用
- 误报处理:建立白名单,持续优化规则(尤其是Progpilot可能产生很多误报)
- 安全测试前置:在代码提交时(pre-commit hook)先运行快速的SAST检查
- 关注OWASP Top 10:将SQL注入、XSS、反序列化、SSRF等作为测试重点
建议先快速集成composer audit和PHPStan(10分钟内可完成),然后根据项目风险逐步添加Progpilot和OWASP ZAP,安全测试不是一次性的,需要纳入日常开发流程。