
InfinityFree 的 "?I=1
来源标题:InfinityFree's "?I=1"
文章以作者2026年11月8日与大学老友重逢为引子,讲述对方请其开发一个计算两坐标中点的小工具,用于与网友约定公平的见面地点。作者回家后随即完成应用并发送链接,约一周后(11月14日)出现转折。
以下正文由 AI 翻译自 Hacker News 最新(原文版权归原站所有),可能存在偏差,重要内容请以原文为准。
分享
2026年11月8日,我和一位大学时代的老朋友见了面。我们大概有八年多没联系了,直到有一天我突发奇想,在Instagram上搜索老同学的踪迹。
事实证明,Facebook Inc.(现为Meta)在“重新找回旧日熟人”这件事上依然相当擅长。我很快就和朋友重新联系上了。按下关注按钮,查看对方的关注列表,再关注几个人,没多久,关注链就引出了私信。经过大量交流后,我们约了线下见面。
见面时,朋友让我做一个简单的应用:一个计算两个坐标之间中点的工具。
他心里有个具体的用途。有时他需要和网上认识的人见面,在双方各自住处之间找到一个合适的碰面地点,对让安排尽可能公平很重要。以地理中点作为会合点,理论上双方就能走相同的距离。
所以,见面一回到家,我立刻就把应用做好,把链接发给了他。
大约一周后,2026年11月14日,我又收到了他的消息。显然,这个应用第一次在真实场景中成功派上了用场!
他还提了一个功能需求:用户不应该只能手动输入坐标,还应该能直接输入地名来搜索位置。
今晚,我打算实现这个功能。
我最初的策略很直接:集成Photon地理编码器,把位置查询解析成坐标。不过,这里有个问题。
我预计Photon会解析不了某些查询,尤其是当底层的OpenStreetMap数据不完整时。我不想让这些失败的查询就这么消失。相反,我想把它们收集到某个地方,这样就能用积累的数据来发现数据缺口,并有可能改进地理编码体验。
我希望每当有人提交位置查询时,我的手机都能收到即时通知。为此,我设计了一套方案,涉及service worker和推送通知。然后我把整套东西部署到了我免费的InfinityFree托管账户上。
不幸的是,service worker拒绝工作。
我开始用Chrome DevTools调试问题。我切换到移动设备模拟,检查了控制台。果然,有一条错误信息:manifest.json中存在语法错误,据说是在第1行。
不可能,我心想。我的manifest.json看起来完全合法。到底能有什么问题?
我决定通过DevTools直接访问manifest.json,查看它的实际内容。结果发现:InfinityFree把我manifest.json的全部内容替换成了完全不同的东西。
<html>
<body>
<script type="text/javascript" src="/aes.js"></script>
<script>
function toNumbers(d) {
var e = [];
d.replace(/(..)/g, function(d) {
e.push(parseInt(d, 16))
});
return e
function toHex() {
for (var d = [], d = 1 == arguments.length && arguments[0].constructor == Array ? arguments[0] : arguments, e = "", f = 0; f < d.length; f++)
e += (16 > d[f] ? "0" : "") + d[f].toString(16);
return e.toLowerCase()
var a = toNumbers("f655ba9d09a112d4968c63579db590b4")
, b = toNumbers("98344c2eee86c3994890592585b49f80")
, c = toNumbers("4445f8d155088fc9ff58f3c4b5f04d8d");
document.cookie = "__test=" + toHex(slowAES.decrypt(c, 2, a, b)) + "; max-age=21600; expires=Thu, 31-Dec-37 23:55:55 GMT; path=/";
location.href = "manifest.json?i=1";
</script>
<noscript>This site requires Javascript to work, please enable Javascript in your browser or use a browser with Javascript support</noscript>
</body>
</html>
其实,早在这次事件之前很久,我就怀疑幕后有类似的事情在发生。有一个细节一直让我耿耿于怀:每当我访问自己的域名时,URL里总会稳定出现那个可疑的?i=1参数。
但这是我第一次偶然发现那个看似无害的URL参数背后实际发生的事情。
这是一段由InfinityFree托管基础设施注入的反机器人/浏览器验证脚本。它的目的是验证访问者能够执行JavaScript、解密一些数据并存储一个cookie,然后才允许访问所请求的资源。
toNumbers(d):把十六进制转换为字节
这个函数接收一个十六进制字符串,并将其转换为数字数组。
function toNumbers(d) {
var e = [];
d.replace(/(..)/g, function(d) {
e.push(parseInt(d, 16))
});
return e
// toNumbers("f655ba9d") -> [246, 85, 186, 157]
toHex():把字节转换回十六进制
这个函数做的是前一个函数的逆操作。它接收一个数字数组,把每个数字转换成两个字符的十六进制表示。
function toHex() {
for (var d = [], d = 1 == arguments.length && arguments[0].constructor == Array ? arguments[0] : arguments, e = "", f = 0; f < d.length; f++)
e += (16 > d[f] ? "0" : "") + d[f].toString(16);
return e.toLowerCase()
// toHex([246, 85, 186, 157]) -> f655ba9d
AES
这是三段密码学数据。每个十六进制字符串包含32个字符,代表16字节(128位)。
var a = toNumbers("f655ba9d09a112d4968c63579db590b4")
, b = toNumbers("98344c2eee86c3994890592585b49f80")
, c = toNumbers("4445f8d155088fc9ff58f3c4b5f04d8d");
// a : AES加密密钥
// b : 初始化向量(IV)
// c : 加密数据(密文)
AES(高级加密标准)是一种对称加密算法。加密和解密使用同一个密钥。
slowAES是AES算法的一个JavaScript实现。
通常,现代浏览器提供原生的密码学API:crypto.subtle.decrypt(...),但独立的JavaScript实现可以在不依赖Web Crypto API的情况下工作。
(原文较长,此处译出前 6000 字,完整内容请点「打开原文」。)
正文由 探How 从来源站点 RSS 同步,内容未经改写;遇到排版缺失或需要图片、视频时请以原文为准。