无畏CORS:CORS中间件库的设计哲学(及Go实现)
TL;DR
本文探究开发者为何难以驾驭CORS,并提出“无畏CORS”设计哲学,包含12条原则:
- 优化可读性
- 追求简洁一致的API
- 支持私有网络访问(PNA)
- 正确分类请求
- 验证配置并快速失败
- 将CORS视为编译目标
- 不提供默认配置
- 不阻碍合法配置
- 通过避免预检捷径简化调试
- 杜绝不安全配置
- 保证配置不可变性
- 聚焦中间件执行性能
同时介绍符合该哲学的开源Go库jub0bs/fcors。
CORS 101
跨源资源共享(CORS)是一种机制,允许服务器指示浏览器为特定客户端放宽同源策略(SOP)对跨源网络访问的限制。该协议依赖特殊HTTP头(如Origin
、Access-Control-Allow-Origin
等)。典型CORS握手流程:
- 用户访问网站A
- 网站A的客户端向网站B的服务器发送GET请求(含
Authorization
头) - 浏览器先发送OPTIONS预检请求
- 服务器返回预检响应,授权实际请求
- 浏览器发送实际请求并获取响应
CORS困境
自2000年代末诞生以来,CORS虽是现代Web开发的关键机制,却仍是开发者的常见困惑源。Stack Overflow上约12,500个CORS相关问题中,大量来自痛苦经历。错误配置不仅影响功能,更可能引发安全风险,例如过度宽松的策略可能导致跨源攻击。
设计原则详解
1. 优化可读性
对比命令式(如rs/cors)与声明式(jub0bs/fcors)配置:
|
|
声明式风格减少视觉干扰,通过函数式选项模式提升可读性和可审查性。
2. 简洁一致的API
避免API冗余(如rs/cors提供三种允许源设置方式)。jub0bs/fcors仅提供FromOrigins
和FromAnyOrigin
两个正交选项,并在重复/冲突选项时报错。
3. 支持私有网络访问(PNA)
PNA加强SOP,限制公网客户端访问本地网络。jub0bs/fcors通过风险包支持PNA,并禁止允许所有源访问私有网络。
4. 正确分类请求
许多库(如Express.js)错误地将含Origin
头的请求均视为跨源请求,导致非预检OPTIONS请求被拦截。jub0bs/fcors正确识别预检请求,无需额外选项。
5. 验证配置并快速失败
许多库(如Fiber、rs/cors)缺少配置验证,产生功能异常的中间件。jub0bs/fcors在初始化时严格验证来源、头、方法等,提供即时反馈。
6. 将CORS视为编译目标
通配符异常(wildcard exception)规定:含凭据的请求不能使用通配符(*
)。许多库(如Express.js、Echo)允许矛盾配置(如origin: '*'
与credentials: true
),导致功能异常或安全风险。jub0bs/fcors禁止显式使用通配符,强制高级声明式配置,并利用类型系统防止凭据访问所有源。
7. 不提供默认配置
启用CORS总会削弱安全性,因此唯一安全的默认配置是不启用CORS。jub0bs/fcors强制开发者明确配置,避免意外风险。
8. 不阻碍合法配置
- 禁用预检缓存:rs/cors等库忽略
Max-Age: 0
,jub0bs/fcors支持禁用缓存。 - 方法名大小写敏感:许多库错误规范化方法名(如"patch"变为"PATCH"),导致预检失败。jub0bs/fcors保持大小写敏感。
- Max-Age类型:避免使用支持秒以下精度的类型(如
time.Duration
),防止误导性配置。
9. 通过避免预检捷径简化调试
早期W3C规范建议预检失败时省略所有CORS头,导致浏览器返回误导性错误(如“缺少Access-Control-Allow-Origin”)。jub0bs/fcors遵循Fetch标准,避免捷径,返回详细错误信息(如“头字段bar未被允许”)。
10. 杜绝不安全配置
- 禁止null来源:除安全实验室外无合法用例。
- 默认禁止不安全来源:禁止
http
来源(localhost除外),需显式启用风险选项。 - 限制来源模式:支持有限模式(如
https://*.example.com
),禁止过于宽松的模式(如https://*
),并默认检查公共后缀。 - 禁止自定义回调:避免滥用导致安全风险(如无条件返回true)或缓存中毒。
11. 保证配置不可变性
动态更新CORS配置可能引发竞态条件。jub0bs/fcors中间件不可变,配置变更需重启服务器,促进变更审查。
12. 聚焦中间件执行性能
jub0bs/fcors在初始化时进行更多验证(慢20倍),但执行时更高效(少分配内存、更快处理)。通过约束来源模式类型和禁止回调,确保执行性能。
结论
jub0bs/fcors是符合无畏CORS哲学的生产级Go库,强调安全、可读性和性能。欢迎试用并提供反馈。
致谢
感谢Michael Smith、Mat Ryer的技术审阅,以及Anne Van Kesteren、Jake Archibald对CORS协议的澄清。Joshua Bloch和John Ousterhout的著作对本文哲学有深远影响。