Coolify 源码中的 Laravel 安全实践从 Mass Assignment 到字段级加密的落地全解【免费下载链接】coolifyAn open-source, self-hostable PaaS alternative to Vercel, Heroku Netlify that lets you easily deploy static sites, databases, full-stack applications and 280 one-click services on your own servers.项目地址: https://gitcode.com/GitHub_Trending/co/coolify本文以 Coolify 仓库内置的 Laravel 安全规范文档security.md为主线系统讲解九大安全实践Mass Assignment 防护、细粒度授权、SQL 注入与 XSS 防护、CSRF 保护、认证与 API 限流、文件上传校验、密钥隔离、依赖审计以及敏感数据库字段加密。每一条规范都会结合 Coolify 的真实源码实现RateLimiter 配置、私钥模型 等展开帮助你在自托管 PaaS 项目或任意 Laravel 应用中把安全规则真正落地而不是停留在知道这些坑的层面。一、Mass Assignment 防护白名单优先规范的核心要求是每个 Eloquent 模型都必须显式定义$fillable白名单或$guarded黑名单绝不在接受用户输入的模型上使用$guarded []。错误示例——全部字段可批量赋值攻击者可借update()一次性篡改任意列class User extends Model { protected $guarded []; // All fields are mass assignable }正确示例——只暴露明确可写的字段class User extends Model { protected $fillable [ name, email, password, ]; }Coolify 中的落地方式Coolify 的 app/Models 目录下所有模型都采用$fillable白名单模式例如 PrivateKeyprotected $fillable [ name, description, private_key, is_git_related, team_id, fingerprint, ];值得注意的是PrivateKey除了白名单外还配合了两道防线这也是规范文档中后续两节的直接体现protected $hidden [ private_key, // 序列化/API 输出时隐藏敏感列 ]; protected $casts [ private_key encrypted, // 落库前自动加密 ];白名单解决哪些列能被写$hidden解决哪些列不能被读出去encryptedcast 解决写进去的是不是密文。三者组合后即使上游校验出现疏漏敏感数据也不会以明文形式出现在响应或数据库中。二、授权每个动作都要过 Policy 或 Gate规范要求控制器中任何会修改数据的动作都必须显式授权禁止跳过。错误示例——直接更新未检查当前用户是否有权操作该资源public function update(UpdatePostRequest $request, Post $post) { $post-update($request-validated()); }正确示例——先Gate::authorize再落库public function update(UpdatePostRequest $request, Post $post) { Gate::authorize(update, $post); $post-update($request-validated()); }或者把授权逻辑放进 Form Request 的authorize()方法让校验与授权同生命周期public function authorize(): bool { return $this-user()-can(update, $this-route(post)); }Coolify 中的落地方式Coolify 在 app/Policies 下为每种资源建立了独立 Policy共 28 个策略类覆盖 Application、Server、Service、数据库、S3 存储等全部资源类型。以 ApplicationPolicy 为例update动作返回Response对象而非简单布尔值被拒绝时能附带具体原因public function update(User $user, Application $application): Response { $teamId $this-getTeamId($application); if ($teamId null) { return Response::deny(Application team not found.); } if ($user-isAdminOfTeam($teamId)) { return Response::allow(); } return Response::deny(You need at least admin or owner permissions to update this application.); }从源码结构看授权判断统一收敛到资源所属 team 用户在 team 中的角色两个维度isAdminOfTeam并且连deploy、manageEnvironment、uploadBackup这类非 CRUD 动作也单独建模为策略方法而不是笼统地挂在update上。此外 Http Kernel 中注册了can.create.resources、can.update.resource等路由中间件别名从源码结构推断部分 Livewire 组件是通过中间件层而非控制器层做权限拦截的属于每层都可授权的纵深设计。三、SQL 注入只做参数绑定不拼字符串规范要求永远使用参数绑定绝不把用户输入直接插值进 SQL 语句。错误示例DB::select(SELECT * FROM users WHERE name {$request-name});正确示例——Eloquent 查询构造器与whereRaw占位符User::where(name, $request-name)-get(); // Raw expressions with bindings User::whereRaw(LOWER(name) ?, [strtolower($request-name)])-get();Coolify 的数据访问几乎全部走 Eloquent 与查询构造器。以 PrivateKey::fingerprintExists 为例即使查询条件来自数据库字段与运行时参数也是通过where()链式方法构造的用户可控值永远不会以字符串拼接方式进入 SQL。这条规范的工程含义可以概括为一句话在 Laravel 中能用构造器就不用原生 SQL必须用原生 SQL 时必须带绑定数组。四、XSS 防护默认转义输出规范Blade 模板中一律用{{ }}做 HTML 转义{!! !!}只允许用于已确认可信、已预净化的内容。错误示例{!! $user-bio !!}正确示例{{ $user-bio }}在 Coolify 这类自托管 PaaS 中这条规则的特殊意义在于用户输入面非常宽——应用名、环境变量、服务模板、Webhook 载荷都可能最终出现在界面上。从源码结构看Coolify 还在服务端对资源名做了额外防护如 HasSafeStringAttribute 这类 Trait 出现在模型上与模板层转义形成双重防线。使用{!! !!}渲染第三方富文本如 Markdown 渲染结果前应先经 Sanctum/Purify 类组件净化——仓库 config/purify.php 的存在说明项目已引入 HTML 净化配置可作为白名单式净化的起点。五、CSRF表单必带令牌API 用签名与限流兜底规范所有 POST/PUT/DELETE 的 Blade 表单必须包含csrfInertia 应用中该指令自动生效。错误示例form methodPOST action/posts input typetext nametitle /form正确示例form methodPOST action/posts csrf input typetext nametitle /formCoolify 中的落地方式在 Http Kernel 中web中间件组显式包含VerifyCsrfToken::class即所有 Web 会话路由默认强制校验 CSRF 令牌web [ EncryptCookies::class, AddQueuedCookiesToResponse::class, StartSession::class, ShareErrorsFromSession::class, VerifyCsrfToken::class, SubstituteBindings::class, CheckForcePasswordReset::class, DecideWhatToDoWithUser::class, ],而api中间件组则不包含VerifyCsrfToken改为 Token 认证 限流见下一节——这正是CSRF 针对有状态会话、API 针对无状态凭证的分层思路。Webhook 入口routes/webhooks.php从源码结构看走的是独立分组依赖来源方签名/密钥校验而非 CSRF 令牌属于对不可交互调用方的合理豁免。六、限流认证路由与 API 路由必须加 throttle规范给出最简实现——为登录路由定义按 IP 计数的限流器RateLimiter::for(login, function (Request $request) { return Limit::perMinute(5)-by($request-ip()); }); Route::post(/login, LoginController::class)-middleware(throttle:login);Coolify 的完整限流矩阵Coolify 在 RouteServiceProvider 中把限流做成了一个矩阵值得逐条拆解限流器限额计数维度设计意图api每分钟config(api.rate_limit)次api/health单独放宽至 1000用户 ID未登录则按 IP已登录用户按身份限流健康检查探活不占配额5每分钟 5 次用户 ID 或 IP通用敏感动作的默认档位feedback每分钟 3 次用户 ID 或 IP防反馈/滥用接口刷屏login每分钟 5 次邮箱 IP 组合同一账号不同 IP 也各自受限防分布式撞库two-factor每分钟 5 次会话中暂存的login.id验证码爆破防护forgot-password每 10 分钟 3 次按 IP 每小时 3 次按邮箱身份双维度叠加防邮件轰炸且对邮箱做了归一化与哈希magic-link每分钟 5 次token IP 的 SHA-256防 magic link 被枚举force-password-reset每分钟 15 次用户 ID强制改密流程防抖其中两处实现细节特别值得借鉴。其一是登录限流的 key 设计RateLimiter::for(login, function (Request $request) { return Limit::perMinute(5)-by((string) $request-email.|.auth_rate_limit_ip($request)); });email|ip复合键意味着同一个账号从任意 IP 尝试登录都会被单独计数比单纯按 IP 限流更能抵御代理池撞库。其二是forgot-password返回了限流器数组$limits即同一请求要同时通过多个 Limit任一超限即拒绝——这是 Laravel 对多维度限流的官方支持用法。API 侧则通过 Http Kernel 的api组挂上ThrottleRequests::class.:api与configureRateLimiting()中的api命名限流器联动配额值来自 config/api.php 的rate_limit配置项部署时可按环境调整而无需改代码。七、文件上传扩展名、MIME 与尺寸三重校验规范要点用mimes校验扩展名、用mimetypes校验真实 MIME 类型、校验尺寸绝不信任客户端文件名入库时改用生成的文件名。校验规则示例public function rules(): array { return [ avatar [required, image, mimes:jpg,jpeg,png,webp, max:2048], ]; }存储时用服务端生成的文件名$path $request-file(avatar)-store(avatars, public);Coolify 中的落地方式Coolify 的上传校验统一收敛在 Livewire 组件的rules()中例如 Profile/Index 的头像上传avatar [required, image, mimes:jpg,jpeg,png,webp, max:5120, dimensions:max_width6000,max_height6000],Project/Edit 的项目图标上传采用完全相同的规则组合。注意这里在规范建议的基础上追加了dimensions校验——只限制文件字节数max:5120KB不够一张几 KB 的 10 万像素大图同样能造成前端渲染压力因此尺寸上限成为标准项之一。从源码结构看这些上传组件没有使用客户端原始文件名落盘配合store生成的随机名与publicdisk与规范中never trust client-provided filenames的要求一致。八、密钥管理.env不入库代码只读config()规范绝不提交.env应用代码中禁止直接调用env()一律通过config()读取。错误示例$key env(API_KEY);正确示例——env 只在 config 文件中出现一次// config/services.php api_key env(API_KEY), // In application code $key config(services.api_key);原因是env()依赖Dotenv在容器引导期的加载config 缓存php artisan config:cache之后env()会直接抛错而config()始终可用。Coolify 的限流器配置config(api.rate_limit)见 RouteServiceProvider就是这一模式的典型用例部署方通过.env注入值代码只读缓存后的 config 项从而同时获得生产环境可 config 缓存与密钥不硬编码两个性质。九、依赖审计composer audit进 CI规范要求周期性运行composer audit并在 CI 中自动化在部署前捕获已知漏洞composer auditCoolify 的依赖清单见 composer.json生产镜像构建流程docker/production 下的 Docker 相关配置在发版前执行依赖审计是把这条规范从建议变成门禁的常见做法。十、敏感字段加密encryptedcast $hidden双保险规范要求API Key、Token 类字段使用encryptedcast 存储并将属性标记为hidden防止序列化泄露。错误示例class Integration extends Model { protected function casts(): array { return [ api_key string, ]; } }正确示例class Integration extends Model { protected $hidden [api_key, api_secret]; protected function casts(): array { return [ api_key encrypted, api_secret encrypted, ]; } }Coolify 中的落地方式Coolify 是字段级加密用得最重的 Laravel 项目之一全仓库共有 30 余处 encryptedcast覆盖所有会接触外部凭证的模型Applicationhttp_basic_auth_password、manual_webhook_secret_github/gitlab/bitbucket/gitea全部加密CloudProviderToken云厂商 OAuthtoken加密GitlabAppaccess_token、refresh_token、client_secret三个凭证全加密EmailNotificationSettingsSMTP 主机、账号、密码以及resend_api_key均加密EnvironmentVariable环境变量value本身加密——对 PaaS 产品而言这是核心安全资产PrivateKeySSH 私钥encryptedcast $hidden与第一节呼应。加密依赖 LaravelCrypt服务AES-256-CBC密钥来自.env的APP_KEY因此**encrypted cast 不入代码仓库的 .env** 才是完整闭环数据库被拖库后得到的是密文没有APP_KEY无法还原。对加密的是数组这种复合场景Coolify 还提供了自定义 cast EncryptedArrayCastset()时json_encode后调用Crypt::encryptString落库get()时先解密再json_decode并且对解密失败的历史明文行做了降级兼容catchDecryptException后按明文 JSON 处理——这在存量明文数据逐步加密迁移的场景中是一个可以直接复用的工程模板。小结九条规则在 Coolify 中的映射速查规范条目Coolify 中的证据路径$fillable白名单app/Models/PrivateKey.php、app/Models 全目录Policy/Gate 授权app/Policies/ApplicationPolicy.php、app/Http/Kernel.phpSQL 参数绑定app/Models/PrivateKey.php 等查询构造器用法Blade 转义 净化配置config/purify.phpCSRFapp/Http/Kernel.phpweb 组VerifyCsrfToken认证/API 限流app/Providers/RouteServiceProvider.php、config/api.php上传校验app/Livewire/Profile/Index.php、app/Livewire/Project/Edit.php密钥走 configconfig/services.php、config/app.php依赖审计composer.json composer audit敏感字段加密app/Models/EnvironmentVariable.php、app/Casts/EncryptedArrayCast.php这套文档的价值不在于罗列通用 Laravel 知识而在于它定义了一组可被 Agent 与开发者共同执行的审查标准白名单、授权、绑定、转义、令牌、限流、校验、隔离、审计、加密每条都配有正反示例。Coolify 的源码则证明这些规则在承载 SSH 私钥、云凭证、环境变量等高敏资产的自托管 PaaS 场景下是完整可运行的——这也是把它作为安全 baseline 学习样本的原因。【免费下载链接】coolifyAn open-source, self-hostable PaaS alternative to Vercel, Heroku Netlify that lets you easily deploy static sites, databases, full-stack applications and 280 one-click services on your own servers.项目地址: https://gitcode.com/GitHub_Trending/co/coolify创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
