内容简介:Hello readers! As promised inprevious blog post, today I’ll write (a bit more technically) about third party JS security, but from a different angle.Privacy Badger
Hello readers! As promised inprevious blog post, today I’ll write (a bit more technically) about third party JS security, but from a different angle.
Privacy Badger
Privacy Badger is a privacy focused browser extension by EFF , that detects and blocks third party trackers. Unlike other extensions, it does it by analyzing the tracking behaviors, rather than relaying on domains blacklist.
Canvas fingerprinting
On of these tracking behaviors is canvas fingerprinting, which I briefly mentioned in previousblog posts. Generally speaking, canvas fingerprinting is a method to generate stateless, consistent, high entropy identifier from the HTML5 canvas element , by drawing several graphics primitives into it and then serialize its pixels. Different browsers and devices produce slightly different pixels due to differences in their graphics rendering stack. You can read the paper “ Pixel Perfect: Fingerprinting Canvas in HTML5 ” for more info.
Privacy Badger Canvas fingerprinting detection
From Privacy Badger website:
Does Privacy Badger prevent fingerprinting?
Browser fingerprinting is an extremely subtle and problematic method of tracking, which we documented with the Panopticlick project . Privacy Badger 1.0 can detect canvas based fingerprinting , and will block third party domains that use it. Detection of other forms of fingerprinting and protections against first-party fingerprinting are ongoing projects. Of course, once a domain is blocked by Privacy Badger, it will no longer be able to fingerprint you.
How Privacy Badger detect canvas fingerprinting
Privacy badger injects fingerprinting.js , along with several other context scripts, as specified in its manifest.json , to all the frames ( “ all_frames “ : true ) of all the pages ( “matches”: [ “<all_urls>” ] ) visited by the user, before any other script in the page has executed ( “ run_at “ : “ document_start “ ).
Content script have access to their frame DOM, but a separate JavaScript context. Because the goal of the script requires to monitors things that happen in the page JS context (canvas manipulation and serialization), this content script injects another, self removing script into the frame DOM, which executes in its JS context.
This script hooks into several canvas related APIs, including fillText (manipulation) and toDataURL (serialization). I wrote about JS hooking before, in the context of spoofing viewabiliy measurements . Whenever once of these APIs gets called, Privacy Badger hook is figuring out the caller script URL form within the call stack.
Threat Model
When designing and implementing fingerprinting countermeasures, there are two significant concerns:
- Observability: which means trackers can fingerprint the presence of the fingerprinting countermeasure itself and using it as another data point in the fingerprint.
- Bypassability: which means tracker can evade the fingerprinting countermeasure or rendering it useless, thus getting access to the desired fingerprinted feature.
Vulnerabilities in Privacy Badger canvas fingerprinting detection
- Observability of the canvas API hooking:
as I wrote previously in depth at “ JavaScript tampering – detection and stealth ” (my most visited blog post so far!), there are several methods to detect that a native function was tampered with. Privacy Badger recognized this threat and tries to hide the tampering by setting the length, name, and toString properties of the hooked functions to match those of the original, but without referring to the native Function.protype.toString, a tracker can write:
Function.prototype.toString.call(HTMLCanvasElement.prototype.toDataURL);
And get:
"function wrapped() { var args = arguments; ...
Of course, it also won’t pass the prototype and hasOwnProperty test (detailed explanationhere).
- Bypassability of the APIs hooking
Privacy Badger recognized this threat site code tampering with its own code, and tries to prevent this by copying the objects it uses into its own function scope . However, it still relies on prototype inherited methods inside the hook code itself, and these methods can be abused to steal the reference to the original API. Let’s look closely on the hook code itself , which gets called whenever a consumer calls one of the hooked canvas APIs:
function wrapped() { var args = arguments; if (is_canvas_write) { // to avoid false positives, // bail if the text being written is too short if (!args[0] || args[0].length < 5) { return orig.apply(this, args); } } var script_url = ( V8_STACK_TRACE_API ? getOriginatingScriptUrl() : getOriginatingScriptUrlFirefox() ), msg = { obj: item.objName, prop: item.propName, scriptUrl: script_url }; if (item.hasOwnProperty('extra')) { msg.extra = item.extra.apply(this, args); } send(msg); if (is_canvas_write) { // optimization: one canvas write is enough, // restore original write method // to this CanvasRenderingContext2D object instance this[item.propName] = orig; } return orig.apply(this, args); }
As we can see, there’s an interesting exception: if is_canvas_write is true and the length of the first arg is shorter then 5, the original function gets called, using the prototype inherited apply method , and returns before send(msg) is called, so Privacy Badger won’t be considering it as a fingerprinting attempt, to avoid false positives.
We can look few lines up and see that is_canvas_write is computed as:
var is_canvas_write = ( item.propName == 'fillText' || item.propName == 'strokeText' );
So, our attack will look like this:
-
- Hook the apply method
- Call the hooked fillText or strokeText
- Steal the reference to the original fillText or strokeText
- Write to the canvas text with length > 5 using the original function
Let’s implement a PoC:
let _apply = Function.prototype.apply; let original; Function.prototype.apply = function () { // `this` is the function if (this.name === 'fillText' || this.name === 'strokeText') { original = this; } // restore the original apply Function.prototype.apply = _apply; };
Then, we call the function:
var canvas = document.createElement('canvas'); var ctx = canvas.getContext('2d'); ctx.fillText('a'); };
And now we have the original fillText:
original ƒ fillText() { [native code] }
Viola!
The same technique can be used to extract the original serialization method, toDataURL. Notice the call to getOriginatingScriptUrl which is also using prototype inherited methods that can be tampered with.
Another bypass method is to obtain a references to the original APIs by using the iframe sandbox attribute . This attribute allows us to specify permissions for the content inside the iframe, and if we specify the allow-same-origin permission and don’t specify the allow-scripts permission, the script injected by the context script won’t execute, according the the sandbox policy[1], but the embedding page will be able to access the iframe’s contentWindow and obtain an unhooked canvas from it.
That’s it for today! Although this topic could be expanded even more, I’ll save something for next time
Hope you enjoyed, and feel free to contact me to discuss any of it!
[1] This is currently true in Firefox, but not in Chrome. In the past I observed the same behavior in Chrome, but from my test it seems like now DOM script that was added from content script will execute inside sandboxed iframes. I’m not sure if that’s intentional.
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
数据结构算法与应用
塞尼 / 机械工业出版社 / 1999-3 / 49.00元
数据结构、算法与应用—C++语言描述(英文版),ISBN:9787111070177,作者:(美)塞尼 著一起来看看 《数据结构算法与应用》 这本书的介绍吧!
MD5 加密
MD5 加密工具
Markdown 在线编辑器
Markdown 在线编辑器