#jwt #image #url #token #proxy #ssl #authorization

bin+lib ecamo

SSL 图像代理与 JWT 认证

1 个不稳定版本

0.1.0 2022年1月26日

#ssl 中排名第 31

MIT 许可证

81KB
2K SLoC

艾卡莫 - SSL 图像代理与 JWT 认证

艾卡莫(嵌入式艾卡莫)是一个受 atmos/camo 严重影响而创建的 HTTP 反向代理。

原始 Camo 的目的是为了在明文 HTTP 服务器后面加载图像,以避免混合内容问题。除此之外,艾卡莫还旨在在加载其他来源的图像时避免使用第三方cookie(例如需要适当会话cookie的公司内部截图服务器)。

我们已经在内部维基中使用 Camo 很长时间来提供一些外部图像,但由于最近关于第三方cookie的活动,我们需要一个类似的系统,以允许在不使用第三方cookie的情况下嵌入内部截图服务。

工作原理(简要说明)

基本上,与 Camo 一样,艾卡莫接收 URL 数据并代表用户检索 URL 上的资源。

与 Camo 不同,必须在一个具有艾卡莫预定义前缀的路径下为艾卡莫设置 的路由。例如,当将 艾卡莫前缀 设置为 /.ecamo/ 时,则任何以 /.ecamo/ 前缀开头的源请求应路由到艾卡莫服务器。单个艾卡莫服务器适用于多个应用程序(= 源)。

艾卡莫设计如下。

<!-- On origin https://wiki.corp.example.com -->
<img src="/.ecamo/v1/r/{URL_TOKEN}...">

在此示例中,一个 wiki.corp.example.com 并期望为艾卡莫设置一个 授权cookie。并且 URL_TOKEN 指定了实际内容的 URL。授权cookie和URL令牌格式为JWT,并由源拥有的P-256私钥签名。

然后艾卡莫将此URL重定向到基于授权cookie的短期令牌的艾卡莫的 规范源。用户将从 接收指定的URL的实际内容。

部署

配置

配置通过环境变量完成。

  • ECAMO_BIND(默认:[::]:3000):绑定地址
  • ECAMO_CANONICAL_HOST(必需):规范源的 HTTP Host 标头值。用于提供实际内容。您可能需要指定非标准端口号。
  • ECAMO_SERVICE_PUBLIC_KEYS(必需):JSON对象,键为"${SERVICE_ORIGIN} ${kid}",值为JWK对象,由服务用于签名授权cookie和ecamo URL。支持ES256密钥。例如:{"https://service.test.invalid key_1": {"kid": "key_1", ...}}
  • ECAMO_PRIVATE_KEYS(必需):JSON对象,键为token kid,值为JWK对象,由Ecamo用于在URL和请求头中签名短暂授权令牌。支持ES256密钥。
  • ECAMO_SIGNING_KID:主私钥kid,通过$ECAMO_PRIVATE_KEYS提供。
  • ECAMO_SERVICE_HOST_REGEXP:用于验证服务源 Host头的正则表达式。当未指定时,任何来源都作为服务源
  • ECAMO_SOURCE_ALLOWED_REGEXP:用于验证源URL的正则表达式。当指定时,任何不匹配的源URL将被拒绝。
  • ECAMO_SOURCE_BLOCKED_REGEXP:用于拒绝源URL的正则表达式。当指定时,任何匹配的源URL将被拒绝。
  • ECAMO_PRIVATE_SOURCE_ALLOWED_REGEXP:用于验证目标IP地址解析为私有IP地址时的源URL;URL可能仅包括方案、主机和端口。任何不匹配的连接到私有IP地址的源URL将被拒绝。当未指定时,任何尝试连接到私有IP地址的连接尝试将被拒绝。注意,URL还必须通过ECAMO_SOURCE_ALLOWED_REGEXP允许。
  • ECAMO_PREFIX(默认:.ecamo):前面解释过的ecamo前缀。这是一个特别用于嵌入在服务源中的URL前缀,更确切地说,用于从规范源重定向请求到服务源
  • ECAMO_MAX_REDIRECTS(默认:0):在单个HTTP请求中允许的HTTP重定向的最大数量,用于获取源URL。当允许时,在跟随重定向时,任何URL都将被允许(当ECAMO_*_REGEXP不起作用但ECAMO_PRIVATE_SOURCE_ALLOWED_REGEXP起作用时)
  • ECAMO_MAX_LENGTH:从源URL允许代理的最大Content-Length数。如果分块响应超出限制,则此类代理响应将被终止(客户端将看到意外的EOF)
  • ECAMO_CONTENT_TYPE_ALLOWED(默认:常见image/*类型):允许代理的Content-Type。指定为逗号分隔的值。
  • ECAMO_TIMEOUT:获取源URL的秒数超时。
  • ECAMO_AUTH_COOKIE(默认:__Host-ecamo_token,当不安全模式=ecamo_token时):用于存储授权令牌的Cookie名称。
  • ECAMO_DEFUALT_CACHE_CONTROL(默认=public, max-age=3600):当源URL响应中缺少缓存控制头时,响应的缓存控制头值
  • ECAMO_INSECURE:当启用时,某些功能将使用纯HTTP进行开发。

sec-x-ecamo-service-host

您可以使用sec-x-ecamo-service-host请求头来向Ecamo服务器显式指定一个服务来源Host头。这特别适用于您将Ecamo服务器放在反向代理后面,并且需要设置特定的Host:authority)头的情况。

(另一方面,这与X-Forwarded-Host请求头类似)

用法

要使用Ecamo,服务来源必须生成一个URL令牌和一个授权令牌

生成ecamo URL

使用以下格式向Ecamo发送请求:

https://${SERVICE_HOST}/${PREFIX}/v1/r/${URL_TOKEN}

其中

  • SERVICE_HOST:允许任何字符串,但需符合$ECAMO_SERVICE_HOST_REGEXP
  • PREFIX:建议与$ECAMO_PREFIX相同,但允许任何字符串。
  • URL_TOKEN:JWT(JSON Web Token),具有以下约束
    • 头部
      • alg:必须是ES256
      • kid:必须设置为在$ECAMO_SIGNING_PUBLIC_KEYS
    • 声明
      • iss:必须与服务来源的Web来源相同。(例如:https://service.test.invalid
      • ecamo:url:源URL
      • ecamo:send-token(可选):设置为true以向源URL发送匿名ID令牌

注意

  • 请注意,每个签名操作生成的URL令牌都是不确定的。如果您打算启用边缘缓存,请确保您的应用程序尽可能不频繁地生成ecamo URL。
  • expnbf声明未进行验证。

授权cookie是由$ECAMO_SIGNING_PUBLIC_KEYS中指定的密钥签名的JWT,具有以下约束。它应存储在名为$ECAMO_AUTH_COOKIE(默认为__Host-ecamo_token)的cookie中。

  • 头部
    • alg:必须是ES256
    • kid:必须设置为在$ECAMO_SIGNING_PUBLIC_KEYS
  • 声明
    • exp必须提供。
    • iss必须与服务来源的Web来源相同。(例如:https://service.test.invalid
    • aud必须设置为规范来源的Web来源。(例如:https://$ECAMO_CANONICAL_HOST
  • 建议
    • 使cookie过期时间和令牌生命周期保持一致。
    • 尽可能缩短生命周期。一般来说,在Cookies中使用JWT是一个糟糕的想法使用JWT在Cookies中,但假设应用程序在其自己的地方进行身份验证,并且ecamo-token是从其会话存储中派生的。如果可以从其他会话令牌中派生出ecamo-token,那么其生命周期可以很短。

杂项

重定向到源地址

为了使用户能够识别请求内容的规范URL,当最终用户直接打开/.ecamo/... URL时,Ecamo会直接将其重定向到源图像(更确切地说,当请求没有授权Cookie或请求Sec-Fetch-Dest=document时)。

匿名ID令牌

如果URL令牌的ecamo:send-token设置为true,Ecamo将设置一个ID令牌作为Bearer令牌(Authorization: Bearer ...)。

该令牌不包含用户信息,例如

{
  "iss": "https://ecamo.test.invalid",
  "sub": "anonymous",
  "aud": "https://source.test.invalid",
  "exp": ...,
  "iat": ...,
  "ecamo:svc": "https://service.test.invalid"
}

与CDN一起使用

SSRF预防(私有IP地址)

由于reqwest当前API的限制,当配置了$ECAMO_PRIVATE_SOURCE_ALLOWED_REGEXP时,Ecamo将启动一个SOCKS5代理来限制连接到私有IP地址。内部代理仅用于不匹配$ECAMO_PRIVATE_SOURCE_ALLOWED_REGEXP的请求。对于此类请求,将拒绝以下地址的任何尝试

许可

MIT许可证

版权所有 2021 Cookpad Inc.

依赖项

~11–29MB
~440K SLoC