惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

A
Arctic Wolf
T
Tenable Blog
T
Troy Hunt's Blog
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
P
Privacy & Cybersecurity Law Blog
NISL@THU
NISL@THU
Application and Cybersecurity Blog
Application and Cybersecurity Blog
H
Hacker News: Front Page
S
Secure Thoughts
AWS News Blog
AWS News Blog
L
LINUX DO - 最新话题
D
Darknet – Hacking Tools, Hacker News & Cyber Security
M
MIT News - Artificial intelligence
T
Tor Project blog
S
Schneier on Security
PCI Perspectives
PCI Perspectives
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
美团技术团队
Google DeepMind News
Google DeepMind News
V
Visual Studio Blog
爱范儿
爱范儿
Google DeepMind News
Google DeepMind News
Cyberwarzone
Cyberwarzone
T
The Exploit Database - CXSecurity.com
罗磊的独立博客
T
Threat Research - Cisco Blogs
Recent Commits to openclaw:main
Recent Commits to openclaw:main
V
V2EX
C
CXSECURITY Database RSS Feed - CXSecurity.com
Stack Overflow Blog
Stack Overflow Blog
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
G
GRAHAM CLULEY
L
LINUX DO - 热门话题
D
Docker
J
Java Code Geeks
GbyAI
GbyAI
H
Heimdal Security Blog
The Hacker News
The Hacker News
MongoDB | Blog
MongoDB | Blog
V
Vulnerabilities – Threatpost
T
Tailwind CSS Blog
Cloudbric
Cloudbric
TaoSecurity Blog
TaoSecurity Blog
C
CERT Recently Published Vulnerability Notes
Y
Y Combinator Blog
Recorded Future
Recorded Future
Cisco Talos Blog
Cisco Talos Blog
T
Threatpost
The Register - Security
The Register - Security
Hacker News - Newest:
Hacker News - Newest: "LLM"

PixelNest

会议是效率的杀手 国庆出游记录 对居家办公的一些想法 2022 春节 《搏击俱乐部》的结局 纪念 PAI 头一回达到 100 卡片笔记法 《刑法学讲义》的部分摘录 迁移博客 《UNIX 传奇》摘录 就地过年 一点记录:docker-compose 编排不同项目间的网络 近期读的几本书 办新身份证 git 获取其他分支的单个文件或目录 我的高考成绩 推荐 2020 年上半年的 8 部影视作品 ChromeOS 开发者模式 终于下单了《守望者》 联通来电管家服务 一些实用的 bash 代码片段 关于 鸟枪换炮 《架构整洁之道》摘录 惨淡的星球大战 旧笔记本电脑 if...then... 命令行检测 SSL 证书过期时间 《程序员的职业素养》读书笔记 2019 国庆假期 在 Ubuntu 里按空格键预览 《基本穿搭》笔记 我在 Ubuntu 里安装的一些软件 让人郁闷的英语学习过程 色彩理论基础 向百度主动推送网站链接 两部电视剧 《历史的教训》摘录 新工具 Koa 获取客户端 IP 备案了 apiDoc 基础语法 《代码整洁之道》摘录 BBC 纪录片 《逻辑的乐趣》 读不下去的《原则》 蓝牙鼠标唤醒休眠的 Ubuntu Google 发布会 2018 国庆假期 开发者的时间追踪和统计 使用 curl 发送 POST 请求的几种方式 《重来 2》读书笔记 Linux 和 MacOS 命令行转换图片用法整理 《Go 语言实战》笔记 Win10 微软拼音添加小鹤双拼以及其他配置 针对不同场景临时禁用 eslint 规则的方法 《好妈妈胜过好老师》读书笔记 配置 Win10 Linux 子系统作为开发环境 又读完一本尤·奈斯博的小说 近期写 Go 的一点语法碎片整理 ffmpeg 合并 MP4 M4A 文件 睡前看手机的大问题 《局外人》读书笔记 菊次郎与佐纪 读书笔记 3 菊次郎与佐纪 读书笔记 2 菊次郎与佐纪 读书笔记 1 《如何有效阅读一本书》读书笔记 - 3 《如何有效阅读一本书》读书笔记 - 2 《如何有效阅读一本书》读书笔记 - 1 Vim iskeyword 济南 图个乐 开始看不懂《西部世界》了 剧透 听到几个好故事 过周末 相亲 让人失望的 Apple 悬疑故事 AI 记忆 世纪三部曲 上帝的梦
豆瓣图片服务器防盗链
2018-07-25 · via PixelNest

前两天在 贤民的比特记忆 看到这篇文章:为 hugo 站点插入豆瓣条目的 shortcode,我也学着把豆瓣条目的 shortcode 加上了。之后发现一个小问题,在自己的页面上引用了豆瓣上电影海报或书籍封面的图片地址,有时会触发豆瓣的防盗链措施,结果就是对图片的请求都是 403,没有访问权限。

一般的防盗链就是根据 HTTP 请求 Header 里的 Referrer 字段的值来判断是正常应答,还是返回 403。针对这种防盗链措施,一般又两种反防盗链措施,一是发起 HTTP 请求时不要在 Header 里带 Referrer 字段,第二种是用反向代理

有些 Web 服务的防盗链措施把不带 Referrer 的请求也当作非法的请求返回 403。如果你想尝试让浏览器在发起请求时修改 Referrer,不可行,浏览器不允许这样做,也就是说在浏览器里的请求要么带着默认的 Referrer,要么没有 Referrer。这样一来,第一条路就被堵死。还好豆瓣图片服务器并没有这么做,对 Referrer 为空的 HTTP 请求,是放行的,跟大多数 Web 服务一样。

Referrer

主流浏览器图片反防盗链方法总结 这篇文章里对第一种反防盗链措施有详细的总结,有两种方法可以实现。

  • 给页面添加 meta 标签。``
  • 给页面元素添加 Referrer 属性。xxx

前一种方法是页面级的修改,针对这个页面里任何资源的请求,都不带 Referer 了。第二种方法只针对指定元素的请求不带 Referer。两种方法在不同浏览器中的兼容性都多多少少有点问题,不过这到不在我的考虑范围——用旧版 IE 的人也不会访问到这里来——所以我本打算用第二种方法,给豆瓣图片的链接添加 Referrer 属性。

结果我一看,这个豆瓣 shortcode 的实现里,图片这部分的代码是类似这样的:

并不是我以为的

给前面那一行代码里的 div 标签添加 ref 属性是没有用的。所以,要么改成下面 img 标签的形式,同时也要修改对应的 CSS,保证内容的正常展示;要么就用反防盗链的第二种措施,反向代理。

反向代理

跟第一种措施比起来,做反向代理有点兴师动众的意味。即便是跟修改 HTML 和 CSS 代码比起来,做反向代理也是跟重量级的操作。

你至少要有自己的域名和 VPS 或者云主机才行,你要配置 Web Server 作为反向代理的工具,而且最后你还是要修改原来那段 shortcode 的代码,把豆瓣图片 URL 中的域名替换为自己反向代理的域名。

现在想一下,我也不明白为什么我选了这个方案,可能这种做法兼容性好,比较“万能”吧。更为可能的原因,可能是我想折腾折腾 Nginx 了。

Nginx 配置

Nginx 做反向代理的核心配置是这么几行,假设要把 img1.example.com 作为 img1.doubanio.com 的反向代理域名:

server {
    listen 80;
    server_name example.com
    location / {
        proxy_pass https://img1.doubanio.com;
    }
}

豆瓣的图片资源在 img*.doubanio.com 域名上,据我所知,目前有 img1.doubanio.com, img3.doubanio.com 两个子域名,也可能有其他的子域名。最好用 Nginx 的正则表达式功能,我准备把 *-douban.ifttl.com 这种格式的域名作为 *.doubanio.com 的反向代理域名。

下面是我实际在用的 Nginx 配置。

server {
    listen 80;
    listen [::]:80;
    server_name "~^(?.*)\-douban\.ifttl\.com$";
    valid_referers *.ifttl.com ifttl.com;
    if ($invalid_referer) {
        return 403;
    }
    location / {
        proxy_pass https://$name.doubanio.com;
        proxy_redirect off;
        proxy_set_header Referer "https://www.douban.com";
    }
}

关键是 server_name "~^(?.*)\-douban\.ifttl\.com$"; 这一行正则表达式指定的主机名,并且把开头部分捕获到 name 变量里,交给 proxy_pass 参数 https://$name.doubanio.com

这个应用场景里没有重定向和修改重定向地址的需求,所以 proxy_redirect off

proxy_set_header Referer "https://www.douban.com"; 这一行也比较重要,添加这样一行配置,在 Nginx 把请求转向豆瓣服务器时,在 HTTP 请求头里加了个 Referrer 是 https://www.douban.com,也就是好像是从 https://www.douban.com 页面中发出的请求,让豆瓣的图片服务器当作是自家人的请求。这样感觉我对豆瓣的良心大大的坏。

上面配置里这一段内容就体现了我对豆瓣的真良心。

valid_referers *.ifttl.com ifttl.com;
if ($invalid_referer) {
    return 403;
}

这是我对做反向代理域名做的在自己这一侧的防盗链,虽然被盗链的概率很小,而且我也不怎么在乎被盗链,但是既然最终请求——没有缓存的——都要落到豆瓣服务器上,我还是挡一下吧。这几行配置设置了有效的 Referrer 为 ifttl.com 和它的所有子域名,如果请求到我这来,但是 Referrer 值不在其中,我也只响应 403,不再处理。

一个插曲

Nginx reload,尝试请求自己的服务器,结果收获一个 502 错误,Nginx 错误日志里记录着:

no resolver defined to resolve img3.doubanio.com

原因很明确,没有指定 resolver,无法解析 proxy_pass 指定的域名的地址,Nginx 不知道该往哪里转发请求。给 Nginx 添加 resolver 就可以解决问题了,需要注意的是,resolver 必须配置在 http 块,不能配置到 server 块。

http {
    # ...
    # ...
        # 可以配置多个地址作为 resolver
    resolver 8.8.8.8 208.67.222.222
    # ...
    # server {
    #     ...
    # }
}

这时我产生了一个疑问,当 proxy_pass 的值是个固定的域名时,不需要配置 resolver,而 proxy_pass 的值里面包含变量时,就要配置 resolver。明明都需要 DNS 解析,为什么是固定域名时不需要配置 resolver?我在 StackOverflow 搜到了答案,Nginx proxy_pass with $remote_addr

If the proxy_pass statement has no variables in it, then it will use the “gethostbyaddr” system call during start-up or reload and will cache that value permanently.
if there are any variables, such as using either of the following:

set $originaddr http://origin.example.com;
proxy_pass $originaddr;
# or even
proxy_pass http://origin.example.com$request_uri;

Then nginx will use a built-in resolver, and the “resolver” directive must be present. “resolver” is probably a misnomer; think of it as “what DNS server will the built-in resolver use”. Since nginx 1.1.9 the built-in resolver will honour DNS TTL values. Before then it used a fixed value of 5 minutes.

proxy_pass 值没有变量时,会在 Nginx 启动时用 gethostbyaddr 这个系统调用来做一次解析,之后一直保存着这个解析结果。而当 proxy_pass 值中包含变量,即便变量并不处于域名中,就要用 resolver 指令指定的 resolver 来解析对应的域名。

修改 shortcode

最后修改 shortcode,把获取到的豆瓣图片地址替换掉。把两处分别对应电影和图书的代码做了如下修改。

// ...
// ...
success: function (data) {
    ...
    var db_image = data.images.large.replace('.doubanio.com', '-douban.ifttl.com')
    $('#db' + id).html(
        // ...
        // ...
        "");
}

最后的最后,我又给我的反向代理地址加了层 Cloudflare,又多了一层缓存,并且捎带着给这个地址用上 HTTPS。也是为了 Cloudflare 的 HTTPS,我用的域名是 *-douban.ifttl.com,而不是 *.douban.ifttl.com,因为 Cloudflare 只免费给一级子域配置 HTTPS 证书。

一番折腾下来,我要承认,把

改成

然后再修改 CSS,这样更省事,并且也很有效。但是我那么搞一通,给豆瓣服务器减小压力啊。