网站使用 CDN 之后获取访客原 IP 的方法

网络上大多数教程给出的方法都是通过修改程序代码,直接取 X-Forwarded-For 等请求标头的值替换原来 REMOTE_ADDR 变量的值作为原 IP,这种做法有很大的安全隐患,我认为不值得提倡。

安全隐患

根据 RFC 3875 文件,REMOTE_ADDR 变量的值必须为发送请求到服务器的客户端的网络地址。在实践中 REMOTE_ADDR 变量的值往往由服务器直接设置为发送请求的客户端网络地址,而不是由客户端提供,因此其真实性有保证。

与 REMOTE_ADDR 变量不同,X-Forwarded-For 请求标头的值不是由服务器直接决定,而可以由客户端自行设置,实践中一般由代理服务器在转发请求时设置。因为 X-Forwarded-For 请求标头的值可能被客户端伪造,所以不应该轻易相信其真实性。

由于 REMOTE_ADDR 变量的值和 X-Forwarded-For 请求标头的值具有不同的可信度,使用低可信度 X-Forwarded-For 请求标头的值去替换高可信度 REMOTE_ADDR 变量的值便会产生不可忽视的安全隐患。比如,攻击者可以通过伪造 X-Forwarded-For 请求标头来绕过基于 IP 的频率限制、访问控制。更进一步,攻击者还可以构造具有危害性 X-Forwarded-For 请求标头来对服务器进行多种攻击,例如注入恶意代码进行 XSS 攻击就是一种可能的行为。

正确做法

在使用 X-Forwarded-For 请求标头的值之前应该确保其内容可信。因为 X-Forwarded-For 请求标头一般由代理服务器添加,所以至少应该先确认请求来自可信的代理服务器才可使用 X-Forwarded-For 标头的值。

对于使用 CDN 的网站,如果服务器是 nginx,那么在 ngx_http_realip_module 模块的帮助下这一过程将会十分简单。只需编辑相应的 nginx 配置文件,在其中的 http、server 或 location 段,使用 set_real_ip_from 指定可信代理服务器地址(即 CDN 节点的地址),然后使用 real_ip_header 指明一个请求标头(即 X-Forwarded-For 标头),保存并重载 nginx 使配置生效。这样 nginx 收到请求后会检查请求的 REMOTE_ADDR 是否与 set_real_ip_from 相符,如果相符,nginx 会用 real_ip_header 对应标头的值替换 REMOTE_ADDR 原有的值,后端程序只需要正常使用 REMOTE_ADDR 的值即可。这种做法一般不需要改变后端程序。

参考资料

看到亚马逊停止 Kindle 电子书店在中国运营的消息有感

对于 Kindle 中国区用户:从 2023 年 6 月 30 日起将不能购买新的电子书,但仍可下载此前已购买的电子书;从 2024 年 6 月 30 日起将不能从 Kindle 下载任何电子书,只可阅读设备上已经下载的电子书。

亚马逊的这次调整算不上突然。早在半年前,国内主要电商平台的 Kindle 就已经开始缺货,那时是 2022 年 1 月左右。虽然这次亚马逊的通知中提到每位用户可以在 2022 年 10 月 31 日之前退回至多 3 台于 2022 年 1 月 1 日及以后从国内授权经销渠道购买的至今没有质量问题及人为损坏的 Kindle 设备,但实际上能满足亚马逊退货条件的用户并不多。因为国内授权经销渠道在 2022 年 1 月之后基本都是缺货状态,所以大部分满足时间要求的用户都是从非国内授权经销渠道购买到 Kindle 设备的。

之前我就说过纸质书比 Kindle 电子书更可靠,不过那时并没有太多实例。这次 Kindle 电子书店在中国停止运营为我的“反电子书”观点提供了新的证据支持。不要简单地将这次事件视作一家国际公司的区域性运营调整。问题的根源不在这家公司,而在当前的电子书商业运作模式。只不过亚马逊在这个行业中一直扮演着“老大”的角色,所以问题最先从它身上暴露出来。我相信如果当前这种电子书商业运作模式不改变,那么支撑我“反电子书”观点的证据还会越来越多。