入侵浏览器页面

2025-06-07

入侵浏览器页面

我从小就喜欢拆东西,想弄清楚它们的工作原理。用撬棍拆解复印机的过程显然是单向的,但却揭示了许多有趣的齿轮、马达和机械装置:所有让机器运转的部件,都隐藏在机器表面之下。软件其实也没什么不同。

所有软件都可以研究、拆解、修改和理解(无需撬棍),但现代浏览器中的 JavaScript 让这一切变得异常简单。只需设定一个目标,然后弄清楚相关部分是如何工作的。

故事时间:做我吧,显然是个叛逆者

很久以前,我工作的一家小公司被并入一个大型代理网络。除了强制切换到过时的时间跟踪应用程序外,公司还要求每位员工完成一些基于网络的安全学习模块,每个模块需要40分钟。

每个模块都包含阅读材料、不可跳过的视频内容和不可跳过的互动“谜题”,最后还会进行一个充满各种问题的测验,例如“Alice 和 Bob 什么时候可以写下他们的密码?”以及“Charlie 应该把这些机密文件带回家吗?”。这几乎就是典型的强制性企业教育体验。

作为一名积极进取的软件开发者,我最多只花了 10 分钟就完成了第一个学习模块,然后就打开浏览器的开发者工具,开始浏览。几个小时后,我完成了剩下的模块,并且恰好拥有了一些脚本,呃……可以节省宝贵的开发者时间:

  1. 将当前课程标记为完成,设置随机但合理的课程时间并提交。
  2. 将当前评估/测验标记为完整且 100% 正确,设置随机合理的会话时间并提交。
  3. 当不可跳过的内容禁用了“下一页”按钮时,跳转到下一页。

我的队友很感兴趣,觉得脚本很棒。我的老板无意中听到了,觉得很棒,但可能只对开发团队有用。虽然我没有亲自发布,但到最后,脚本已经通过口口相传在其他几个团队中流传开来。

每个人都节省了很多时间。

很好。

大约一周后,老板宣布有人以创纪录的速度完成了一项测试!可惜的是,楼上新来的人大多分不清真假,而且缺乏讽刺意识,所以每个人都被要求重新接受安全培训。

我不记得自己曾经重新参加过考试,但随后几年我被认定为“破解安全测验的人”的次数表明其他人确实不幸地重新经历了完整的学习经历。

明显的免责声明 - 不要模仿这一点,因为你的雇主可能不会觉得你的滑稽动作有趣!

故事寓意

  1. 如果您可以在网站上执行某个操作,那么您就可以自动执行该操作。
  2. 如果某个网站知道某些信息,您就可以访问它。
  3. 如果网站向服务器发送回某些内容,您可以发出相同的请求。

虽然这个故事有点调侃,但还是有很多实用且无害的方法可以让你作为客户端发挥自己的优势。像这样的尝试也是提升调试和静态分析技能的有趣方式!以下是我的一些其他冒险经历:

  • 自动以市场价格列出我的所有 Steam 集换式卡牌
  • 将 AliExpress 订单列表导出为 CSV
  • 导出 Tumblr Messenger 对话的完整历史记录
  • 只需单击一下,即可自动执行缓慢且笨重的时间表 Web 应用程序中的重复计费
  • 使用包含当前日期的模板名称克隆 Jira 票证
  • 使用 Google Sheets 文档中的值填充 Jira 票证中的字段
  • 在 2013 年消失之前存档旧社交网络的数据

入门套件

如果您有兴趣亲自尝试但不确定从哪里开始,这里有一些提示:

  • 首先观察现有代码的工作方式:检查元素,在 DOM 节点上找到相关的属性,查看 DOM 如何随着 UI 交互而变化,查看触发网络请求的原因、请求和响应是什么样的,等等。
  • 使用 Chrome 开发者工具中的搜索工具,搜索可能出现在脚本中的、足够独特的字符串。元素 ID、类和文本标签是查找相关代码的方法:

Chrome 开发工具全局搜索功能

  • Chrome 源代码窗格中的漂亮打印按钮非常适合使最小化的代码更易读和可调试:

Chrome 开发工具 JavaScript 漂亮打印按钮

  • 内置的 JavaScript 函数通常就是您现在进行修改所需要的全部功能。并且querySelector您的朋友。querySelectorAllfetch

  • 使用 Chrome 中的“Sources -> Snippets”或 Firefox 中的“Scratchpad”编写更多代码。JavaScript 控制台非常适合探索,但不太适合编辑大段代码:

Chrome 开发工具代码片段

祝您黑客愉快!


附录

以下是一些我用来自动化其他人页面的有用代码片段。它们本身并没有什么特别之处,但如果你以前没有用过 JavaScript,其中一些内容可能会让你觉得很新奇。

等待 DOM

与 UI 进行程序化交互的排序几乎总是需要超时或条件检查,以确保页面已准备好执行下一个操作。以下是我几乎在每个脚本中都会用到的两个函数:

/**
 * Timeout as a promise
 *
 * @param  {int} time - time in milliseconds to wait
 * @return {Promise}
 */
function timeout(time) {
    return new Promise(function(resolve, reject) {
        setTimeout(resolve, time)
    });
}

/**
 * Return a promise that resolves once the passed function returns a truthy value.
 *
 * @param  {function() : bool} conditionFunc
 * @return {Promise}
 */
function wait(conditionFunc) {
    return new Promise(function(resolve, reject) {
        var interval;
        interval = setInterval(function() {
            var value = conditionFunc();

            if (value) {
                clearInterval(interval);
                resolve(value);
            }
        }, 100);
    });
}
Enter fullscreen mode Exit fullscreen mode

在脚本执行之前获取 DOM 内容

有些页面的 HTML 中包含一些有用的信息,但当页面自身的脚本运行时,这些信息会被剥离。为了解决这个问题,您可以从服务器获取原始 HTML 的副本,并使用它DOMParser获取功能齐全的 DOM 上下文,从而不受脚本干扰地进行探索:

/**
 * Get a DOM node for the HTML at the given url
 * @returns HTMLDocument
 */
async function getDom(url) {
    var response = await fetch(url, {
        mode: 'cors',
        credentials: 'include',
    });

    // Grab the response body as a string
    var html = await response.text();

    // Convert HTML response to a DOM object with scripts remaining unexecuted
    var parser = new DOMParser();
    return parser.parseFromString(html, 'text/html');
}
Enter fullscreen mode Exit fullscreen mode

跨页面加载脚本

当目标网站需要加载完整页面才能执行操作时,可以使用 iframe 来避免页面更改打断代码。如果目标页面上X-Frame-Options没有设置 header 或设置了 header sameorigin(这种情况很常见),原始页面就可以作为访问同一域名下其他页面的平台:

var client = document.createElement('iframe');
client.src = window.location;

document.body.appendChild(client);

// Do stuff in the iframe once it's loaded
client.contentDocument.querySelector('a').click();
Enter fullscreen mode Exit fullscreen mode

获取数据

复制粘贴

从页面中获取文本数据的廉价而愉快的方法是使用prompt()并从对话框中复制粘贴:

prompt('Copy this', data);
Enter fullscreen mode Exit fullscreen mode

文件下载

如果变量中收集了大量文本或二进制数据,则可以使用文件 API 下载它:

/**
 * Download the contents of a variable as a file
 */
function downloadAsFile(data, fileName, contentType='application/octet-stream') {
    var file = new Blob([data], {type: contentType});

    // Make the browser download the file with the given filename
    var node = document.createElement('a');
    node.href = URL.createObjectURL(file);
    node.download = fileName;
    node.click();
}
Enter fullscreen mode Exit fullscreen mode

HTTP 请求

在内容安全策略设置不佳或缺失的页面上,您可以直接将数据作为 HTTP 请求 POST 到您自己的服务器。这通常只在您想将大量数据直接导出到数据库而无需进行重复处理时才有用。

fetch('https://myserver.example.com/ingest-handler', {
    method: 'POST',
    mode: 'no-cors',
    body: data
});
Enter fullscreen mode Exit fullscreen mode

无论跨域请求标头如何,这都可以工作,因为 HTTP 客户端必须先发送整个请求,然后才能看到任何响应标头。

文章来源:https://dev.to/stecman/hacking-on-pages-in-the-browser-3l0e
PREV
职业道路简介自我意识的必要性安装自我意识奥德赛计划结论参考文献
NEXT
如何摆脱困境并取得进步