andreapollastri/checkpoint

GitHub: andreapollastri/checkpoint

一款 Laravel 安全静态扫描工具,通过 artisan 命令对项目的依赖漏洞、配置缺陷和代码安全风险进行全面自动化审计。

Stars: 107 | Forks: 2

# Checkpoint ``` php artisan checkpoint:scan ``` ## 检查内容 | # | 检查项 | 严重程度 | | --- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------- | | 1 | **Composer CVE Audit** — 运行 `composer audit` 并报告已知的安全公告 | `FAIL` | | 2 | **NPM CVE Audit** — 运行 `npm audit` 并标记严重/高危漏洞 | `FAIL` / `WARN` | | 3 | **环境配置** — `APP_DEBUG`, `APP_KEY`, `APP_URL`, `SESSION_SECURE_COOKIE` | `WARN` | | 4 | **`.gitignore` 敏感文件** — 确保排除了 `.env`, `*.key`, `*.pem`;检测 `.env` 是否被 git 追踪 | `FAIL` | | 5 | **文件权限** — 标记全局可读的 `.env` 或全局可写的 `storage/` | `WARN` | | 6 | **硬编码的密钥** — 扫描 PHP/JS 文件中的 API 密钥、Stripe token、AWS 密钥、GitHub PAT、PEM 头信息 | `FAIL` | | 7 | **SQL 注入风险** — 检测带有变量插值的原始查询 (`DB::select("… $var")`, `->whereRaw(…)`) | `FAIL` | | 8 | **批量赋值漏洞** — 查找 `$guarded = []`、`Model::unguard()` 或没有定义 fillable/guarded 的模型 | `WARN` | | 9 | **XSS (跨站脚本攻击) 风险** — 标记 Blade 视图中未转义的 `{!! $var !!}` 以及原始 `echo` 请求输入的内容 | `WARN` | | 10 | **CSRF 保护** — 检测缺少 `@csrf` 的 `POST`/`PUT`/`PATCH`/`DELETE` 表单,并检查是否存在相应的 middleware | `FAIL` | | 11 | **开放重定向风险** — 识别带有未验证输入的 `redirect($request->…)` 或 `header('Location: ' . $var)` | `WARN` | | 12 | **命令注入风险** — 查找使用未转义变量调用的 `exec`、`shell_exec`、`system`、`passthru`、`proc_open` | `FAIL` | | 13 | **不安全的反序列化** — 检测 `unserialize($userInput)` 以及经典的 `unserialize(base64_decode(…))` 漏洞利用链 | `FAIL` | | 14 | **生产代码中的调试函数** — 查找测试文件之外遗留的 `var_dump`、`dd`、`dump`、`ray` | `WARN` | | 15 | **敏感数据暴露** — 标记 `display_errors = 1`、密码/token 的日志记录,以及 Telescope 的常开配置 | `WARN` | | 16 | **SSRF 风险** — 检测 `Http::get($request->…)`,以及使用用户控制的 URL 调用的 Guzzle/cURL/`file_get_contents` | `FAIL` | | 17 | **TLS 证书验证** — 标记 `withoutVerifying()`、`'verify' => false`、`CURLOPT_SSL_VERIFYPEER => false` | `FAIL` | | 18 | **CORS 配置** — 标记 `allowed_origins => ['*']` 与 `supports_credentials => true` 组合使用的情况,以及其他宽松的配置 | `FAIL` / `WARN` | | 19 | **包时效性 (供应链)** — 如果任何 Composer 包是在最近 N 天(默认为 3 天)内发布的,则扫描失败;可通过 config 设置白名单 | `FAIL` | | 20 | **供应链工具** — 当存在 `package.json` 时,如果 PATH 上没有 npm 安装时的守卫工具 (Safe-Chain, Socket CLI),则发出警告 | `WARN` | | 21 | **路径遍历风险** — 检测 `Storage::get($request->…)`,以及使用用户控制路径的 `file_get_contents`/`include`/`require` | `FAIL` | | 22 | **弱密码学** — 标记 `mcrypt_*`、ECB 模式、DES/3DES/RC4,以及在密码/token/HMAC 关键字附近使用的 `md5`/`sha1` | `FAIL` / `WARN` | | 23 | **不安全的随机数生成器 (RNG)** — 检测在安全上下文 (token、CSRF、密码重置、OTP) 中使用的 `rand`/`mt_rand`/`uniqid` | `FAIL` | | 24 | **Session 与 Cookie 安全** — 审计 `config/session.php` 中的 `http_only=false`、`same_site=null/none`、`secure=false`、`encrypt=false` | `WARN` | | 25 | **EOL 版本** — 当 Composer 锁定的 Laravel 和运行时的 PHP 已过期或即将达到上游安全截止日期时进行标记 | `FAIL` / `WARN` | | 26 | **可疑的 Vendor Autoload** — 标记 `vendor/` 下通过内置白名单之外的 `autoload.files` 注册 PHP 的包 (此机制曾被 2026 年 5 月的 Laravel-Lang 供应链攻击滥用) | `WARN` | ## 要求 - **PHP** `^8.1` 是包的最低版本要求。较新的 Laravel 版本可能需要更高的 PHP,因此您实际所需的最低版本取决于您的 Laravel 主版本要求。 - **Laravel** `8`–`13` (与应用使用的 `illuminate/*` 8.x–13.x 主版本一致) ## 安装 ``` composer require --dev andreapollastri/checkpoint ``` 该包会通过 Laravel 的包自动发现功能进行注册 — 无需手动注册。 ## 推荐的配套工具 Checkpoint 是一个静态扫描器 — 它会检查您的代码库,但不会拦截包的安装。为了防范下一个 event-stream/ua-parser-js/chalk 风格的供应链攻击,加固 npm install 路径,请将 Checkpoint 与**纵深防御**结合使用:在 container 中运行安装,并在必须于本地安装时在宿主机上添加运行时守卫。 ### Docker (推荐) 在 **container 内部**运行 `composer install`、`npm install` 和 `php artisan checkpoint:scan`,而不是直接在您的笔记本电脑或服务器 shell 上运行。供应链恶意软件通常在包的 post-install 脚本执行期间运行 — 如果它在您的宿主机上运行,就可以访问您的 SSH 密钥、浏览器 cookie 和文件系统。一次性的开发 container 可以将爆炸半径限制在一个可以随时丢弃的隔离文件系统中。 典型的工作流: ``` docker compose up -d docker compose exec app composer install docker compose exec app npm install docker compose exec app php artisan checkpoint:scan ``` 使用适合您项目的任何 Docker 设置 — Docker Compose、devcontainer,或者在同一作业中带有 Node 的 CI 镜像(例如 `composer:2`)。目标都是一样的:**绝不让不受信任的安装脚本在裸机上运行**;仅将宿主机视为控制平面。 ### Safe-Chain (推荐) 由 Aikido 提供的 [Safe-Chain](https://www.npmjs.com/package/@aikidosec/safe-chain) 是一个免费的 shell shim,它可以在已知的恶意 npm 包**运行其安装脚本之前**阻止它们。只需全局安装一次: ``` npm install -g @aikidosec/safe-chain safe-chain setup ``` 当您**确实**在宿主机上运行 npm 时 (CI runner、一次性脚本),Safe-Chain 会在已知的恶意包**运行其安装脚本之前**阻止它们。Checkpoint 的**供应链工具**检查会验证您的 `PATH` 中是否存在 Safe-Chain (或等效工具,如 Socket CLI),如果未检测到保护机制,则会发出 `WARN`。 ## 用法 ### 运行所有检查 ``` php artisan checkpoint:scan ``` ### 仅运行特定检查 ``` php artisan checkpoint:scan --only="SQL Injection Risks,CSRF Protection" ``` ### 跳过特定检查 ``` php artisan checkpoint:scan --skip="NPM CVE Audit,Debug Functions in Production Code" ``` ### JSON 输出 (用于 CI/CD pipeline) ``` php artisan checkpoint:scan --json ``` 如果任何检查返回 `FAIL`,该命令将以退出码 `1` 退出,这使其适合作为 pipeline 的拦截门槛。 ## 配置 Checkpoint 开箱即用,具有合理的默认配置。当您需要切换单个检查或调整时效性控制门槛时,请发布配置文件: ``` php artisan vendor:publish --tag=checkpoint-config ``` 这将创建包含两个部分的 `config/checkpoint.php`: ### 启用 / 禁用检查 列出了每个默认检查并处于启用状态。将任何条目设置为 `false` 即可将其从扫描中排除: ``` 'checks' => [ Checks\ComposerAuditCheck::class => true, Checks\NpmAuditCheck::class => false, // skip npm audit on a PHP-only project Checks\EnvironmentCheck::class => true, // … Checks\PackageFreshnessCheck::class => true, Checks\SupplyChainToolingCheck::class => true, ], ``` ### 包时效性调整 ``` 'package_freshness' => [ 'minimum_age_days' => 3, 'whitelist' => [ 'andreapollastri/checkpoint', // bundled — see note below // 'laravel/framework', // 'symfony/console', ], ], ``` - `minimum_age_days` — 发布时间少于该天数的包将无法通过扫描。默认值为 `3`。**设置为 `0` 可完全绕过时效性门槛**,而无需从扫描器中移除该检查。 - `whitelist` — 豁免时效性检查的完整包名 (`vendor/package`)。请谨慎使用,最好添加内联注释说明为什么允许每个条目。 ### 抑制单个发现结果 每个 `WARN` 或 `FAIL` 的发现结果都会显示一个稳定的 12 字符哈希值: ``` FAIL Hardcoded Secrets 3 potential hardcoded secret(s) found. ✗ app/Services/PaymentService.php:14 — 'api_key' => 'sk_live_…' [a1b2c3d4e5f6] ✗ config/services.php:8 — $secret = 'super…' [9f8e7d6c5b4a] ``` 要静默其中一项发现 — 例如误报、接受的遗留代码、内部测试 fixture — 请将括号中的哈希值复制到 `config/checkpoint.php` 中: ``` 'suppressed' => [ 'a1b2c3d4e5f6', '9f8e7d6c5b4a', ], ``` 在下一次运行时,这些发现结果将被过滤掉。如果某个检查的所有发现结果最终都被抑制,该检查将被降级为 `PASS`,并附带一条明确的 `"All N finding(s) suppressed via config."` 消息 — 这样抑制操作会在输出中可见,而不是被静默忽略。 该哈希值基于内容稳定性:仅改变同一文件内行号的重构**不会**使抑制失效。如果您更改了文件路径或发现的内容本身,哈希值_确实_会发生变化,这就是预期的安全防范机制。 ### 从文件扫描中排除文件夹 基于文件的检查 (硬编码密钥、SQL 注入、XSS 等) 会跳过诸如 `vendor/`、`node_modules/` 和 `storage/` 等内置路径。当您挂载了数据目录或其他不属于应用程序源代码的文件夹时,请添加您自己的路径: ``` 'exclude_paths' => [ 'storage/app/mounted-data', 'data/external', ], ``` 路径是相对于项目根目录的。前导和尾随斜杠是可选的。不可读的目录会被自动跳过,因此挂载卷上的权限错误不会中止扫描。 ## 输出示例 ``` ██████╗██╗ ██╗███████╗ ██████╗██╗ ██╗██████╗ ██████╗ ██╗███╗ ██╗████████╗ ██╔════╝██║ ██║██╔════╝██╔════╝██║ ██╔╝██╔══██╗██╔═══██╗██║████╗ ██║╚══██╔══╝ ██║ ███████║█████╗ ██║ █████╔╝ ██████╔╝██║ ██║██║██╔██╗██║ ██║ ██║ ██╔══██║██╔══╝ ██║ ██╔═██╗ ██╔═══╝ ██║ ██║██║██║╚████║ ██║ ╚█████╗██║ ██║███████╗ ╚█████╗██║ ██╗██║ ╚█████╔╝██║██║ ╚███║ ██║ ╚════╝╚═╝ ╚═╝╚══════╝ ╚════╝╚═╝ ╚═╝╚═╝ ╚════╝ ╚═╝╚═╝ ╚══╝ ╚═╝ Laravel Security Scanner — andreapollastri/checkpoint Scanning: /var/www/my-app PASS Composer CVE Audit No known CVEs in Composer dependencies. FAIL Hardcoded Secrets 3 potential hardcoded secret(s) found. ✗ app/Services/PaymentService.php:14 — 'api_key' => 'sk_live_abc123…' [a1b2c3d4e5f6] ✗ config/services.php:8 — $secret = 'supersecretvalue' [9f8e7d6c5b4a] ✗ app/Http/Controllers/WebhookController.php:31 — 'api_key' => 'ghp_…' [3e2d1c0b9a8f] FAIL Path Traversal Risks 1 potential path traversal risk(s) found. ✗ app/Http/Controllers/DownloadController.php:24 — Storage::get($request->path) [7b6a5f4e3d2c] WARN Environment Configuration 3 environment issue(s) found. ⚑ APP_DEBUG is true — full stack traces will be exposed to end users. [5c4b3a2d1e0f] ⚑ SESSION_SECURE_COOKIE is not enabled. [1a2b3c4d5e6f] ⚑ APP_URL is set to "http://localhost" — update it for production. [6e5d4c3b2a1f] ───────────────────────────────────────────────────────── Summary 19 passed 4 warning(s) 2 failed (25 checks total) Scan result: FAIL — fix the issues above before deploying. ``` ## 通过自定义检查进行扩展 创建一个扩展了 `AbstractCheck` 的类并返回一个 `CheckResult`: ``` use Checkpoint\Checks\AbstractCheck; use Checkpoint\Checks\CheckResult; class MyCustomCheck extends AbstractCheck { public function name(): string { return 'My Custom Check'; } public function run(): CheckResult { // your logic here return CheckResult::pass('Everything looks good.'); // or: CheckResult::warn('Something to review.', ['detail one', 'detail two']); // or: CheckResult::fail('Critical issue found.', ['detail']); } } ``` 然后通过手动构建 `Scanner` 来注册它,而不是使用默认设置: ``` use Checkpoint\Scanner; $scanner = Scanner::withDefaultChecks(base_path()) ->add(new MyCustomCheck()); ``` ## CI/CD 集成 Checkpoint 只需一条命令即可为任一提供商搭建一个开箱即用的 pipeline。 ### GitHub Actions ``` php artisan checkpoint:github ``` 创建 `.github/workflows/checkpoint.yml` — 在推送到 `main`/`master` 分支以及每次发起 pull request 时触发。使用 `actions/checkout@v4`、`shivammathur/setup-php@v2` (PHP 8.2)、Composer cache,并运行 `php artisan checkpoint:scan`。传入 `--force` 可覆盖现有文件。 ### GitLab CI ``` php artisan checkpoint:gitlab ``` 创建 `.gitlab-ci.yml` — 在 merge request 和默认分支推送时运行,使用带有 Composer cache 的 `composer:2` 镜像。如果您已经拥有 `.gitlab-ci.yml`,该命令将拒绝覆盖,并将代码片段打印到 stdout,以便您将其粘贴到现有的 pipeline 中。使用 `--force` 进行覆盖。 ### 自定义用法 如果您倾向于将 Checkpoint 接入您已经维护的 pipeline 中,只需调用: ``` - name: Security audit run: php artisan checkpoint:scan --json | tee checkpoint-report.json ``` ### Composer hooks 在每次执行 `composer install` / `composer update` 后自动运行 Checkpoint: ``` php artisan checkpoint:install-hooks ``` 这会将 `@php artisan checkpoint:scan` 追加到 `composer.json` 中的 `scripts.post-update-cmd` 和 `scripts.post-install-cmd` 中。该命令: - 在修改 `composer.json` 之前以交互方式确认 (对于 CI,可以使用 `--no-interaction` 跳过提示)。 - 具有幂等性:在已安装的设置上重新运行是空操作。 - 保留任何现有的 hook (仅追加);**不会**覆盖属于其他工具的脚本。 - 支持 `--remove` 以进行干净的卸载,并支持 `--force` 以替换过期的 Checkpoint 条目。 ### 退出码 | Code | Meaning | | ---- | ------------------------------------ | | `0` | 所有检查通过 (或仅有警告) | | `1` | 至少有一项检查返回 `FAIL` | ## 架构 ``` src/ ├── CheckpointServiceProvider.php # auto-registers the command ├── Scanner.php # orchestrates all checks ├── Commands/ │ ├── ScanCommand.php # php artisan checkpoint:scan │ ├── GithubPipelineCommand.php # php artisan checkpoint:github │ ├── GitlabPipelineCommand.php # php artisan checkpoint:gitlab │ └── InstallHooksCommand.php # php artisan checkpoint:install-hooks └── Checks/ ├── AbstractCheck.php # base class ├── CheckResult.php # pass / warn / fail value object ├── ComposerAuditCheck.php ├── NpmAuditCheck.php ├── EnvironmentCheck.php ├── GitIgnoreCheck.php ├── FilePermissionsCheck.php ├── HardcodedSecretsCheck.php ├── SqlInjectionCheck.php ├── MassAssignmentCheck.php ├── XssCheck.php ├── CsrfCheck.php ├── OpenRedirectCheck.php ├── CommandInjectionCheck.php ├── InsecureDeserializationCheck.php ├── DebugFunctionsCheck.php ├── SensitiveExposureCheck.php ├── SsrfCheck.php ├── TlsVerificationCheck.php ├── CorsConfigCheck.php ├── PackageFreshnessCheck.php ├── SuspiciousVendorAutoloadCheck.php ├── SupplyChainToolingCheck.php ├── PathTraversalCheck.php ├── WeakCryptographyCheck.php ├── InsecureRngCheck.php ├── SessionSecurityCheck.php └── EolVersionCheck.php ``` ##可证 MIT — [Andrea Pollastri](https://andreapollastri.net)
标签:ffuf, Laravel, LNA, OpenVAS, PHP, 代码安全, 动态分析, 漏洞枚举, 请求拦截