有趣且轻量的 CDN URL 鉴权方式: 时间戳 Token 鉴权
本文最后更新于 2025年1月16日 凌晨
为了防止 CDN 的 资源被盗刷而产生高额流量费;CDN 云厂商通常会给予我们简单的权限认证,避免未授权的文件被访问,进而避免资源被盗刷。我尝试了一下腾讯云基于时间戳的 Token 鉴权,还是挺巧妙和轻量的,这里分享给大家。
CDN 内容分发
首先科普一下 CDN (Content Delivery Network) : 我们都知道,服务器带宽资源有限,当多用户同时进行下载时,服务器可能承受不住压力。此外,由于网络环境的复杂性,不同地区访问服务器时的延迟会有所不同,甚至会在某些地区遇到较高的丢包率。
可以看到,我当前的网络环境,访问我的博客是非常稳定的。
因为我使用了 CDN (实际上是腾讯云 EdgeOne,相当于在 CDN 的边缘节点加速的情况下,加上了 WAF 功能): 通过在全球多个地点部署服务器,将内容缓存到不同的节点服务器,用户访问网站内容时,优先从节点获取内容数据,从而减少了数据传输的距离和时间,提高了访问速度和网站的整体性能,减轻源站服务器的压力。
graph LR
User1[用户1] --> Node1[CDN 边缘节点]
User2[用户2] --> Node2[CDN 边缘节点]
User3[用户3] --> Node3[CDN 边缘节点]
Node1 --> CDN[CDN 边缘/收敛节点]
Node2 --> CDN[CDN 边缘/收敛节点]
Node3 --> CDN[CDN 边缘/收敛节点]
CDN --> Origin[源服务器]
subgraph 全球边缘节点
Node1
Node2
Node3
end
CDN 本身其实就是一个缓存服务器,但是云厂商通常会提供一些额外的功能,比如:缓存、防盗链、限速、限流、鉴权等。我们文章介绍的是 CDN 的鉴权功能,就是衍生的功能,用来配合存储桶,非常合适。
对象存储桶
对象存储桶,是云厂商提供的一种存储服务,只是叫法可能不同,比如:Amazon S3、Google Cloud Storage、腾讯云 COS 和阿里云 OSS等。
它提供的是对象存储服务,即存储的是对象,每个对象包含一个键值对,键是对象名,值是对象内容(类似于 Redis 的 key-value)。如果只存储文件,那么使用存储桶是不错的选择。
是不是有很多小伙伴问,为什么不直接用服务器存储? Nginx 开启一个目录映射,似乎也不是很麻烦,而且还可以鉴权。我最开始用存储桶也有这个想法,但是对比之下,主要有以下几个原因:
- 成本更低、性能高效:存储桶通常比云服务器的存储成本更低。云服务器不仅需要支付存储费用,还需要支付计算资源的费用;并且云服务器通常需要配置额外的网络和安全措施,而存储桶则不需要。
- 可扩展、高可用:存储桶提供了几乎无限的存储空间,可以轻松扩展,甚至是扩展到 TB 级别;而云服务器通常需要配置额外的网络和安全措施,以支持高可用性和扩展性。
如果你使用 Serverless 服务,那么存储桶还可以作为持久化数据的存储中心。比如: Serverless 搭建 WordPress,网站图片和 HTML 等数据存储在存储桶,使用 CDN 配合域名给用户提供访问服务。
联动 CDN
实际上,我们使用存储桶,都会激活一个默认的域名,比如我在腾讯云上新建的存储桶:
存储桶通常是一个地区的数据,跨地区访问,我们通常会将存储桶和 云厂商的 CDN 联动,实现跨地区加速访问和公有访问资源的防盗刷、轻量鉴权。
举个例子:
- Case 1: 我们的存储桶可能是上海的某个地区,我们上传 App 的更新包到其中;如果只使用存储通,所有用户都从存储桶所在的上海地区下载,那么下载速度可能就会比较慢。这个时候,我们可以将 CDN 节点部署在离用户更近的地方,比如北京、广州等地区,这样用户下载时,就会从就近的 CDN 节点下载,从而提高下载速度。
- Case 2: 我们使用存储桶当作图床,肯定是公有读;但是为了防止存储桶被盗刷,我们可以设置私有读,使用 CDN 公有范围。最后,当前端渲染图片的时候,资源的加载走 CDN 配合 Token 鉴权的方式完成,可以防止图片被盗问题。
flowchart LR
User([公网用户])
subgraph Public["公有读私有写方案"]
B1[存储桶]
end
subgraph Private["私有读、私有写+CDN方案"]
B2[边缘节点缓存资源/回源存储桶]
CDN[边缘节点]
Auth[Token鉴权]
end
User -->|直接访问| B1
User -->|携带Token| CDN
CDN -->|鉴权| Auth
Auth -->|验证通过| B2
Auth -->|验证失败| X[拒绝访问]
style Public fill:#e1f3d8
style Private fill:#fbe5e1
细看 Case 2,腾讯云的 CDN 主要有两种鉴权方式:远程鉴权 和 Token 鉴权(URL 时间戳鉴权)。
远程鉴权,需要使用云函数、云服务器等,设置自己的鉴权逻辑:
sequenceDiagram
participant Client as 客户端
participant CDN as 边缘节点
participant AuthServer as 鉴权服务器
Client->>CDN: 发送请求(包含鉴权参数)
CDN->>AuthServer: 转发请求
AuthServer-->>CDN: 返回鉴权结果
CDN->>Client: 响应客户端(允许/拒绝访问)
相比之下,我觉得 Token 鉴权方式更轻量,不需要额外的服务器;基于时间戳来绑定有效期,也可以防止盗刷:
sequenceDiagram
participant 客户端
participant 边缘节点
客户端->>边缘节点: 发起请求(携带签名和时间戳)
边缘节点->>边缘节点: 解析请求中的签名和时间戳
边缘节点->>边缘节点: 获取鉴权算法并计算预期签名
边缘节点->>边缘节点: 对比预期签名和请求签名
alt 校验通过
边缘节点->>客户端: 返回节点缓存内容
else 校验失败
边缘节点->>客户端: 拒绝访问请求
end
还是挺有趣的。我们来看一下。
支持创作
制作教程不易,如果热心的小伙伴,想支持创作,可以加入我们的电圈(还可以解锁远程协助、好友位😃):
- Mintimate的电圈: https://afdian.com/a/mintimate
- Mintimate的微信赞赏码 👉 如果认为本教程对你很有帮助,可以请我喝咖啡 ☕
志同道合的小伙伴也是知音难觅。
- 开发者爱好群: 👉 如果你对云服务器、CDN、云数据库和Linux等云计算感兴趣,亦或者喜欢编程、设计、产品、运营等领域,欢迎加入我们的开发者爱好群,一起交流学习(目前可能就我一个人?🤔,毕竟才刚刚创建~)。
当然,也欢迎在B站、YouTube或微信公众号上关注我们:
- Bilibili: https://space.bilibili.com/355567627
- YouTube: https://www.youtube.com/@mintimate/featured
- 微信公众号: MintimateBlog
更多:
时间戳鉴权
终于到了“硬菜”了。前文说到,使用时间戳鉴权,就是改变 URL 的内容,内部添加 token 参数,当 token 无效(时间过期、篡改)时,拒绝访问。
细看时间戳鉴权。以腾讯云 CDN(包括 EdgeOne)为例,主要有四种鉴权签名计算方式:
- TypeA: 在请求的 URL 末尾附加一个计算出的签名,该签名通过将资源请求路径、时间戳、密钥以及一串随机字符串拼接起来,并对其进行MD5哈希运算得到。
- TypeB: 重新排列 URL 的目录结构,在域名和路径之间插入时间戳和计算出的签名,该签名通过将资源请求路径、时间戳以及密钥拼接起来,并对其进行MD5哈希运算得到。
- TypeC: 同样重新排列 URL 的目录结构,与 TypeB不同的是,时间戳使用十六进制表示。
- TypeD: 与 TypeA 类似,只是末尾附加计算出来的签名同时,附带时间戳。计算签名使用密钥、资源请求路径和时间戳拼接起来,并对其进行MD5哈希运算得到。时间戳支持十进制和十六进制表示。
我们以 TypeD 为例,来演示一下时间戳鉴权。首先,在腾讯云的 CDN 或者 EdgeOne 管理控制台,并且联动了腾讯云的 COS 存储桶:
配置当前的鉴权方式为 TypeD,然后配置密钥和过期时间,如下图所示:
可以看到,主要设置了:
- URL Path: URL 路径。我这里使用即存储桶的路径,比如:
/private/1.jpg
。我这里使用正则匹配。 - Token 鉴权: Token 鉴权选择了 TypeD,并且设置了主/备密钥、鉴权加密串参数名称、鉴权时间戳参数名称、时间格式为十六进制以及过期时间。
最后的 URL 形式是将https://www.example.com/private/demo/demo.png
计算为https://www.example.com/private/demo/demo.png?sign=99883f521c85d00dd0a39ac6854269b1&t=675efd21
。
当我们的 URL 发送到 CDN/EdgeOne 的 边缘节点 时,边缘节点 服务器解析出 URL 中的 时间戳参数 与 Token 鉴权 与当前时间进行比较:
- 如果 时间戳参数 有效时长小于当前时间,则服务器判定过期失效,并返回 HTTP 403错误。
- 如果 时间戳参数 有效时长大于当前时间,则使用 MD5 算法算出 md5hash 的值,再比较计算出来的 md5hash 值与 URL 中传入的 Token 鉴权 值,如果一致则放过,不一致则返回 HTTP 403错误。
那么?我们如何计算签名和时间戳呢?
代码实现
首先,我们需要安装一个 MD5 加密库;在实际的使用过程中,将原 URL 计算出 EdgeOne 目标 URL 过程应该是后端进行的,我这里为了方便,直接前端 JavaScript 实现。
为了实现 MD5 加密,方法很多,比如:crypto-js或者js-md5;然后,我们就可以使用 MD5 加密库来计算签名和时间戳了。我这里使用 js-md5:
1 |
|
根据 TokenD 的计算方式,我们可以写一个 JavaScript 的函数,来计算签名和时间戳:
1 |
|
我们顺便也写一个前端,来测试一下:腾讯云 CDN / EO Token 鉴权生成
当然,为了更好的 Demo ,我实际上还有代码实现其他几种方式,比如:TypeA、TypeB、TypeC、TypeD,感兴趣的可以查看源码。
END
好了,关于腾讯云 CDN 的 Token 验证内容,就介绍到这里啦。感谢你的阅读。如果觉得文章对你有点帮助,记得分享给身边的小伙伴哦。其实 CDN 的扩展性挺高的,对网站的体验改善也非常不错,小伙伴们可以多尝试,多体验。
最后,如果你觉得本篇教程对你有帮助,迎加入我们的开发者交流群: 812198734 ,一起交流学习,共同进步。