业务场景
网站上的图片在没有加水印的情况下,会被他人爬取,比如文章类的网站,为了防止图片被大量爬取,可使用防盗链。阿里云CDN提供了Referer、UA黑/白名单、IP黑/白名单、URL鉴权、远程鉴权几种防盗链方式,本文介绍常用的几种方式。
准备内容
- CDN
- 可访问的图片站点或者OSS
操作步骤
方式1 IP黑/白名单
白名单比较简单,将允许访问的IP配置到规则中,那么仅只有ip在范围内的可访问,比如一些公司内的文件只有公司的 IP 可以访问。
黑名单用于拒绝某些IP的访问,比如当发现站点被攻击时,可通过访问的日志找到攻击的IP,然后配置黑名单后拒绝对应 IP 的请求。所以找到这个攻击的IP就比较重要,这里提供两个途径判断这个攻击IP,一个是网站的Nginx日志,一个是CDN本身的日志信息。
- nginx日志
这里的前提条件是你的网站只有一部分资源接入CDN,比如仅将图片、css、js这类的静态文件缓存在CDN,一些数据获取的接口访问的是源站。此时如果攻击者大批量访问网站时,会有一些数据接口会命中源站,这时就可以通过nginx日志来查询找出攻击IP。下图中的 remote_addr 即为访问者的IP,如果发现这个ip在非常短的时间内产生了很多的访问信息,并且这个量超出了你网站正常的访问量,那么基本可以确定为攻击的IP。
- CDN日志
CDN的日志有离线日志和实时日志两种,通过日志文件我们可以看到访问者的相关信息,以离线日志内容为例:
[23/May/2022:13:55:31 +0800] 121.237.219.31 - 452 "https://your.domain.com/product/list" "GET https://your.domain.com/2021/11/18/b4c01a61a270690082ce5bd410959c07.jpg" 200 909 44472 MISS "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.4951.67 Safari/537.36" "image/jpeg"
通过日志我们可以获取访问者的IP,通过日志分析出攻击IP后将其加入黑名单即可。这里我们还可以将日志转存到OSS,利用Maxcompute、Datalake等工具可以更方便的分析日志,此处就不做过多介绍了。
方式2 UA黑/白名单
如果你不想网站的内容不想被爬虫爬取的话,可以使用UA黑名单来进行控制。通过服务器访问日志,可以获取访问者的UA,此处以nginx的访问日志为例,如下:
我们取两者UA中共同的 spider 关键字进行配置:
配置完成后所有UA中包含spider的访问都会被拒绝。
方式3 Referer防盗链
Referer防盗链用的比较多的是配置白名单,也就是仅允许你认可的站点访问你的资源。比如,图片类的资源,我们一般就希望仅自己的站点可以引用访问,其他站点不可访问,比如微信公众号里面的图片不可以在其他的站点使用,那么此时就可以通过referer白名单来进行控制。
通常我们会以站点一级域名的通配符方式配置规则,这样无论是二级域名还是三级域名都可以命中这条规则。白名单配置后,如果不在白名单范围内的站点引用资源就会出现403。
方式3 URL鉴权
以CDN缓存OSS的图片资源为例,为了防止爬虫、故意刷图的情况,可以使用URL鉴权的方式生成动态链接。
1、鉴权方式A
- 图片路径:/images/2022/05/07/_MG_0090.jpg,开启鉴权后访问原图返回403
- 鉴权URL生成代码(PHP版本)
function getCDNAuthUrlA($filePath){ $fileDomain = "https://your.domain.com"; $timestamp = time(); $rand = uniqid(mt_rand(), true); $privateKey = 'aliyuncdntest'; $md5hash = md5($filePath.'-'.$timestamp.'-'.$rand.'-0-'.$privateKey); $fileUrl = $fileDomain.$filePath.'?auth_key='.$timestamp.'-'.$rand.'-0-'.$md5hash; return $fileUrl; } //获取URL地址 $filePath = '/images/2022/05/07/_MG_0090.jpg'; $fileUrl = getCDNAuthUrlA($filePath);
2、鉴权方式B
- 鉴权URL生成代码(PHP版本)
function getCDNAuthUrlB($filePath,$minutes=0){ $fileDomain = "https://your.domain.com"; $timestamp = date('YmdHi',strtotime('+'.$minutes.' minutes')); $privateKey = 'aliyuncdntest'; $md5hash = md5($privateKey.$timestamp.$filePath); $fileUrl = $fileDomain.'/'.$timestamp.'/'.$md5hash.$filePath; return $fileUrl; } //获取URL $filePath = '/images/2022/05/07/_MG_0090.jpg'; $fileUrl = $this->getCDNAuthUrlB($filePath,3);
鉴权方式B允许我们在控制台设置的有效时间基础上再定义时长,所以这里我们在生成鉴权的时候增加了一个参数 minutes(分钟),这个参数将和我们控制台设置的时间共同决定了链接的有效时长。本例中的有效时长为 33 分钟 (1800秒+3分钟)。
3、鉴权方式C
- 鉴权URL生成代码(PHP版本)
private function getCDNAuthUrlC($filePath,$minutes=0){ $fileDomain = "https://your.domain.com"; $timestamp = dechex(strtotime('+'.$minutes.' minutes')); $privateKey = 'aliyuncdntest'; $md5hash = md5($privateKey.$filePath.$timestamp); $fileUrl1 = $fileDomain.'/'.$md5hash.'/'.$timestamp.$filePath; $fileUrl2 = $fileDomain.$filePath.'?key1='.$md5hash.'&key2='.$timestamp; return [$fileUrl1,$fileUrl2]; } //获取URL $filePath = '/images/2022/05/07/_MG_0090.jpg'; $fileUrl = $this->getCDNAuthUrlC($filePath,3);
与方式B相同,参数 minutes 与控制台设置的有效时间共同决定了链接的有效时间。
结语
针对不同的应用场景,选择适合你的防盗链可以让你的网站更安全。