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, 代码安全, 动态分析, 漏洞枚举, 请求拦截