一套可直接开源落地的))"Hyperf PHP 安全基线工具箱"(从0到持续维护),带核心代码骨架。 ---1)项目目标(MVP) 先做6项基线检查:1. 运行时配置检查(APP_ENV、APP_DEBUG、CORS、错误暴露)2. HTTP 安全头检查(CSP、HSTS、X-Frame-Options 等)3. 依赖漏洞检查(composer audit)4. Secret 泄漏扫描(AK/SK、私钥、Token)5. 文件权限检查(.env、storage、runtime)6. 报告输出(CLI + JSON + CI 失败门禁) ---2)仓库结构(建议) hyperf-security-baseline/ ├─ src/ │ ├─ Contract/ │ │ ├─ RuleInterface.php │ │ └─ Finding.php │ ├─ Rule/ │ │ ├─ EnvRule.php │ │ ├─ HeaderRule.php │ │ ├─ ComposerAuditRule.php │ │ ├─ SecretScanRule.php │ │ └─ PermissionRule.php │ ├─ Service/ │ │ ├─ BaselineRunner.php │ │ └─ ReportFormatter.php │ ├─ Command/ │ │ └─ SecurityScanCommand.php │ └─ ConfigProvider.php ├─ config/ │ └─ autoload/security_baseline.php ├─ tests/ ├─ .github/workflows/ci.yml ├─ composer.json ├─ README.md ├─ SECURITY.md └─ LICENSE ---3)从0初始化mkdirhyperf-security-baseline&&cdhyperf-security-baselinecomposerinitcomposerrequire hyperf/command hyperf/contract hyperf/utils symfony/processcomposerrequire--devphpunit/phpunit phpstan/phpstan friendsofphp/php-cs-fixer ---4)核心代码4.1规则接口 + Finding src/Contract/RuleInterface.php<?php declare(strict_types=1);namespace HyperfSecurityBaseline\Contract;interface RuleInterface{publicfunctionname(): string;/** @return Finding[]*/ publicfunctioncheck(array$context): array;}src/Contract/Finding.php<?php declare(strict_types=1);namespace HyperfSecurityBaseline\Contract;final class Finding{publicfunction__construct(public string$rule, public string$level, // info|low|medium|high|critical public string$message, public ?string$file=null, public ?int$line=null, public ?string$fix=null,){}}---4.2规则示例:EnvRule src/Rule/EnvRule.php<?php declare(strict_types=1);namespace HyperfSecurityBaseline\Rule;use HyperfSecurityBaseline\Contract\Finding;use HyperfSecurityBaseline\Contract\RuleInterface;final class EnvRule implements RuleInterface{publicfunctionname(): string{return'env_rule';}publicfunctioncheck(array$context): array{$findings=[];$env=(string)($context['env']['APP_ENV']??'dev');$debug=(string)($context['env']['APP_DEBUG']??'true');if($env==='prod'&&strtolower($debug)==='true'){$findings[]=new Finding(rule:$this->name(), level:'high', message:'APP_DEBUG must be false in production', fix:'Set APP_DEBUG=false in .env for prod');}return$findings;}}---4.3规则示例:ComposerAuditRule src/Rule/ComposerAuditRule.php<?php declare(strict_types=1);namespace HyperfSecurityBaseline\Rule;use HyperfSecurityBaseline\Contract\Finding;use HyperfSecurityBaseline\Contract\RuleInterface;use Symfony\Component\Process\Process;final class ComposerAuditRule implements RuleInterface{publicfunctionname(): string{return'composer_audit_rule';}publicfunctioncheck(array$context): array{$cwd=$context['project_root'];$p=new Process(['composer','audit','--format=json'],$cwd);$p->run();if(!$p->isSuccessful()){return[new Finding($this->name(),'medium','composer audit execution failed')];}$data=json_decode($p->getOutput(),true);$findings=[];foreach(($data['advisories']??[])as $package=>$items){ foreach($items as $advisory){ $findings[]=new Finding(rule:$this->name(),level:'high',message:sprintf('Vulnerability found in%s:%s',$package,$advisory['title']??'unknown advisory'),fix:sprintf('Upgrade package "%s" to patched version',$package));} } return $findings;} }---4.4规则示例:SecretScanRule src/Rule/SecretScanRule.php<?php declare(strict_types=1);namespace HyperfSecurityBaseline\Rule;use HyperfSecurityBaseline\Contract\Finding;use HyperfSecurityBaseline\Contract\RuleInterface;final class SecretScanRule implements RuleInterface { public function name():string { return 'secret_scan_rule';} public function check(array $context):array { $patterns=[ '/AKIA[0-9A-Z]{16}/'=>'Possible AWS Access Key','/-----BEGIN(RSA|EC|OPENSSH)PRIVATE KEY-----/'=>'Private key material','/(?i)(api[_-]?key|secret|token)\s*[:=]\s*[\'"][^\'"]{12,}[\'"]/'=>'Hardcoded secret',];$findings=[];$files=$context['scan_files']??[];foreach($files as $file){ $content=@file_get_contents($file);if($content===false){ continue;} foreach($patterns as $regex=>$label){ if(preg_match($regex,$content,$m,PREG_OFFSET_CAPTURE)){$offset=$m[0][1];$line=substr_count(substr($content,0,$offset),"\n")+1;$findings[]=new Finding(rule:$this->name(), level:'critical', message:$label, file:$file, line:$line, fix:'Move secret to env/secret manager and rotate leaked credential');}}}return$findings;}}---4.5Runner + 报告格式化 src/Service/BaselineRunner.php<?php declare(strict_types=1);namespace HyperfSecurityBaseline\Service;use HyperfSecurityBaseline\Contract\RuleInterface;final class BaselineRunner{/** @param RuleInterface[]$rules*/ publicfunction__construct(private array$rules){}publicfunctionrun(array$context): array{$all=[];foreach($this->rules as$rule){$all=array_merge($all,$rule->check($context));}return$all;}}src/Service/ReportFormatter.php<?php declare(strict_types=1);namespace HyperfSecurityBaseline\Service;use HyperfSecurityBaseline\Contract\Finding;final class ReportFormatter{/** @param Finding[]$findings*/ publicfunctiontoJson(array$findings): string{$arr=array_map(fn(Finding$f)=>['rule'=>$f->rule,'level'=>$f->level,'message'=>$f->message,'file'=>$f->file,'line'=>$f->line,'fix'=>$f->fix,],$findings);returnjson_encode(['total'=>count($arr),'findings'=>$arr], JSON_PRETTY_PRINT|JSON_UNESCAPED_SLASHES);}}---4.6Hyperf 命令入口 src/Command/SecurityScanCommand.php<?php declare(strict_types=1);namespace HyperfSecurityBaseline\Command;use Hyperf\Command\Annotation\Command;use Hyperf\Command\Command as HyperfCommand;use HyperfSecurityBaseline\Service\BaselineRunner;use HyperfSecurityBaseline\Service\ReportFormatter;#[Command]final class SecurityScanCommand extends HyperfCommand{publicfunction__construct(private BaselineRunner$runner, private ReportFormatter$formatter){parent::__construct('security:scan');}publicfunctionconfigure(){parent::configure();$this->setDescription('Run security baseline checks');}publicfunctionhandle(){$projectRoot=getcwd();$context=['project_root'=>$projectRoot,'env'=>$_ENV+$_SERVER,'scan_files'=>$this->collectFiles($projectRoot),];$findings=$this->runner->run($context);$json=$this->formatter->toJson($findings);$this->line($json);$hasHigh=collect($findings)->contains(fn($f)=>in_array($f->level,['high','critical'],true));return$hasHigh?2:0;}privatefunctioncollectFiles(string$root): array{$rii=new\RecursiveIteratorIterator(new\RecursiveDirectoryIterator($root));$files=[];foreach($riias$file){if($file->isDir())continue;$path=$file->getPathname();if(preg_match('/vendor|runtime|\.git/',$path))continue;if(preg_match('/\.(php|env|yaml|yml|json|ini)$/',$path)){$files[]=$path;}}return$files;}}---5)ConfigProvider 与依赖注册 src/ConfigProvider.php<?php declare(strict_types=1);namespace HyperfSecurityBaseline;use HyperfSecurityBaseline\Rule\ComposerAuditRule;use HyperfSecurityBaseline\Rule\EnvRule;use HyperfSecurityBaseline\Rule\PermissionRule;use HyperfSecurityBaseline\Rule\SecretScanRule;use HyperfSecurityBaseline\Service\BaselineRunner;class ConfigProvider{publicfunction__invoke(): array{return['dependencies'=>[BaselineRunner::class=>function(){returnnew BaselineRunner([new EnvRule(), new ComposerAuditRule(), new SecretScanRule(), new PermissionRule(),]);},],'commands'=>[\HyperfSecurityBaseline\Command\SecurityScanCommand::class,],];}}---6)CI 门禁(开源仓库必须) .github/workflows/ci.yml name: ci on:[push, pull_request]jobs: test: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: shivammathur/setup-php@v2 with: php-version:"8.2"- run:composerinstall--no-interaction --prefer-dist - run: vendor/bin/phpunit - run: vendor/bin/phpstan analyse src - run: php bin/hyperf.php security:scan>security-report.json - run:|catsecurity-report.jsonifgrep-E'"level": "(high|critical)"'security-report.json;thenecho"High/Critical findings found";exit1;fi---7)开源发布流程(从0到上线)1. LICENSE 选 MIT 或 Apache-2.02. README 写清:安装、命令、退出码、规则扩展方式3. SECURITY.md 写漏洞上报方式和响应时间4. 首个版本 v0.1.0(MVP)5. 打 Tag 并发 GitHub Release6. 提交 Packagist(包名如 your-org/hyperf-security-baseline) ---8)持续维护路线图 - v0.1: CLI 扫描 + JSON 报告 + CI 门禁 - v0.2: SARIF 输出(接 GitHub Code Scanning) - v0.3: 基线策略分级(dev/staging/prod) - v1.0: 规则插件化、基线豁免清单(有审计记录) ---9)首版最容易踩坑1. 扫描范围太大(把 vendor 扫进去导致噪声)2. 高危判定太松(CI 失去门禁意义)3. 没有退出码规范(流水线无法阻断)4. Secret 命中后不做轮换流程5. 只做静态检查,不做依赖漏洞检查 --- 你按这套骨架直接建仓库就能跑第一版。核心闭环是: security:scan ->JSON 报告 ->CI 根据 high/critical 失败,这就是一个可用的 Hyperf 安全基线工具箱起点。