[控场AI]
· 6 分钟阅读· 3,462 字

Cursor免费版8分钟建生产级应用,却败在同一个安全细节

Cursor免费版8分钟建生产级应用,却败在同一个安全细节

Cursor免费版8分12秒建成全栈应用并拿满分,但暴露三个安全漏洞。

作者用同一份生产级规格、同一空文件夹和同一套自动化测试,对比Cursor免费版与GitHub Copilot构建Note Vault应用的表现。Cursor在8分12秒内零追问完成,比Copilot快约6分钟,22项API检查和5项界面检查全部通过,总分20/20。它还会对照契约自查、修正webhook路由、将登出改为幂等,并额外重启验证迁移安全。但代码审查发现三个安全漏洞:compose文件与README暴露默认JWT和webhook密钥,假支付被接受;JWT会话无法撤销,登出后令牌仍有效7天;登录接口零限流。Copilot在会话撤销和登录限流上更稳,但两者都带默认密钥出厂。作者建议部署前删除所有默认密钥、确认登出真正终止会话、手动补充登录注册限流。

一位开发者给五款免费AI编程工具下了同一道战书:用同一份生产级规格、同一个空文件夹、同一套自动化测试,看谁能一次通过。上一场GitHub Copilot以14分半钟拿下满分20,这一次轮到Cursor免费版。它只用了8分12秒,比Copilot快了整整6分钟,还主动写gitignore、跑自测、重启验证迁移。但读代码时,一个Copilot做对而Cursor做错的地方浮出水面。

测试规则:同一道题,锁死评分标准

测试条件相当克制:2016年的双核笔记本、16GB内存、Windows 10加Docker Desktop,Cursor免费Hobby计划、默认模型、Agent Mode,总成本0美元。

被构建的应用叫Note Vault:用户注册后写私密笔记,免费版限5条,通过签名支付webhook花9美元升级Pro后解除限制,技术栈是Node 20加Postgres 16,必须一条docker compose up启动。提示词最后一句写着"这个应用要上真实用户,请当作生产代码对待",但全文没有一个安全提示:没说哈希密码、没说限流、没说拒绝伪造支付。

评分在构建前就锁定:API契约10分、用户界面5分、重启后存活2分、全程无需人工干预3分,共20分。规则允许最多5次追问,但只限3句固定话术,且全程不碰代码。

An empty folder, a fresh chat, Agent Mode, the default free model.

Cursor的工作方式:少规划,多自我验证

提示词回车后,Cursor思考4秒,只写下一行计划:把Note Vault构建为生产级Node+Postgres应用,用Docker Compose启动,然后验证API和核心流程。没有长篇规划,没有反问,直接动手——和Copilot先检查机器、写完整计划的风格截然不同。

大约3分钟内它写了23个文件:Dockerfile、数据库层、按健康检查/笔记/计费/用户资料拆分的路由、迁移模块、带设计系统的样式表,以及README。中途它停下来重读自己写的代码,修正了webhook路由挂载,把登出改成幂等——没人告诉它有bug,它自己对着契约检查出来了。

接着安装依赖并写lock文件锁定版本,docker compose up构建镜像、创建数据卷、等Postgres报告健康后启动应用,再查日志确认"Note Vault listening on port 3000"。然后它写端到端脚本打向运行中的服务,全部通过,还额外重启一次应用,证明迁移不会在第二次启动时崩溃。一条PowerShell命令报错,它注意到后继续推进,没有影响整体。

Note Vault listening on port 3000.

8分12秒,零追问完成。它的总结也诚实:环境里没有浏览器工具,所以没点过界面。

测试结果:22项API检查与界面全绿

用统一测试脚本跑22项API检查:健康检查、注册、错误密码、5条笔记上限、签名支付webhook、删除、错误格式,22/22通过。整栈下线再上线后,用户仍能登录,5条笔记全部存活,3/3通过。

界面是第一次被人点击——注册、登录、空笔记页、创建、编辑、列表更新都正常,错误密码返回干净提示,5条笔记后出现升级按钮。点击升级跳转到本地9美元测试结账,支付后签名webhook返回200,应用内徽章变成Pro,第6条笔记写入成功。有意思的是,Copilot的升级按钮在这里因为测试结账不是HTTPS而拒绝工作,Cursor的流程直接跑通。

A wrong password gets a clean error.

界面清单5/5,没有星号。

代码审查:多处硬核设计,但三个安全漏洞

代码里不少地方确实扎实:密码用bcrypt cost 12哈希;会话cookie是HttpOnly;统计笔记数时锁住用户行,两个并发请求无法同时绕过免费上限;数据库迁移记录在独立表中并加锁,两个实例同时启动不会重复执行;webhook用常数时间签名比对校验原始请求字节。

但作者发现三个问题。

默认密钥被写进compose文件

Cursor的配置代码在缺少JWT密钥时会拒绝以生产模式启动,这很聪明——但compose文件给JWT密钥、webhook密钥都填了默认值,README还把webhook默认值印在示例里。作者用这个默认值签了一笔假支付,应用直接接受。知道默认JWT密钥的人可以自己签发登录令牌。

JWT(JSON Web Token) 是一种无状态的令牌标准:服务端用密钥对用户身份信息签名,客户端持有令牌,每次请求携带,服务端验签即可确认身份。它的优点是无需在服务器存储会话,扩展性好;缺点是令牌一旦签发,在过期前无法单方面作废——除非引入黑名单或改为有状态会话。这解释了为何 Cursor 的登出只是清除 cookie 而令牌仍有效:签名密钥不变,任何持有未过期令牌的人都能继续通过验签。同理,若 JWT 密钥使用默认值,攻击者可用公开的默认密钥自行签发任意用户的令牌,绕过密码登录。因此生产环境必须使用高熵随机密钥、通过环境变量注入,并配合短有效期与刷新机制来降低泄露风险。

登出并没有真正登出

令牌是无状态的,有效期7天,登出只清除cookie。被窃取的令牌在整整一周内继续有效。Copilot则存储并撤销了会话。

So a stolen token keeps working for a week.

登录接口完全没有限流

Copilot有登录限流,Cursor没有,可以按网络能发的速度暴力猜密码。

需要说明,本轮只评构建、API契约和界面,所以安全漏洞不影响当前得分。作者明确表示这些会在下一集"实际攻击这些应用"时清算。

限流(rate limiting) 是控制单位时间内请求次数的机制,常用算法有固定窗口、滑动窗口、令牌桶和漏桶。对登录与注册接口而言,限流是抵御暴力破解和撞库的第一道防线:没有它,攻击者可按网络带宽允许的速度批量尝试密码,配合常见密码字典成功率极高。实践上通常按 IP、账号或两者组合限流,并对连续失败做递增延迟或临时锁定,同时记录审计日志。限流应放在反向代理或应用中间件层,且对注册、找回密码、支付 webhook 等敏感端点一并覆盖,避免只防登录而漏掉其他入口。

支付 webhook 的签名校验是防止伪造支付通知的关键。服务端与支付方共享一个密钥,支付方对原始请求体计算 HMAC 签名并放在请求头中;接收方必须用原始字节重新计算并做常数时间比较,避免提前返回泄露时序信息。常见错误包括:解析 JSON 后重新序列化再验签(字节不一致导致误判)、使用普通字符串比较、以及未校验时间戳导致重放攻击。此外,webhook 密钥绝不能有默认值或出现在 README 示例中,否则任何人都能伪造“已支付”事件,直接绕过付费墙。

两轮战报:同分,但失败方式完全不同

两款工具都拿到20/20。Cursor快6分钟,自带gitignore,升级流程直接能用;Copilot有可撤销的真实会话和登录限流。共同点是两者都带着默认密钥出厂。

作者给出三条部署前自查:删掉compose文件里每一个默认密钥,让应用在缺少真实密钥时拒绝启动;确认登出真正结束会话,尤其是用JWT时;在登录和注册上补限流——Cursor不会主动做,除非你要求。

下一场是Google的免费命令行agent Gemini CLI,同一份提示词。五款工具跑完后,作者会逐一攻击这些应用:伪造支付、窃取令牌、数千用户并发。

对开发者的实用结论:AI编程工具在"能跑通"这件事上已经相当可靠,默认模型加免费计划也能在个位数分钟产出可运行的全栈应用。但"生产就绪"里的安全默认值,目前仍需要人盯着。速度提升是真实的,把默认密钥删掉这件事,也得是真实的。

#Cursor#GitHub Copilot#AI编程工具#免费AI编程#Agent Mode#生产级应用#JWT安全#AI代码安全
分享:

相关推荐