在内容脚本之前注入javascript变量
使用我的后台脚本background.js,我需要先将一个动态变量作为内容脚本注入,然后再将另一个文件inject.js也作为内容脚本注入。在运行页面上的任何脚本之前,Inject.js需要访问该变量并运行其代码。从inject.js内容脚本访问动态变量时遇到困难 manifest.json在内容脚本之前注入javascript变量,javascript,google-chrome-extension,Javascript,Google Chrome Extension,使用我的后台脚本background.js,我需要先将一个动态变量作为内容脚本注入,然后再将另一个文件inject.js也作为内容脚本注入。在运行页面上的任何脚本之前,Inject.js需要访问该变量并运行其代码。从inject.js内容脚本访问动态变量时遇到困难 manifest.json { "name": "Shape Shifter", "version": "1.0", "description": "Anti browser fingerprinting web extension.
{
"name": "Shape Shifter",
"version": "1.0",
"description": "Anti browser fingerprinting web extension. Generates randomised values for HTTP request headers, javascript property values and javascript method return types.",
"manifest_version": 2,
"icons": {
"32": "icons/person-32.png",
"48": "icons/person-48.png"
},
"background": {
"persistent": true,
"scripts": ["js/ua.js", "js/words.js", "js/lib/seedrandom.min.js", "js/random.js", "js/background.js"]
},
"browser_action": {
"default_title": "Shape Shifter",
"default_icon": "icons/person-32.png",
"default_popup": "html/popup.html"
},
"content_scripts": [
{
"run_at": "document_end",
"matches": ["<all_urls>"],
"js": ["js/inject.js"]
}
],
"permissions": [
"webRequest",
"webRequestBlocking",
"webNavigation",
"tabs",
"activeTab",
"storage",
"<all_urls>"
],
"web_accessible_resources": [
"js/ua.js",
"js/words.js",
"js/lib/seedrandom.min.js",
"js/random.js",
"js/api/document.js",
"js/api/navigator.js",
"js/api/canvas.js",
"js/api/history.js",
"js/api/battery.js",
"js/api/audio.js",
"js/api/element.js"
]
尝试将种子记录到控制台时出现错误:
inject.js:26 Uncaught ReferenceError: seed is not defined
at inject.js:26
at inject.js:52
有什么想法吗?这会很棘手。
让我们看看您的需求
在运行页面上的任何脚本之前,Inject.js需要访问该变量并运行其代码
这不是您的代码目前的工作方式。您的inject.js
在document\u end
执行-这发生在整个DOM树解析之后,这意味着在所有页面脚本运行之后(禁止异步部分和async
脚本加载)
Chrome有一个解决方案-您可以将执行设置为document\u start
。然后,您的代码将真正先于其他所有内容运行,而DOM仍然没有被解析(因此document
基本上是空的)。对于代码所做的,它不应该产生问题(它只依赖于将存在的document.documentElement
)
问题是,您的所有代码都必须是同步的,才能仍然享受“先运行再运行”属性。只要代码的同步部分运行,Chrome就会暂停DOM解析,但是当它愉快地继续解析(并从中运行代码)文档时,所有的赌注都被取消了
例如,这就取消了chrome.storage
和消息传递的资格,因为访问chrome.storage必须是异步的
我需要[在页面加载时]注入一个动态变量
这意味着您无法将其提前存储在某些同步可用的存储中(例如,在本地存储中或网站的cookie中),考虑到您事先不知道域,这将是一个问题
请注意,特别是对于您的代码,这可能不是一个很大的因素;实际上,每个域的“动态”值是固定的。您仍然不知道将访问哪个域,但您至少可以保证在第二次加载时它会在那里
使用我的后台脚本background.js,在注入另一个文件之前,我需要注入一个动态变量作为内容脚本[该文件仍然需要在页面上所有其他文件之前运行]
这是棘手的部分事实上,如前所述,这根本不可能。您正试图从后台捕捉导航提交、Chrome将页面切换到新域和执行文档开始
脚本之间的确切时刻
那里没有可检测的间隙,也没有办法告诉Chrome等待。这是一个你没有希望解决的比赛状态
您正在尝试使用webNavigation.onBeforeNavigate
——甚至在提交导航之前。因此,您的injectScript
甚至可能会转到上一页,使其变得无用。如果你尝试其他活动,例如onCommitted
,仍然无法确定何时会处理injectScript
。可能在你的剧本之后
那么,如何解决这些问题呢?
幸运的是,有一些同步存储可用于内容脚本,您可以在最早的脚本执行之前将一些信息推送到内容脚本
饼干。
但是,使用chrome.cookies
API不会有帮助。您需要在webRequest.onHeadersReceived
上主动将cookie值注入请求
您必须准备好同步的值,以便使用阻塞处理程序将其处理到onHeadersReceived
,但是您只需添加一个Set Cookie
头,并立即在document.cookies
中的inject.js
中使用它
- background.js
"use strict";
console.log("Background Script Running ...");
function getSeed(origin) {
// Get a Storage object
var storage = window.localStorage;
// Do we already have a seed in storage for this origin or not?
var seed = storage.getItem(origin);
if (seed === null) {
// Initialise a 32 byte buffer
seed = new Uint8Array(32);
// Fill it with cryptographically random values
window.crypto.getRandomValues(seed);
// Save it to storage
storage.setItem(origin, seed);
}
return seed;
}
// Methods to get HTTP headers
function getAcceptHeader(seed) {
return "NotYetImplemented";
}
function getAcceptCharsetHeader(seed) {
return "NotYetImplemented";
}
function getAcceptEncodingHeader(seed) {
return "NotYetImplemented";
}
function getAcceptLanguageHeader() {
// NOTE: TOR Browser uses American English
return "en-US,en;q=0.5";
}
function getAuthorizationHeader(seed) {
return "NotYetImplemented";
}
function getExpectHeader(seed) {
return "NotYetImplemented";
}
function getFromHeader(seed) {
return "NotYetImplemented";
}
function getHostHeader(seed) {
return "NotYetImplemented";
}
function getIfMatchHeader(seed) {
return "NotYetImplemented";
}
function getIfModifiedSinceHeader(seed) {
return "NotYetImplemented";
}
function getIfNoneMatchHeader(seed) {
return "NotYetImplemented";
}
function getIfRangeHeader(seed) {
return "NotYetImplemented";
}
function getIfUnmodifiedSinceHeader(seed) {
return "NotYetImplemented";
}
function getMaxForwardsHeader(seed) {
return "NotYetImplemented";
}
function getProxyAuthorizationHeader(seed) {
return "NotYetImplemented";
}
function getRangeHeader(seed) {
return "NotYetImplemented";
}
function getRefererHeader() {
// NOTE: From https://developer.mozilla.org/en-US/docs/Web/API/Document/referrer
// NOTE: The value is an empty string if the user navigated to the page directly (not through a link, but, for example, via a bookmark).
// NOTE: Since this property returns only a string, it does not give you DOM access to the referring page.
// NOTE: Make websites think we always go to them directly rather than being referred.
return "";
}
function getTEHeader(seed) {
return "NotYetImplemented";
}
function getUserAgentHeader(seed) {
Math.seedrandom(seed);
return userAgents[randomNumber(0, userAgents.length)];
}
function rewriteHttpHeaders(e) {
// Create URL object from url string
var serverUrl = new URL(e.url);
console.log(e);
// Get the origin (hostname)
var origin = serverUrl.hostname;
var seed = getSeed(origin);
console.log("Background - Seed for origin " + origin + ": " + seed);
for (var header of e.requestHeaders) {
if (header.name.toLowerCase() === "accept") {
}
else if (header.name.toLowerCase() === "accept-charset") {
}
else if (header.name.toLowerCase() === "accept-encoding") {
}
else if (header.name.toLowerCase() === "accept-language") {
header.value = getAcceptLanguageHeader();
}
else if (header.name.toLowerCase() === "authorization") {
}
else if (header.name.toLowerCase() === "expect") {
}
else if (header.name.toLowerCase() === "from") {
}
else if (header.name.toLowerCase() === "host") {
}
else if (header.name.toLowerCase() === "if-match") {
}
else if (header.name.toLowerCase() === "if-modified-since") {
}
else if (header.name.toLowerCase() === "if-none-match") {
}
else if (header.name.toLowerCase() === "if-range") {
}
else if (header.name.toLowerCase() === "if-unmodified-since") {
}
else if (header.name.toLowerCase() === "max-forwards") {
}
else if (header.name.toLowerCase() === "proxy-authorization") {
}
else if (header.name.toLowerCase() === "range") {
}
else if (header.name.toLowerCase() === "referer") {
header.value = getRefererHeader();
}
else if (header.name.toLowerCase() === "te") {
}
else if (header.name.toLowerCase() === "user-agent") {
header.value = getUserAgentHeader(seed);
}
}
return {requestHeaders: e.requestHeaders};
}
chrome.webRequest.onBeforeSendHeaders.addListener(rewriteHttpHeaders, {urls: ["<all_urls>"]}, ["blocking", "requestHeaders"]);
chrome.webNavigation.onBeforeNavigate.addListener(function(details) {
// Create URL object from url string
var serverUrl = new URL(details.url);
// Get the origin (hostname)
var origin = serverUrl.hostname;
var seed = "Some dynamic value";
console.log("Injecting Value");
chrome.tabs.executeScript(details.tabId, {code: "var seed = '" + seed + "';console.log(seed);", runAt: "document_start"}, function() {
console.log("Value Injected");
});
});
函数addSeedCookie(详细信息){
seed=SomethingSynchronous();
详细信息。负责人。推送({
名称:“设置Cookie”,
值:`seed\u goes\u here=${seed}`
});
返回{
负责人:详细信息。负责人
};
}
chrome.webRequest.onHeadersReceived.addListener(
addSeedCookie,{URL:[“”]}[
“封锁”,
“负责人”,
//Chrome 72+需要“extraHeaders”来处理设置Cookie头
chrome.webRequest.OnHeadersReceivedOptions.EXTRA_头,
].filter(布尔值)
);
- inject.js
(function() {
function inject(filePath) {
var script = document.createElement('script');
script.src = chrome.extension.getURL(filePath);
script.onload = function() {
this.remove();
};
(document.head || document.documentElement).appendChild(script);
}
function injectText(text) {
var script = document.createElement('script');
script.textContent = text;
script.onload = function() {
this.remove();
};
(document.head || document.documentElement).appendChild(script);
}
console.log("CONTENT SCRIPT RUNNING");
console.log(seed); // SEED IS NOT DEFINED HERE ???
injectText("var seed = 'hello';");
console.log("[INFO] Injected Seed ...");
inject("js/ua.js");
console.log("[INFO] Injected UA ...");
inject("js/words.js");
console.log("[INFO] Injected Words ...");
inject("js/lib/seedrandom.min.js");
console.log("[INFO] Injected Seed Random ...");
inject("js/random.js");
console.log("[INFO] Injected Random ...");
inject("js/api/document.js");
console.log("[INFO] Injected Document API ...");
inject("js/api/navigator.js");
console.log("[INFO] Injected Navigator API ...");
inject("js/api/canvas.js");
console.log("[INFO] Injected Canvas API ...");
inject("js/api/history.js");
console.log("[INFO] Injected History API ...");
inject("js/api/battery.js");
console.log("[INFO] Injected Battery API ...");
inject("js/api/audio.js");
console.log("[INFO] Injected Audio API ...");
inject("js/api/element.js");
console.log("[INFO] Injected Element API ...");
})();
函数getCookie(cookie){//https://stackoverflow.com/a/19971550/934239
return document.cookie.split(“;”).reduce(函数(prev,c){
var arr=c.split('=');
返回(arr[0].trim()==cookie)?arr[1]:prev;
},未定义);
}
var seed=getCookie(“seed_到这里去”);
如果需要异步函数生成数据,请在onBeforeRequest事件中发送请求之前准备数据,然后在onHeadersReceived侦听器中使用它
constpreparedseed={};
chrome.webRequest.onBeforeRequest.addListener(
详细信息=>{
chrome.storage.local.get('seed',data=>{
preparedSeed[details.requestId]=data.seed;
});
}, {
网址:[''],
类型:[“主框架”、“子框架”],
});
注意:以上代码未经测试,仅用于说明想法。当您登录到该行时,您希望在哪里定义seed
?相关:看起来这是一个棘手的问题。我最终找到了一个完全不同的解决方案。谢谢你的帮助。哇,你是怎么想出这个Xan的?天才。