【杂谈】jsDelivr域名遭到DNS污染

发布于 2022年4月29日 / 日常杂谈 / 68 条评论

在jsDelivr被吊销ICP许可证四个月后的4月28日,cdn.jsdelivr.net开始遭到污染,这一个赫赫有名的静态资源库面向中国大陆的服务最终倒在了政策和监管双重压力之下。

结束了三月的研究生复试,四月的博主更多是投身在荒废的大四生活和毕业论文撰写之中。很长时间没有更新博客了。恰好今天看到jsDelivr出现了如此严重的意外,就来简单聊聊jsDelivr的大陆服务是如何走向终点的,顺便给出一些博主建议的解决方案。


零、写在前面

虽然从四个月前那次宕机失去中国大陆CDN开始,很大一部分网站已经陆陆续续将静态资源切出jsDelivr,但是碍于jsDelivr多年的深耕以及服务的独特性,仍有不少场景下引用有jsDelivr的链接。不同于以往的短时间宕机,这次的“污染”几近于死刑,意味着 cdn.jsdelivr.net在中国大陆服务的彻底终结,从此这个网站将不再是慢,而是不可及。

*再次提醒 :建议各位站长细致检查个人站点前端主题、插件、脚本等内容中对jsDelivr的引用,以避免由于jsDelivr不可及导致的加载卡顿和前端无法正常加载的情况。

Update 2022.04.29

污染已解除,文章内容仅供参考,应该是当局发现影响范围实在太大了吧~

Update 2022.05.17

再次被污染,并且增加了伴随的sni阻断,hosts不再有效。二进宫实惨,尽快着手转移吧。


壹、jsDelivr的命运

2022年4月28日,jsDelivr得到了与Facebook、Twitter等如出一辙的安排,主要的服务域名遭到DNS污染。在正常状态下,当你请求网站域名域名时,你的DNS服务器会逐级向上寻找这个域名的解析记录,并通过这个链条将它指向的服务器返回给你,实现域名与服务器的融合。若你的DNS逐级向上请求记录的过程中,出现了一个中间人提前抢答了错误的记录,而非来自域名权威服务器的正确回复,导致返回的结果并不是指向正确服务器的,连接因此不能建立,这便是DNS污染。其中的原因,还是要从一开始说起。

惊艳四座的jsDelivr

不知道提到jsDelivr,大家都是从哪一项服务开始接触到它的?由中国最大的传统CDN提供商网宿(QUANTIL)赞助,支持 cdnjsGitHub内容直接加速引用,它的应用可以说是迄今为止所有静态库中最为广泛的了。大到各种门户网站,小到个人博客,乃至去广告规则订阅、图床、插件静态库等等种种衍生场景,都能见到它的身影。

在网宿的协助下,2016年12月jsDelivr挂名在上海幻文信息科技有限公司下完成了企业ICP备案,取得了备案号【沪ICP备15005128号-2】。这是一家网宿用于代理备案的公司,通过天眼查等工具很容易看出来,历史上共有8个网站在这个公司挂名进行备案,目前除了所谓的主页已全部注销。

这是历史上第一个以较为正规的方式进入中国大陆的海外静态资源库项目,在网宿与诸多海外赞助商协同下,5年中jsDelivr提供了非常稳定且出色的服务。jsDelivr官方毫不掩饰对自己能够在中国大陆合法提供服务的喜悦,专门在节点页面中写下了“我们拥有中国政府的ICP许可证,拥有数百个服务节点的巨大中国网络”的字眼。

然而千里之堤溃于蚁穴,纵使拥有网宿这样强有力的支撑,也难抵运营以来遇到的重重阻碍。

一波三折的大陆服务

在网宿负责中国大陆的CDN节点这几年中,因为网宿方面的问题导致了几次SSL证书过期而宕机,博主有印象的在2019、2020年都有出现过。如果说那些都是网宿单方面的失误的话,2019年10月的暂时退出是jsDelivr官方面临的第一次危机。2018年工信部对域名备案政策颁布了新的规定,只有注册局在中国大陆拥有代理公司并完成申报、且域名停放在在中国大陆注册商的情况下才可以进行备案。jsDelivr挂名的公司在2019年需要进行了负责人信息的变更,备案主体信息需要进行修改,这在多个域名中都可以查到记录。

当时,jsDelivr暂时关闭了中国大陆的节点,转而使用网宿位于中国台湾和韩国首尔的节点提供服务,加载速度一落千丈。当时博主还向官方发送了一封邮件进行了咨询,官方也亲切地回应是在更新ICP备案,将在不久之后恢复。较早的issue中,官方人员进行了更详细的解释,他们在更新ICP备案的过程中遇到新规的要求将备案域名转入至中国大陆的服务商的问题,在评估后他们认为没有一种安全的方式能够确保在服务不中断的前提下将域名转移至中国大陆,因此暂时关闭中国大陆的节点等待进一步的探讨。最终在一个月后,jsDelivr恢复了位于中国大陆的节点,这次风波算是告一段落。

接下来的三年中大体相安无事,除了几乎每年一度的网宿忘记更新SSL证书。但是由于支持对GitHub项目的完整加速,对jsDelivr的滥用日趋严重,GitHub+jsDelivr图床、视频床甚至网盘层出不穷。如果说以上只是对免费资源的滥用,在GitHub中储存成人、邪教等文件通过jsDelivr向中国大陆分发,则是将jsDelivr一步步推向万丈深渊。

在2020年的8月15日,jsDelivr在官方GitHub项目中首次更新了使用限制说明(点击前往),我截取了其中较为重要的一部分,这是官方第一次明确表示禁止多种滥用行为并添加了对中国大陆政策的额外说明。在这之后,官方在网宿方向屏蔽了一系列不符合中国大陆法律内容的项目。但是由于是针对整个GitHub项目的通用加速,官方的封禁显然远远比不过肆意滥用的脚步。

命中注定的结局

jsDelivr对中国大陆的态度一直颇为暧昧,在2019年风波平息后,有不少人提议针对中国大陆的服务中GitHub加速项目应当审核开放或关闭此项以防止滥用,但官方认为将项目推送cdnjs也是很容易的事,单单禁用GitHub并不能解决不合理利用的问题,于是便没有了后文。

于是在2021年12月20日,当项目组成员在另一个半球睡得正香的时候,自上而下的命令压力下网宿直接关闭了jsDelivr的大陆CDN,几个小时后jsDelivr的ICP备案也被注销。当jsDelivr项目工作人员起来时,一脸茫然地发现网宿在未告知原因的情况下关闭了中国大陆的CDN,在愤怒之余将DNS记录切换至了Fastly恢复了jsDelivr的访问,这次的风波暂时告一段落。

但是网宿这次为何突然关闭CDN的原因依然众说纷纭,有内部人士称是因为网安部门发现了通过jsDelivr的链接传播邪教内容,但这些无从考证,官方自始至终也未对此给出任何解释。但无法改变的是,jsDelivr失去了ICP许可证,不再拥有位于中国大陆的CDN节点,加载速度大幅下降,官方也不再通过区域服务商对内容进行过滤。

在这之前有一个同样支持GitHub加速的静态资源库 statically.io已被SNI阻断,与曾经的jsDelivr唯一的不同便是没有ICP许可证的保护。它走过的路,冥冥中暗示着jsDelivr注定的结局。

2022年4月28日,jsDelivr在中国大陆确认遭到DNS污染,乐章到此戛然而止。


贰、jsDelivr的替代方案

遭到DNS污染,基本宣告这个域名面向大众的服务失去价值,因为你无法让每个人学习像极客一样学会修改hosts、使用DoH分流。特别是前端引用这样面向用户的场景,应当更多考虑用户的便利性。以下博主提供几种可行的方案供大家参考,希望对大家有所帮助。

针对恢复访问主要分为服务和本地两种场景,服务场景修改则是替换jsDelivr资源到可访问的资源上,本地场景修改恢复访问的目的是针对海外引用jsDelivr的站点,这是两种不同的操作和目标。

服务·官方子域

这次的污染只针对 cdn.jsdelivr.net这一个域名,jsDelivr有很多的CDN赞助商共同支持,每一个服务商都会有自己的专有子域名,通过替换访问资源到其他的二级域名可以恢复访问。但这些CDN普遍速度一般,而且前途并不明朗,建议仅供临时使用。

CloudFlare:test1.jsdelivr.net
CloudFlare:testingcf.jsdelivr.net
Fastly:fastly.jsdelivr.net
GCORE:gcore.jsdelivr.net

服务·反向代理

如果一定要使用jsDelivr的资源的话,可以考虑通过NGINX反代 cdn.jsdelivr.net这一个资源库自用。建议通过海外优化线路落地+国内中转缓存,不过要注意添加防盗链以及尽量隐藏反代路径,以防止被其他人滥用。具体配置这里给一个简单的范例,博主不是很推荐这样做,可靠性上很打折扣。

NGINX反代jsDelivr示例

1234567891011#针对/gh目录的反代location/gh{ proxy_passhttps://104.16.86.20; proxy_set_headerHostcdn.jsdelivr.net; proxy_ssl_server_nameon; proxy_ssl_namecdn.jsdelivr.net; proxy_set_headerX-Real-IP$**remote_addr**; **proxy_set_header**X-**Forwarded**-**For**$proxy_add_x_forwarded_for; proxy_set_headerREMOTE-HOST$remote_addr;}

服务·切换国内静态库

推荐一些国内比较稳定、全面的静态资源库吧,其中不乏完全同步cdnjs内容的,可以逐步将静态资源替换过去。

字节静态库:cdn.bytedance.com

*完整同步了 cdnjs的内容,通过自家CDN加速,缺点是没有海外节点而且链接比较凌乱。

360静态库:cdn.baomitu.com

*完整同步了 cdnjs的内容,并且有提供Google fonts加速,通过自家CDN加速,前段时间启用了AWS CloudFront的海外节点,是目前国内公共CDN做的比较好的了。

七牛静态库:staticfile.org

*通过自家融合CDN加速,海外节点较少不过也表现尚可,缺点就是担心org域名后续备案维护的问题。

~本地·修改Hosts~ (失效)

一般情况下,DNS污染通常伴随着SNI阻断,不过比较幸运的是jsDelivr只是单纯的DNS污染,可以通过本地指定正常的IP恢复访问。这样操作可以解决作为用户本地无法加载页面包含jsDelivr资源的问题。Hosts文件在UNIX系统下位于 /etc/hosts,Windows系统下位于 C:\Windows\System32\drivers\etc\hosts,在末尾处添加适当的以下条目即可恢复访问。

jsDelivr hosts

123456789#CloudFlare(不推荐联通使用)104.16.85.20cdn.jsdelivr.net104.16.86.20 cdn.jsdelivr.net104.16.87.20 cdn.jsdelivr.net104.16.88.20 cdn.jsdelivr.net104.16.89.20 cdn.jsdelivr.net#Fastly(不推荐电信使用)151.101.1.229 cdn.jsdelivr.net151.101.129.229 cdn.jsdelivr.net

~本地·使用DoH/DoT~ (失效)

DoH/DoT博主研究的很少,因为jsDelivr只是单纯的DNS污染可以通过DNS分流走海外加密DNS绕过污染。比如CloudFlare的 1.1.1.1都是可用的,但是修改DNS一定要做好分流,以免影响GeoDNS对日常上网导致的CDN分配的问题。

本地·其他可能的思路

目前有通过油猴替换reCAPTCHA使用的API中的 google.comrecaptcha.net实现中国大陆加载,理论上也是可以通过这样的方法将jsDelivr替换到大陆可加载的链接上,期待各位大佬的实践。


叁、结语

于是,到底是谁杀死了jsDelivr呢?是jsDelivr审核不够严谨?是网宿的不辞而别?是政策的“一刀切”?博主不知道,相信各位看官自己心里都有自己的答案吧。

本来只是想简单讲几句,没想到就说了这么多,一篇文章难免会参杂有个人情感,文中如果有不够严谨的地方请多指点。

最后,晚安jsDelivr,感谢您和诸多的赞助商这么多年来为用户无偿提供这样便捷的服务~


*原创文章,本文转载请注明出处

转载原创文章请注明,转载自: Luminous' Home » 【杂谈】jsDelivr域名遭到DNS污染

参照:jsdelivr cdn挂了解决方案、用unpkg来快速临时替代它 - 欲饮琵琶码上催 - 博客园 (cnblogs.com)

作者:每天学点黑科技
链接:https://www.zhihu.com/question/533766356/answer/2495374387
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

http://cdn.jsdelivr.net替换为http://fastly.jsdelivr.net 就行了。

如果这个也挂了,打开 https://ipaddress.com/website/raw.githubusercontent.com 将GitHub的ip地址复制到host文件 C:WindowsSystem32driversetchosts就行,就是麻烦点。

发布于 2022-05-21 17:15

jsdelivr.com挂了,免费的真的无风险吗?

众所周知,https://www.jsdelivr.com/ 是一个国外很有名的github、npm等静态文件加速站,说人话,就是免费提供cdn访问路由的。

这么多年,一直很稳定,所以有不少网站已经在线上使用他们的链接了,毕竟可以节约不少购买使用cdn的费用。

是的,没问题时候,确实是利大于弊。可是,一旦崩了,网站打不开,乱码等等问题带来的损失,谁来买单???

我们公司线上也有几个流量不大的页面也在用,自然也受到了影响。当时纯粹是懒了,顺手直接复制了,没有本地搭建。谁曾想到,再稳定的系统,也有崩的时候。就连bootcdn首页都在使用他家的cdn,如今变成这个样子:

而他家自己的官网,是这个样子的!

总之呢,免费的才是最贵的,千万不要贪便宜,图省事,不然带来的损失只能自己承担。无论是个人还是企业,毕竟世上没有既免费又稳定的东西。做技术的,更不能懒,以至于忽视任何风险预判,不然后果很严重。免费的cdn,一定不要用在生产环境。否则,吃不了兜着走。正如jsdelivr所说,A free CDN for Open Source,一个免费的开源cdn。本质就是为开源服务的,而不是生产环境的商业行为。

滴水成冰,世间不存在毫无意义的付出,时间终会给你答案。

本文作者:知风阁

本文链接:https://www.cnblogs.com/itbaby/p/16309475.html

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

前言
众所周知,在去年年底,知名的免费cdn服务提供商jsdelivr由于大陆域名备案的问题,没有国内的CDN加速了,目前都只能解析到海外,不但速度慢,还会偶发性无法连接到服务器。因此国内超多网站都受到了影响。
有人说可以批量修改引用的url,都改成 unpkg.com,但实测,我的个人网站上有一半的js和css在这个站点上是没有的。

由于我的个人站点并没有提供多少花里胡哨的内容,所以我就想着把所有要从jsdelivr获取的文件都下载到服务器本地,不再从外部获取,没准哪天海外服务都没了那就芭比Q了。

操作步骤
打开博客模板文件夹,找出所有包含jsdelivr的链接,去重后发现有39个链接

然后写入一个文本文件

编写下载程序
可以看到这个目录结构相当复杂,如果要做最少的改动,应该让下载文件后的目录与链接路径保持一致,于是我想到了我以前曾经用网际快车下载过整个网站,但这玩意早就过时了,也懒得装软件。现在用python应该就可以实现,为避免重复造轮子,这种想法肯定有人也曾有过,于是先搜,轻松找到一篇文章

让Python自动下载网站所有文件 ! https://zhuanlan.zhihu.com/p/62876301

我把里面的程序复制出来,修改了入口函数,遍历url列表传入

import urllib.request
import requests
import re, os

基于 https://zhuanlan.zhihu.com/p/62876301 修改

def get_file(url):
'''
递归下载网站的文件
:param url:
:return:
'''

if isFile(url):
    print(url)
    try:
        download(url)
    except:
        pass
else:
    urls = get_url(url)
    for u in urls:
        get_file(u)

def isFile(url):
'''
判断一个链接是否是文件
:param url:
:return:
'''
if url.endswith('/'):
return False
else:
return True

def download(url):
'''
:param url:文件链接
:return: 下载文件,自动创建目录
'''
full_name = url.split('//')[-1]
filename = full_name.split('/')[-1]
dirname = "/".join(full_name.split('/')[:-1])
if os.path.exists(dirname):
pass
else:
os.makedirs(dirname, exist_ok=True)
urllib.request.urlretrieve(url, full_name)

def get_url(base_url):
'''
:param base_url:给定一个网址
:return: 获取给定网址中的所有链接
'''
text = ''
try:
text = requests.get(base_url).text
except Exception as e:
print("error - > ",base_url,e)
pass
reg = '<a href="(.*)">.*</a>'
urls = [base_url + url for url in re.findall(reg, text) if url != '../']
return urls

if name == '__main__':
with open('list.txt', 'r') as f:
lines = f.readlines()
url_list = []
for line in lines:
get_file(line.strip('n'))
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
执行
将上面的代码保存成py文件后执行,就会在当前目录下生成cdn.jsdelivr.net的主目录及其子目录和文件

上传文件夹到服务器
由于我是使用的halo博客,可以自定义添加静态资源,直接把下载的gh和npm两个文件夹整个拖到/root/.halo/static目录即可

修改博客模板中的链接
这个就容易了,直接打开模板中的所有文件,批量将cdn.jsdelivr.net替换成我网站的域名,并保存,覆盖到服务器上

最终效果

说点题外的
有不少程序员习惯使用国外的免费服务,比如github和本文中提到的jsdelivr,大家也应该已经发现了这两个东西在国内已经是属于间歇性抽风的状态了。
当前国际形势越来越紧张,把东西放在国外的服务器上所要承担的风险越来越大,也应该要考虑将国外服务器上的东西迁移回本国了,否则哪天一个制裁,轻则断连,中则账号拉黑,重则把你数据直接删了也说不定。

本文作者: DarkAthena
本文链接: https://www.darkathena.top/archives/jsdelivr-byebye
版权声明: 本博客所有文章除特别声明外,均采用CC BY-NC-SA 3.0 许可协议。转载请注明出处!
文章知识点与官方知识档案匹配,可进一步学习相关知识
————————————————
版权声明:本文为CSDN博主「DarkAthena」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/wwwwwwgame/article/details/123343441

让Python自动下载网站所有文件 !

萌新程序员

萌新程序员

程序员

26 人赞同了该文章

最近维基 jie mi 彻底公开了网站的全部文件,我就在想如何使用 Python 将其下载到本地永久保存,于是就有了这篇文章,写爬虫会遇到很多坑,借鉴他人经验,考虑越全面,出错的概率就越小。

假如一个网站,里面有很多链接,有指向文件的,有指向新链接的,新的链接点击进去后,仍然是有指向文件的,有指向新链接的,类似一个文件夹,里面即有文件,又有目录,目录中又有文件和目录。如何从这样的网站上下载所有的文件,并按网站的目录结构来保存这些文件呢?

关键词:Python、下载、正则表达式、递归。

按照自顶向下来设计程序,我们整理自己的思路,然后使用 Python 语言来翻译下即可。

思路:由于目录的深度不固定,也不可能穷举,且每一个目录的处理方式和子目录父目录的处理流程都是一样的,因此我们可以使用递归来下载所有文件。

递归代码必须要有退出条件,退出条件要放在前面,本例中的递归退出条件就是:如果是文件就下载,下载完递归函数即完成任务。

总体思路:

1、给定一个 url,判断是否是文件,如果是文件,下载即可,然后函数结束。

2、如果给定 url 不是文件,那么访问该 url,并获取它下面的所有链接。

3、遍历步骤 2 产生的所有链接,递归的执行步骤 1 和 2,直到程序运行结束。

以上思路,用代码描述如下:

import urllib.request
import requests
import re, os


def get_file(url):
    '''
    递归下载网站的文件
    :param url:
    :return:
    '''
    if isFile(url):
        print(url)
        try:
            download(url)
        except:
            pass
    else:
        urls = get_url(url)
        for u in urls:
            get_file(u)

前面导入的包在接下来函数中会用到,下面就是逐渐层向下,实现子功能。

判断链接是否指向文件:

这里总结 url 规律,很容易写出。

def isFile(url):
    '''
    判断一个链接是否是文件
    :param url:
    :return:
    '''
    if url.endswith('/'):
        return False
    else:
        return True

下载文件:

下载文件时要从 url 中获取文件应该存储的位置,并使用 os.makedirs 来创建多级目录。然后使用 urllib.request.urlretrieve 来下载文件。

def download(url):
    '''
    :param url:文件链接
    :return: 下载文件,自动创建目录
    '''
    full_name = url.split('//')[-1]
    filename = full_name.split('/')[-1]
    dirname = "/".join(full_name.split('/')[:-1])
    if os.path.exists(dirname):
        pass
    else:
        os.makedirs(dirname, exist_ok=True)
    urllib.request.urlretrieve(url, full_name)

获取 url 下的所有链接:

这里要具体网站具体分析,看看如何使用正则表达式获取网页中的链接,这样的正则表达式可以说是再简单不过了。

def get_url(base_url):
    '''
    :param base_url:给定一个网址
    :return: 获取给定网址中的所有链接
    '''
    text = ''
    try:
        text = requests.get(base_url).text
    except Exception as e:
        print("error - > ",base_url,e)
        pass
    reg = '<a href="(.*)">.*</a>'
    urls = [base_url + url for url in re.findall(reg, text) if url != '../']
    return urls

这里有个小坑,就是网站有个链接是返回上级页面的,url 的后辍是 '../' 这样的链接要去掉,否则递归函数就限入了死循环。

接下来就是写主函数,执行任务了,慢慢等它下载完吧。

if __name__ == '__main__':
    get_file('https://file.wikileaks.org/file/')

其实,还会存两个问题:

1、假如网站某页有个链接它指向了首页,那么递归程序仍然会限入一个死循环,解决方法就是将访问过的 url 保存在一个列表里(或者其他数据结构),如果接下来要访问的 url 不在此列表中,那么就访问,否则就忽略。

2、如果下载的过程中程序突然报错退出了,由于下载文件较慢,为了节约时间,那么如何让程序从报错处继续运行呢?这里可采用分层递归,一开始时先获取网站的所有一级 url 链接,顺序遍历这些一级 url 链接,执行上述的 get_file(url) ,每访问一次一级 url 就将其索引位置加1(索引位置默认为0,存储在文件中或数据库中),程序中断后再运行时先读取索引,然后从索引处开始执行即可。另外,每下载成功一个文件,就把对应的 url 也保存在文件中或数据库中,如果一级 url 下的链接已经下载过文件,那么就不需要重新下载了。

发布于 2019-04-18 16:21

Last modification:November 20, 2022
如果觉得我的文章对你有用,请随意赞赏