2017-08-21 76 views
1

我正在写一个隐私扩展,它需要我欺骗浏览器的用户代理属性,也就是navigator.userAgent(是的,我已经知道User-Agent HTTP头并且已经处理了该问题) 。浏览器仍然泄漏真正的用户代理

我的问题是,一个页面可能不仅仅有一个主框架,而且还有一个关于iframe的变量。在我的清单文件中,我使用了all_frames:true将我的内容脚本注入到所有框架和match_about_blank:true以注入具有“about:blank”url的框架。

我使用BrowserLeaks来测试我的扩展它似乎使用窗口选项正确地欺骗用户代理,但是当使用iframe.contentWindow方法时,它显示真正的用户代理。

我认为这可能是因为iframe是沙箱,你不允许注入到沙盒iframes。这将是一个巨大的问题,因为网站可以逃避扩展,并拒绝他们访问沙盒iframe。

这是我得到的铬错误:

阻止脚本执行在“关于:空白”,因为文档的帧是沙箱和“允许的脚本”权限未设置。

Chrome Developer

match_about_blank:

可选。是否将内容脚本插入about:blank和about:srcdoc。只有当内容脚本的继承URL与匹配字段中的一种已声明模式相匹配时,内容脚本才会被注入页面。继承URL是创建框架或窗口的文档的URL。 内容脚本不能插入沙盒框中。 默认为false。

或者脚本运行在所有包括沙盒的iframe中,但脚本运行速度不够快,即run_at:document_start。

MDN

match_about_blank:

match_about_blank是在Firefox从版本52.注意支持在Firefox中,内容脚本将无法在“document_start”注入到空的I帧,即使你指定值在run_at。

我的标题说铬扩展,但它也将是Firefox的。我发布了来自MDN和Chrome的文档,因为他们的措辞不同。在Chrome上,当我测试这个说github.com时,我得到关于在iframe上的沙盒上的错误,但在Firefox上我没有得到这样的错误,但它仍然不会像我想要的那样欺骗iframe中的属性。有任何想法吗?

的manifest.json

{ 
    "name": "Shape Shifter", 
    "version": "0.0.1", 
    "description": "Anti browser fingerprinting web extension. Generates randomised values for HTTP request headers and javascript API's.", 
    "manifest_version": 2, 
    "icons": { 
     "16": "icons/crossed_eye_16x16.png", 
     "32": "icons/crossed_eye_32x32.png", 
     "48": "icons/crossed_eye_48x48.png", 
     "128": "icons/crossed_eye_128x128.png" 
    }, 
    "background": { 
     "persistent": true, 
     "scripts": ["js/background.js"] 
    }, 
    "browser_action": { 
     "default_title": "Shape Shifter", 
     "default_icon": { 
      "16": "icons/crossed_eye_16x16.png", 
      "32": "icons/crossed_eye_32x32.png" 
     }, 
     "default_popup": "html/popup.html" 
    }, 
    "content_scripts": [ 
     { 
      "all_frames": true, 
      "match_about_blank": true, 
      "run_at": "document_end", 
      "matches": ["<all_urls>"], 
      "js": ["js/inject.js"] 
     } 
    ], 
    "permissions": [ 
     "webRequest", 
     "webRequestBlocking", 
     "<all_urls>" 
    ], 
    "web_accessible_resources": [ 
     "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(我的内容脚本)

console.log("Content Script Running ..."); 

function inject(filePath, seed) { 
    // Dynamically create a script 
    var script = document.createElement('script'); 

    // Give the script a seed value to use for spoofing 
    script.setAttribute("data-seed", seed); 

    // Give the script a url to the javascript code to run 
    script.src = chrome.extension.getURL(filePath); 

    // Listen for the script loading event 
    script.onload = function() { 
    // Remove the script from the page so the page scripts don't see it 
    this.remove(); 
    }; 

    // Add the script tag to the DOM 
    (document.head || document.documentElement).appendChild(script); 
} 

function getSeed(origin) { 
    // Get a Storage object 
    var storage = window.sessionStorage; 

    // Try to get a seed from sessionStorage 
    var seed = storage.getItem(origin); 

    // Do we already have a seed in storage for this origin or not? 
    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; 
} 

var seed = getSeed(window.location.hostname); 

inject("js/lib/seedrandom.min.js", seed); 
console.log("[INFO] Injected Seed Random ..."); 

inject("js/random.js", seed); 
console.log("[INFO] Injected Random ..."); 

inject("js/api/document.js", seed); 
console.log("[INFO] Injected Document API ..."); 

inject("js/api/navigator.js", seed); 
console.log("[INFO] Injected Navigator API ..."); 

inject("js/api/canvas.js", seed); 
console.log("[INFO] Injected Canvas API ..."); 

inject("js/api/history.js", seed); 
console.log("[INFO] Injected History API ..."); 

inject("js/api/battery.js", seed); 
console.log("[INFO] Injected Battery API ..."); 

inject("js/api/audio.js", seed); 
console.log("[INFO] Injected Audio API ..."); 

inject("js/api/element.js", seed); 
console.log("[INFO] Injected Element API ..."); 
+0

当你欺骗一个页面对象,你运行一个脚本页面,而不是内容脚本,这是为什么iframe的沙箱限制适用。我认为你无能为力。 – wOxxOm

+0

@ wOxxOm这真的很不幸。因此,如果一个页面想要获得用户代理的实际价值,他们只需制作一个沙盒的iframe,然后我的扩展就无法做到这一点?这使我的扩展毫无意义。有没有办法解决这个问题?以前使用旧版Firefox插件时,只需设置userAgent首选项值,但使用新的Web扩展名则无法再执行此操作。我想通过网络扩展来制作隐私扩展将成为一场噩梦。 – Snapper26

+0

请编辑题目:包括复制问题的[mcve]。对于Chrome扩展程序或Firefox WebExtensions,这通常意味着包含您的* manifest.json *以及一些背景,内容和/或弹出式脚本/ HTML。寻求调试帮助的问题(“为什么代码不按我想要的方式工作?”)必须包括:(1)期望的行为,(2)特定问题或错误,以及(3)重现它所需的最短代码*在问题本身*。另请参阅:[我可以在这里询问什么主题?](http://stackoverflow.com/help/on-topic)和[问]。 – Makyen

回答

0

我能解决这个问题,通过以下方式:

从我的内容脚本...

var UAScript = "document.addEventListener('DOMContentLoaded', function(event) { var iFrames = document.getElementsByTagName('iframe'); "+ 
       "for (i=0; i<iFrames.length; i++) try { Object.defineProperty(iFrames[i].contentWindow.clientInformation, 'userAgent', { value:'Custom' }); } catch(e) {} }); "+ 
       "try { Object.defineProperty(clientInformation, 'userAgent', { value:'Custom' }); } catch(e) {}"; 
var script = document.createElement("script"); 
script.type = "text/javascript"; 
script.textContent = UAScript; 
document.documentElement.appendChild(script); 

这会更改文档上的userAgent以及DOMContentLoaded触发器之后的iFrames。

问题是......有没有更好的方法来做到这一点?

(因为你仍然可以解决这个恶搞通过添加iframe中的iframe等)