本文目录导读:

我来详细说明 PHP 安全扫描流水线的搭建方法。
完整的 PHP 安全扫描流水线架构
# .gitlab-ci.yml 示例
stages:
- dependencies
- static_analysis
- security_scan
- dynamic_scan
# 依赖安装
install_deps:
stage: dependencies
script:
- composer install --no-dev --optimize-autoloader
- npm ci
artifacts:
paths:
- vendor/
- node_modules/
# 静态代码分析
static_analysis:
stage: static_analysis
parallel:
matrix:
- TOOL: [phpcs, phpmd, phpstan, psalm]
script:
- |
case $TOOL in
phpcs)
vendor/bin/phpcs --standard=PSR12 src/
;;
phpmd)
vendor/bin/phpmd src/ text cleancode,codesize,controversial,design,naming,unusedcode
;;
phpstan)
vendor/bin/phpstan analyse src/ --level=9
;;
psalm)
vendor/bin/psalm --show-info=true
;;
esac
# 安全扫描
security_scan:
stage: security_scan
parallel:
matrix:
- TOOL:
- composer_audit
- security_checker
- snuffleupagus
- php_sec_info
- owasp_dependency_check
script:
- |
case $TOOL in
composer_audit)
composer audit --format=json > reports/composer-audit.json
;;
security_checker)
vendor/bin/security-checker security:check composer.lock
;;
snuffleupagus)
# 运行 Snuffleupagus 规则
php -d "snuffleupagus.rules"="default" run_tests.php
;;
php_sec_info)
vendor/bin/php-security-info
;;
owasp_dependency_check)
dependency-check --scan . --format JSON > reports/owasp.json
;;
esac
artifacts:
paths:
- reports/
expire_in: 30 days
# DAST 动态扫描
dynamic_scan:
stage: dynamic_scan
services:
- name: owasp/zap2docker-stable
alias: zap
script:
- |
# 启动目标应用
php -S 0.0.0.0:8000 -t public/ &
# 等待应用启动
sleep 5
# 运行 ZAP 扫描
zap-cli quick-scan --self-contained \
--start-options '-config api.disablekey=true' \
http://app:8000/
# 生成报告
zap-cli report -o reports/zap-report.html -f html
artifacts:
paths:
- reports/zap-report.html
# 代码安全审计
code_audit:
stage: security_scan
script:
- |
# 运行 Progpilot
vendor/bin/progpilot --input src/ --output reports/progpilot.json
# 运行 RIPS 扫描
php -r "
\$scanner = new RipsScanner('src/');
\$scanner->scan();
file_put_contents('reports/rips.html', \$scanner->getHtmlReport());
"
# 运行 Phan Security Plugin
vendor/bin/phan --plugin SecurityPlugin \
--output-mode json \
--output reports/phan-security.json
artifacts:
paths:
- reports/
# 依赖漏洞扫描
dependency_scan:
stage: security_scan
script:
- |
# Syft 扫描
syft packages dir:. -o json > reports/syft.json
# Grype 漏洞扫描
grype dir:. -o json > reports/grype.json
# Trivy 扫描
trivy filesystem --severity HIGH,CRITICAL . > reports/trivy.txt
# Snyk 扫描
snyk test --json > reports/snyk.json
artifacts:
paths:
- reports/
# 配置安全检查
config_scan:
stage: security_scan
script:
- |
# 检查 PHP 配置安全性
php -r "
\$secure = [
'expose_php' => 'Off',
'display_errors' => 'Off',
'allow_url_fopen' => 'Off',
'allow_url_include' => 'Off',
'session.cookie_httponly' => 'On',
'session.cookie_secure' => 'On',
'session.use_only_cookies' => 'On',
'session.use_strict_mode' => 'On',
'session.cookie_samesite' => 'Lax'
];
foreach (\$secure as \$key => \$expected) {
\$actual = ini_get(\$key);
if (\$actual != \$expected) {
echo \"WARNING: \$key should be \$expected, current is \$actual\n\";
}
}
" > reports/config-check.txt
artifacts:
paths:
- reports/config-check.txt
Docker 化流水线配置
# Dockerfile.security
FROM php:8.2-cli
# 安装依赖
RUN apt-get update && apt-get install -y \
git \
curl \
wget \
unzip \
libzip-dev \
libcurl4-openssl-dev \
&& docker-php-ext-install zip curl
# 安装 Composer
COPY --from=composer:latest /usr/bin/composer /usr/bin/composer
# 安装安全工具
RUN wget https://github.com/OWASP/dependency-check/releases/download/v8.3.1/dependency-check-8.3.1-release.zip \
&& unzip dependency-check-8.3.1-release.zip -d /opt/dependency-check \
&& ln -s /opt/dependency-check/bin/dependency-check.sh /usr/local/bin/dependency-check
# 安装安全扫描器
RUN composer global require \
sensiolabs/security-checker \
phpstan/phpstan \
vimeo/psalm \
phan/phan \
rips/rips-scanner
# 安装开源工具
RUN wget https://github.com/anchore/syft/releases/download/v0.87.1/syft_0.87.1_linux_amd64.deb \
&& dpkg -i syft_0.87.1_linux_amd64.deb
RUN wget https://github.com/anchore/grype/releases/download/v0.65.1/grype_0.65.1_linux_amd64.deb \
&& dpkg -i grype_0.65.1_linux_amd64.deb
# 设置工作目录
WORKDIR /workspace
COPY composer.json composer.lock ./
COPY src/ src/
COPY config/ config/
CMD ["composer", "install", "--no-dev", "--optimize-autoloader"]
GitHub Actions 工作流配置
# .github/workflows/security-scan.yml
name: PHP Security Scan
on:
push:
branches: [main, develop]
pull_request:
branches: [main]
schedule:
- cron: '0 2 * * *' # 每天凌晨2点运行
jobs:
security-checks:
runs-on: ubuntu-latest
strategy:
matrix:
php-version: ['8.1', '8.2']
tool: ['phpstan', 'psalm', 'security-checker']
steps:
- uses: actions/checkout@v3
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: ${{ matrix.php-version }}
extensions: mbstring, xml, json, curl, gd
coverage: xdebug
tools: composer:v2
- name: Install dependencies
run: composer install --no-interaction --prefer-dist
- name: Run ${{ matrix.tool }}
run: |
case ${{ matrix.tool }} in
phpstan)
vendor/bin/phpstan analyse src/ --level=9
;;
psalm)
vendor/bin/psalm --show-info=true --stats
;;
security-checker)
vendor/bin/security-checker security:check composer.lock
;;
esac
- name: Upload report
uses: actions/upload-artifact@v3
if: always()
with:
name: security-report-${{ matrix.tool }}-php${{ matrix.php-version }}
path: |
reports/
composer-audit:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: shivammathur/setup-php@v2
with:
php-version: '8.2'
- name: Composer audit
run: composer audit --format=json
continue-on-error: true
- name: Check for vulnerabilities
run: |
AUDIT_RESULT=$(composer audit --format=json)
echo "$AUDIT_RESULT" | jq '.advisories'
if echo "$AUDIT_RESULT" | jq -e '.advisories | length > 0' > /dev/null; then
echo "::warning::Vulnerabilities found in dependencies"
exit 1
fi
dependency-check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: OWASP Dependency Check
uses: dependency-check/Dependency-Check_Action@main
with:
project: 'PHP Application'
path: '.'
format: 'HTML'
args: >
--failOnCVSS 7
--enableExperimental
--suppression suppression.xml
- name: Upload Dependency Check report
uses: actions/upload-artifact@v3
with:
name: dependency-check-report
path: reports/dependency-check-report.html
sast-scan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Phan Security Scan
run: |
vendor/bin/phan --plugin SecurityPlugin \
--output-mode pylint \
--output reports/phan.log
- name: Progpilot Scan
run: |
vendor/bin/progpilot --input src/ \
--output reports/progpilot.json \
--config progpilot_config.yml
- name: Upload SAST results
uses: actions/upload-artifact@v3
with:
name: sast-reports
path: reports/
自定义扫描规则配置
// progpilot_config.yml
scanner:
inputs:
- src/
outputs:
- reports/progpilot.json
rules:
# SQL注入检查
sql_injection:
enabled: true
sinks:
- mysqli_query
- PDO::query
- db_query
# XSS检查
xss:
enabled: true
sinks:
- echo
- print
- print_r
# 命令注入
command_injection:
enabled: true
sinks:
- exec
- system
- shell_exec
- passthru
# 文件包含
file_inclusion:
enabled: true
sinks:
- include
- include_once
- require
- require_once
# 文件操作
file_operations:
enabled: true
sinks:
- fopen
- file_get_contents
- file_put_contents
- unlink
# 序列化
deserialization:
enabled: true
sinks:
- unserialize
- json_decode
# 自定义漏洞规则
custom_vulnerabilities:
- name: "Weak Password Hash"
pattern: "md5|sha1"
severity: "high"
- name: "Hardcoded Credentials"
pattern: "(password|passwd|pwd)\s*=\s*['\"](?!.*(env|getenv|\$_SERVER))"
severity: "critical"
- name: "Insecure Random"
pattern: "rand\(|mt_rand\("
severity: "medium"
报告生成与聚合
// ReportGenerator.php
<?php
class SecurityReportGenerator
{
private array $reports = [];
private array $vulnerabilities = [];
public function __construct(private string $outputDir)
{
if (!is_dir($outputDir)) {
mkdir($outputDir, 0755, true);
}
}
public function generateSummary(array $scanResults): array
{
$summary = [
'timestamp' => date('Y-m-d H:i:s'),
'total_vulnerabilities' => 0,
'critical' => 0,
'high' => 0,
'medium' => 0,
'low' => 0,
'scan_duration' => 0,
'scans_performed' => count($scanResults)
];
foreach ($scanResults as $tool => $results) {
$counts = $this->parseToolResults($tool, $results);
$summary['critical'] += $counts['critical'];
$summary['high'] += $counts['high'];
$summary['medium'] += $counts['medium'];
$summary['low'] += $counts['low'];
$summary['total_vulnerabilities'] += $counts['total'];
$this->vulnerabilities[$tool] = $results;
}
return $summary;
}
public function generateHTMLReport(array $scanResults): string
{
$summary = $this->generateSummary($scanResults);
$html = <<<HTML
<!DOCTYPE html>
<html>
<head>PHP Security Scan Report</title>
<style>
body { font-family: Arial, sans-serif; margin: 20px; }
h1 { color: #333; }
.vulnerability { margin: 10px 0; padding: 10px; border-radius: 5px; }
.critical { background-color: #ffebee; border-left: 4px solid #f44336; }
.high { background-color: #fff3e0; border-left: 4px solid #ff9800; }
.medium { background-color: #fff8e1; border-left: 4px solid #ffc107; }
.low { background-color: #e8f5e9; border-left: 4px solid #4caf50; }
.severity { font-weight: bold; padding: 2px 6px; border-radius: 3px; }
.severity-critical { background-color: #f44336; color: white; }
.severity-high { background-color: #ff9800; color: white; }
.severity-medium { background-color: #ffc107; color: black; }
.severity-low { background-color: #4caf50; color: white; }
</style>
</head>
<body>
<h1>PHP Security Scan Report</h1>
<h2>Summary</h2>
<p>Total Vulnerabilities: {$summary['total_vulnerabilities']}</p>
<p>Critical: {$summary['critical']}</p>
<p>High: {$summary['high']}</p>
<p>Medium: {$summary['medium']}</p>
<p>Low: {$summary['low']}</p>
<p>Scan Date: {$summary['timestamp']}</p>
HTML;
// 添加具体漏洞信息
foreach ($this->vulnerabilities as $tool => $results) {
$html .= "<h3>Tool: {$tool}</h3>";
foreach ($results as $vuln) {
$severity = strtolower($vuln['severity'] ?? 'medium');
$html .= <<<VULN
<div class="vulnerability {$severity}">
<span class="severity severity-{$severity}">{$vuln['severity']}</span>
<strong>{$vuln['title']}</strong>
<p>{$vuln['description']}</p>
<p>File: {$vuln['file']}:{$vuln['line']}</p>
<pre>{$vuln['code']}</pre>
<p>Recommendation: {$vuln['recommendation']}</p>
</div>
VULN;
}
}
$html .= '</body></html>';
file_put_contents(
$this->outputDir . '/security-report-' . date('Y-m-d') . '.html',
$html
);
return $html;
}
private function parseToolResults(string $tool, array $results): array
{
// 根据不同工具格式解析结果
switch ($tool) {
case 'phpstan':
return $this->parsePhpStanResults($results);
case 'psalm':
return $this->parsePsalmResults($results);
case 'progpilot':
return $this->parseProgpilotResults($results);
default:
return $this->parseGenericResults($results);
}
}
}
最佳实践建议
流水线集成建议
# 安全检查点配置
security_pipeline:
# 1. 代码提交前检查(pre-commit hooks)
pre_commit:
- php -l {files} # 语法检查
- composer audit --format=json # 依赖检查
# 2. CI/CD 流水线检查
ci_cd:
- stage: dependencies
check: composer validate && composer audit
- stage: static_analysis
check: phpstan analyse --level=max
- stage: security_scan
check: |
progpilot --input src/ \
security-checker security:check
- stage: dependency_scan
check: grype dir:.
# 3. 部署前检查(门禁)
deployment_gates:
- severity: critical
action: block_deployment
tools: [phpstan, psalm, security-checker]
- severity: high
action: require_approval
tools: [progpilot, dependency-check]
- severity: medium
action: notify
tools: [all]
# 4. 定期扫描
scheduled_scans:
- frequency: daily
time: "02:00"
tools: [all]
- frequency: weekly
time: "03:00"
tools: [full-scan, penetration-test]
- frequency: monthly
time: "04:00"
tools: [owasp-zap, nuclei]
这样的流水线配置可以:
- 在代码提交时实时检查
- CI/CD 过程中全面扫描
- 部署前自动门禁
- 定期执行深度扫描
- 生成详细报告并告警
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播