Skip to content
This repository has been archived by the owner on Dec 11, 2019. It is now read-only.

Commit

Permalink
block access to child frames' contentWindow, contentDocument, place g…
Browse files Browse the repository at this point in the history
…uard in blocking proxy to prevent an infinite loop, issue #11683
  • Loading branch information
pes10k committed Nov 15, 2017
1 parent 7024bff commit fadd508
Show file tree
Hide file tree
Showing 3 changed files with 100 additions and 0 deletions.
59 changes: 59 additions & 0 deletions app/extensions/brave/content/scripts/blockCanvasFingerprinting.js
Original file line number Diff line number Diff line change
Expand Up @@ -106,9 +106,21 @@ if (chrome.contentSettings.canvasFingerprinting == 'block') {
return undefined
}

var callCounter = 0

var allPurposeProxy = new Proxy(defaultFunc, {
get: function (target, property) {

// If the proxy has been called a large number of times on this page,
// it might be stuck in an loop. To prevent locking up the page,
// return undefined to break the loop, and then resume the normal
// behavior on subsequent calls.
if (callCounter > 1000) {
callCounter = 0
return undefined
}
callCounter += 1

if (property === Symbol.toPrimitive) {
return valueOfCoercionFunc
}
Expand Down Expand Up @@ -267,4 +279,51 @@ if (chrome.contentSettings.canvasFingerprinting == 'block') {
type: 'WebRTC',
methodName: 'navigator.mediaDevices.enumerateDevices'
})

var propertiesToReport = new Set(canvasMethods
.concat(canvasElementMethods)
.concat(webglMethods)
.concat(audioBufferMethods)
.concat(analyserMethods)
.concat(svgPathMethods)
.concat(svgTextContentMethods)
.concat(webrtcMethods)
.concat(['enumerateDevices']))

var iframeProxy = new Proxy(allPurposeProxy, {
get: function (ignore, property) {
if (propertiesToReport.has(property)) {
reportBlock('Iframe')
}

return iframeProxy
}
})

chrome.webFrame.setGlobal("window.__braveIframeProxy", iframeProxy)

// Prevent access to frames' contentDocument / contentWindow
// properties, to prevent the parent frame from pulling unblocked
// references to blocked standards from injected frames.
// This may break some sites, but, fingers crossed, its not too much.
var pageScriptToInject = function () {
var frameTypesToModify = [window.HTMLIFrameElement, window.HTMLFrameElement]
var propertiesToModify = ['contentWindow', 'contentDocument']
var braveIframeProxy = window.__braveIframeProxy
delete window.__braveIframeProxy

frameTypesToModify.forEach(function (frameType) {
propertiesToModify.forEach(function (propertyToModify) {
Object.defineProperty(frameType.prototype, propertyToModify, {
get: () => {
// XXX: this breaks contentWindow.postMessage since the target window
// is now the parent window
return braveIframeProxy
}
})
})
})
}

chrome.webFrame.executeJavaScript(`(${pageScriptToInject.toString()})()`)
}
13 changes: 13 additions & 0 deletions test/bravery-components/braveryPanelTest.js
Original file line number Diff line number Diff line change
Expand Up @@ -895,6 +895,19 @@ describe('Bravery Panel', function () {
.tabByIndex(0)
.waitUntil(verifyProxyBlocking)
})
it('blocking access to fingerprinting methods on iframe.contentWindow', function * () {
const url = Brave.server.url('fingerprinting-blocking-from-child-frames.html')
yield this.app.client
.tabByIndex(0)
.loadUrl(url)
.waitForUrl(url)
.openBraveMenu(braveMenu, braveryPanel)
yield changeFpSetting(this.app.client, blockFpOption)
yield this.app.client
.keys(Brave.keys.ESCAPE)
.tabByIndex(0)
.waitUntil(verifyProxyBlocking)
})
it('block device enumeration', function * () {
const url = Brave.server.url('enumerate_devices.html')
yield this.app.client
Expand Down
28 changes: 28 additions & 0 deletions test/fixtures/fingerprinting-blocking-from-child-frames.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<html>
<head>
</head>
<body>
<div id="target">
proxy blocking being tested
</div>
<script>
(function () {

let parentFrameMethod = window.HTMLCanvasElement.prototype.toDataURL

let iframe = document.createElement("iframe")
iframe.src = "https://example.com/"
document.body.appendChild(iframe)

// Not blocked
let childFrameMethod = iframe.contentWindow.HTMLCanvasElement.prototype.toDataURL

if (parentFrameMethod() === childFrameMethod()) {
// If an exception is thrown in the above code, the below line will never
// run, and the text in the div will never be changed (ie test fails).
document.getElementById('target').innerHTML = 'proxy blocking works'
}
}())
</script>
</body>
</html>

0 comments on commit fadd508

Please sign in to comment.