This paper is included in the Proceedings of the
28th USENIX Security Symposium.
August 14–16, 2019 • Santa Clara, CA, USA
978-1-939133-06-9
Open access to the Proceedings of the
28th USENIX Security Symposium
is sponsored by USENIX.
Rendered Private: Making GLSL Execution Uniform
to Prevent WebGL-based Browser Fingerprinting
Shujiang Wu, Song Li, and Yinzhi Cao, Johns Hopkins University; Ningfei Wang,
Lehigh University
https://www.usenix.org/conference/usenixsecurity19/presentation/wu
Rendered Private: Making GLSL Execution Uniform to Prevent WebGL-based
Browser Fingerprinting
Shujiang Wu, Song Li, Yinzhi Cao, and Ningfei Wang
Johns Hopkins University, Lehigh University
{swu68, lsong18, yinzhi.cao}@jhu.edu, wangningfei7@gmail.com
Abstract
Browser fingerprinting, a substitute of cookies-based track-
ing, extracts a list of client-side features and combines them
as a unique identifier for the target browser. Among all these
features, one that has the highest entropy and the ability for
an even sneakier purpose, i.e., cross-browser fingerprinting,
is the rendering of WebGL tasks, which produce different
results across different installations of the same browser on
different computers, thus being considered as fingerprintable.
Such WebGL-based fingerprinting is hard to defend against,
because the client browser executes a program written in
OpenGL Shading Language (GLSL). To date, it remains un-
clear, in either the industry or the research community, about
how and why the rendering of GLSL programs could lead
to result discrepancies. Therefore, all the existing defenses,
such as these adopted by Tor Browser, can only disable We-
bGL, i.e., a sacrifice of functionality over privacy, to prevent
WebGL-based fingerprinting.
In this paper, we propose a novel system, called UN IG L, to
rewrite GLSL programs and make uniform WebGL rendering
procedure with the support of existing WebGL functionalities.
Particularly, we, being the first in the community, point out
that such rendering discrepancies in state-of-the-art WebGL-
based fingerprinting are caused by floating-point operations.
After realizing the cause, we design UN IGL so that it rede-
fines all the floating-point operations, either explicitly written
in GLSL programs or implicitly invoked by WebGL, to miti-
gate the fingerprinting factors.
We implemented a prototype of UNI GL as an open-source
browser add-on (
https://www.github.com/unigl/
). We
also created a demo website (
http://test.unigl.org/
),
i.e., a modified version of an existing fingerprinting web-
site, which directly integrates our add-on at the server-side
to demonstrate the effectiveness of UNI GL. Our evaluation
using crowdsourcing workers shows that UNI GL can prevent
state-of-the-art WebGL-based fingerprinting with reasonable
FPSes.
The last author, Ningfei Wang, contributed to the paper when he was a
master student financially supported and mentored by Dr. Yinzhi Cao.
1 Introduction
Browser fingerprinting [12,13,20,23,34,45,63], a substitute
of traditional cookie-based approaches, is recently widely
adopted by many real-world websites to track users’ browsing
behaviors potentially without their knowledge, leading to a
violation of user privacy. In particular, a website performing
browser fingerprinting collects a vector of browser-specific
information called browser fingerprint, such as user agent, a
list of browser plugins, and installed browser fonts, to uniquely
identify the target browser.
Among all the possible fingerprintable vectors, the render-
ing behavior of WebGL, i.e., a Web-level standard that follows
OpenGL ES 2.0 to introduce complex graphics functionali-
ties to the browser, is an important factor that contributes the
most, in terms of entropy, to the overall distinguishability of
browser fingerprints [19]. Specifically, WebGL-based finger-
printing is first discovered by Mowery et al. [41], and then
further explored by Cao et al. [19], who not only show that
WebGL-based fingerprinting has the highest entropy among
all fingerprinting factors, but also demonstrate the ability of
WebGL-based fingerprinting for an even sneakier purpose,
i.e., cross-browser fingerprinting, compared to traditional fin-
gerprinting vectors like user agents.
In order to prevent WebGL from being used as a vector
of browser fingerprinting, Tor Browser, the pioneer private
browser for the Web makes WebGL click-to-play, i.e., dis-
abling it by default, so that a website cannot use it for the
tracking purpose. However, there exists a tradeoff between
privacy and functionality: Tor Browser sacrifices an important
functionality—i.e., all the computer graphics features brought
by WebGL, which are particularly useful for modern web
applications like games [10] and virtual reality [50]—for pri-
vacy. Specifically, according to a 2016 study [55], about 10%
of Top 10K Alexa websites, including famous ones visited
by billions of users such as Google Map and Earth [2], adopt
WebGL to augment user experience—and the number keeps
increasing as the WebGL community grows. Therefore, the
research question that we want to ask in the paper is whether
USENIX Association 28th USENIX Security Symposium 1645
a browser can allow Web applications to use WebGL and its
abundant functionalities without violating users’ privacy.
Before answering this question, we first take a look at how
existing works prevent browser fingerprinting that does not
use WebGL. There are two categories of approaches in defend-
ing against browser fingerprinting in general (e.g., these based
on fonts, plugins, and user agent), which are randomization
and uniformity. The former, adopted by PriVaricator [44] and
some browser add-ons [1,9], adds noise to the fingerprinting
results so that an adversary cannot obtain an accurate finger-
print each time. However, according to prior work [18,49],
such randomization-based defense can be defeated if the ad-
versary fingerprints the browser multiple times and averages
the results. In addition, according to a recent work [59], incon-
sistencies in browser fingerprints may cause further privacy
violations. Because of these concerns, Tor Browser also ex-
plicitly prefers the latter, i.e., uniformity, over randomization
in its design document [49].
Therefore, our detailed research question becomes how to
make uniform WebGL rendering results and prevent WebGL-
based browser fingerprinting. The answer to this question is
unknown in the community as indicated in Tor Browser’s
practice of disabling WebGL. The reason is that unlike other
forms of fingerprinting (e.g., user agent and fonts), which rely
on the outputs of a browser API, WebGL-based fingerprinting
runs a program, i.e., a rendering task, in OpenGL Shading
Language (GLSL). One possible solution, i.e., an idea floated
in the design document [49] of Tor Browser without any
implementation, is to adopt software rendering and make
uniform WebGL rendering. However, Cao et al. [19] show
that even if software rendering is enabled, WebGL rendering
results are still fingerprintable.
Now, to answer the specific question of making WebGL
uniform in the paper, we need to understand why a single
WebGL rendering task differs much from one browser to an-
other. From a high level, the reason is that computer graphic
tasks pursue visual rather than computational uniformity. One
single WebGL task on different browsers is rendered by a
different combination of a variety of computer graphics ren-
dering layers, such as browsers, graphics libraries (e.g., Di-
rectX and OpenGL) including conversion interfaces (e.g.,
Almost Native Graphics Layer Engine, i.e., ANGLE), render-
ing mechanisms, device drivers and graphics cards. Therefore,
different implementations and even versions of these various
layers will lead to a computationally different rendering result.
This high-level answer also partially explains the reason that
software rendering cannot prevent fingerprinting: Software
rendering, belonging to rendering mechanisms, is just one of
the many layers that could lead to the rendering discrepancies,
and it may also have different versions and implementations.
While this problem appears hard to solve unless we make
uniform all the graphics layers, the root reason, after our in-
tensive manual study and experiment, can be summarized
as one surprisingly concise and abstract sentence—i.e., the
results of floating-point operations on different machines are
different inside and across various graphics layers, leading
to rendering differences. This one-sentence, intuitive reason
can be further broken down into many sub-reasons when the
WebGL rendering performs various operations in different
graphics layers. Let us illustrate two examples.
First, we consider the color value, i.e., RGB, in WebGL,
which semantically ranges from 0 to 255 but is represented
as a floating-point from 0 to 1. Therefore, a conversion is re-
quired when WebGL renders a 0–1 color value on the screen
to be a 0–255 RGB value—and most importantly the con-
version, i.e., a floating-point operation, will lead to rendering
difference. Say one WebGL implementation, i.e., a combi-
nation of different graphics layer, multiplies the color value
with 255 and applies
f loor
to convert it to the RGB value,
and the other applies
round
. Then, a color value of
<
0.5, 0.5,
0.5
>
will be rendered as
<
127, 127, 127
>
in the former, but
as
<
128, 128, 128
>
in the latter. This float-to-int conversion
issue can be generalized in many other representation, such as
alpha value, texture size, and canvas size—and also other con-
version algorithms beyond
f loor
and
round
, such as linear
interpolation in texture mapping.
Second, let us consider another common graphics operation
involving several float multiplications and then a subtraction,
i.e., we need to decide whether a given point, very close to one
triangle edge, is inside the given triangle. Say, there are two
WebGL implementations, one adopting 10-bit float numbers
and the other a higher precision, i.e., 16-bit. The multiplication
results on these two implementations differ slightly, because
the former has fewer decimals than the latter. Because the
given point is very close to the triangle, such slight difference
will propagate to the float subtraction, leading to a positive in
the former implementation but a negative the latter. Therefore,
the point will be judged as either inside or outside the triangle
in these two implementations, causing a rendering difference.
That said, the key insight of the paper is that we need to
make uniform all the floating-point operations across various
computer graphics layers. Specifically, we adopt two integers,
one as the numerator and the other as the denominator, to
simulate floating-point operations in GLSL programs so that
the underlying layers, regardless of their implementation or
approximation for floating-point operations, always produce
the same results. When we need to feed simulated values
into WebGL, we convert the value to a float based on its
semantics. In the aforementioned color value example, we
can use 127/255 to represent 127 and 128/255 for 128, leading
to no confusions under different implementations.
While the idea is intuitively simple, the major challenge
is that WebGL rendering process involves implicit floating-
point operations. In order to understand this challenge, let us
briefly describe the three-stage WebGL rendering process—
i.e., (i) vertex rendering, (ii) rasterization and interpolation,
and (iii) fragment rendering—and corresponding floating-
point operations in each stage. The first stage, controlled by a
1646 28th USENIX Security Symposium USENIX Association
GLSL program, i.e., vertex shader, generates vertices infor-
mation using graphics operations, e.g., transformation and
rotation, and also associates attribute values with each ver-
tex. These aforementioned graphics operations are all related
to floating-point operations. Then, the second stage, an im-
plicit one implemented by WebGL and not controlled by any
GLSL program, generates fragments, called rasterization, and
then interpolates values based on fragments using floating-
point operations. Lastly, the third stage, controlled by another
GLSL program, called fragment shader, colors each fragment,
which also involves floating-point operations, such as texture
mapping.
In this paper, we propose UN IGL, a novel system that
rewrites GLSL programs and redefines all the floating-point
operations in the aforementioned three stages of WebGL ren-
dering. Specifically, UNI GL hooks JavaScript APIs—which
accept GLSL programs and the corresponding parameters
such as vertex and index arrays—and then rewrites both ver-
tex and fragment shaders via three phases mapping to the
three stages of WebGL rendering. First, UNI GL converts the
vertex shader to a JavaScript program and executes it. Dur-
ing the execution, floating-point operations in vertex shader,
e.g., matrix multiplication, are executed as JavaScript, thus
kept with uniformity. Second, UNI GL takes the execution
results of JavaScript vertex shader and feeds them into a cus-
tomized rasterization and interpolation engine written as a
fragment shader. In this phase, UNI GL preserves uniformity
for floating-point operation implemented natively in WebGL’s
rasterization and interpolation module via integer simulation.
Lastly, UNIGL rewrites the original fragment shader and re-
defines floating-point operations, such as texture mapping, in
the fragment shader via integer simulation.
In designing UN I GL, we realize the following additional
challenges from the viewpoint of system building.
Backward Compatibility. We want UNI GL to be back-
ward compatible with existing commercial Web Browsers.
Specifically, we deploy UNI GL as a browser add-on, easily
installable, to protect Web users’ privacy.
Performance. We want to keep the high-performance ben-
efits brought by WebGL, especially when it runs on GPU.
Therefore, we design UNI GL so that the rendering bottle-
neck, i.e., rasterization, interpolation and coloring, runs as
a GLSL program on fragment shader possibly via GPU (de-
pending on whether the underlying rendering mechanism
is software or hardware rendering). Note that the vertex
shader has to run as a JavaScript program because other-
wise we do not have access to intermediate results between
two shaders without modifying the browser. Because of
this, we adopt multiple optimization techniques, such as
caching, typed array, and code-data separation, to speed up
UNI GL’s vertex shader.
Variable Number Limits. Since we choose backward com-
patibility, we are constrained by the limit that is enforced
by the current version of WebGL. Particularly, all current
1: Vertex
Rendering
Rendering
Procedure:
WebGL:
Floating-point
Operations:
2: Rasterization
& Interpolation
3: Fragment
Rendering
Vertex shader
(GLSL)
Native WebGL
implementation (C/C++)
Fragment shader
(GLSL)
Matrix and other
Math operations
Triangle judgement, Z-buffer
calculation, interpolation of
varying variables, and so on.
Matrix and Math
operations, and
texture mapping
UniGL: JavaScript (parallel
and speed-up)
Fragment Shader
(GLSL)
Fragment Shader
(GLSL)
Floating-point
Uniformization:
JavaScript operation Integer simulation Integer simulation
Figure 1: A High-level Overview of Rendering Procedure (i.e., the
execution of GLSL programs) in both WebGL and UN IG L as well
as a Description of Corresponding Floating-point Operations
implementations of WebGL have enforced a limit [26] for
“uniform” variables, sometimes 256 or 1024 depending on
the graphics card and operating system. Therefore, in de-
signing UN IG L, we have to divide one rendering task itera-
tively until each small one can fit into and run as a fragment
shader.
We implemented a prototype of UNI GL as an open-source
Google Chrome add-on, which is available at the repositories
of this GitHub user (
https://www.github.com/unigl/
).
We also created a demo website, i.e.,
http://test.unigl.
org/
, which works on modern web browsers including
Chrome, Firefox, and Safari. Specifically, the demo is a mod-
ified version of Cao et al.’s fingerprinting website [19], which
directly integrates our add-on at the server-side, to show that
UNI GL can prevent WebGL-based browser fingerprinting.
We make the following contributions in the paper:
We are the first to point out that WebGL-based browser
fingerprinting is caused by floating-point operations.
We design UNI GL to rewrite GLSL programs and rede-
fine all, i.e., explicit and implicit, floating-point operations
embedded deeply inside WebGL.
We show that our prototype of UN IG L can defend against
WebGL-based browser fingerprinting with reasonable FPS.
2 Overview
We give an overview of WebGL and UN IGL rendering proce-
dure, and then present a running example.
2.1 WebGL’s Rendering and Floating-point Operations
WebGL’s rendering procedure can be roughly divided into
three stages as shown in Figure 1. First, the vertex shader
in WebGL performs operations, e.g., rotation via a matrix
multiplication, related to the vertices of a computer graphics
model. Specifically, the shader accepts two types of variables,
i.e., attributes and uniforms, binds attributes, such as texture
coordinates, to vertices, and then outputs transformed vertices,
i.e.,
gl_Position
, and varyings. Many operations in the vertex
shader, such as matrix multiplication and Math functions like
sqrt, have floating-point values involved.
Second, the outputs of the vertex shader are fed into the
rasterization and varying interpolation module implemented
USENIX Association 28th USENIX Security Symposium 1647
natively by WebGL. The module maps a computer graphics
model to each pixel on the canvas and interpolates each vary-
ing variable based on the attribute values on each vertex. Let
us illustrate three major floating-point related operations in
this module. (i) The module decides whether a given pixel is
inside a triangle. (ii) The module calculates the z-buffer of
each point, i.e., determining whether a point is in front of or
behind another on the canvas. (iii) The module interpolates a
varying variable based on attributes.
Lastly, the outputs of the rasterization and varying inter-
polation module are fed into the fragment shader in WebGL,
which paints all pixels on the canvas by assigning a value to
gl_FragColor
. All the floating-point related operations in the
vertex shader, such as matrix operations, also exist in the frag-
ment shader. Additionally, color lookup operations, such as
texture mapping, need to fetch a color from a texture, which
involve floating-point operations as well.
2.1.1 An Explanation of Floating-point Operation and
Rendering Discrepancies
We now explain that floating-point operations will cause ren-
dering discrepancies. Figure 2shows a classic computer
graphics model, i.e., a 3D monkey head, covered with a ran-
dom texture. We render this WebGL task in Google Chrome
browser on two different machines, one iMac and the other
Dell with Windows system—the rendering results, though
being visually the same (Left and Middle of Figure 2), are
quite different if we compare them pixel by pixel (Right of
Figure 2).
This model is complex with many floating-point operations
and thus hard to explain the discrepancies. We now decom-
pose the complex model into several small experiments with
only one or a few types of floating-point operations for expla-
nation.
A Varying Experiment. We setup a thin 3
×
100 rectangle
and then specify a varying variable spanning along the long
edge from 0 to 100. The variable starts from a color
<
0,
0, 0
>
at position 0 and ends to a color
<
0, 0, 255
>
at
position 100. That is, we are rendering a simple spectrum
on a canvas with only one type of floating-point operation,
i.e., the interpolation of a varying variable between 0 and
100.
When we perform this varying experiment on different
machines and compare the rendering results, we find that
the result differences are several single-pixel lines orthog-
onal to the long edge. This explains that floating-point
operations for interpolating varying variable will lead to
rendering discrepancies.
A Triangle Experiment. We setup a triangle on a 255
×
255
canvas: two vertices at
<
127, 0
>
and
<
0, 128
>
, and the
third movable along the line from
<
255, 0
>
to
<
255, 255
>
.
We then color the triangle with only a single color, such as
black. By doing so, we create a rendering task with another
Figure 2: An Illustration of Rendering Task Difference for Browser
Fingerprinting Purpose (Left: A classic monkey head model rendered
in Google Chrome on an iMac, Middle: the same model rendered in
Google Chrome on a Windows machine, Right: The pixel difference
between these two rendering results.)
type of floating-point operation, i.e., determining whether
a pixel is inside a triangle.
When we perform this triangle experiment on different
machines and move the point along the edge, we find that
the result difference is a single pixel close to the triangle
edge for a special third vertex position. This explains that
floating-point operations for triangle judgement will lead
to rendering discrepancies.
A Texture Experiment. We setup a triangle and then map
a random texture onto the triangle. That is, we create a
rendering task with a texture mapping operation, which has
floating-point operations in color interpolation.
When we perform this texture experiment on different ma-
chines, we find that the result differences are several pixels
within the triangle. This explains that floating-point opera-
tions for texture mapping will lead to rendering discrepan-
cies.
2.2 UN IG L’s Rendering and Floating-point Operations
Now let us go over the three-stage rendering procedure
(Figure 1) again in UNI GL and show how to make uni-
form floating-point operations in aforementioned steps.
First, UN IG L moves the vertex shader from GLSL to
JavaScript, i.e., all the floating-point operations are executed
on JavaScript interpreter and thus handled by CPU without
any discrepancies. Note that we need to adopt parallel work-
ers and many other speed-up techniques to run the JavaScript
version of vertex shader fast.
Second, UN IG L implements a customized rasterization
and varying interpolation module via GLSL in which all the
floating-point values are represented via integer simulation,
and therefore, all the aforementioned floating-point operations
in this module are made uniform. It is worth noting that
theoretically we can also implement the module via JavaScript
for uniformization, but the performance is unacceptable.
Lastly, UNIGL executes the fragment shader in GLSL, but
rewrites all the floating-point operations via integer simula-
tion. Additionally, UN IG L also implements a customized
texture mapping algorithm using integers so that the color
lookup operation in texture mapping is also made uniform.
2.3 A Running Example
After a high-level overview of UN IGL rendering, we now
present a detailed running example to illustrate our target
problem and how UN IG L solves the problem via uniformity.
1648 28th USENIX Security Symposium USENIX Association
JavaScript:
1ve rs = [. .. ]; // v e rt i c es i n f or m at i o n
2in ds = [. .. ]; // i n di c es i n fo r ma t i on
3.. .
4var ve r s B uf f e r Ob j e c t = g l . c r ea t e B uf f e r ( ) ;
5gl . b i n dB u f fe r ( g l . A R RA Y _ BU F F ER , ve r sB u f f er O b j ec t ) ;
6gl . b u f fe r D at a ( g l . A R RA Y _ BU F F ER , new Float32Array (vers),
gl . S TA T IC _ DR AW ) ;
7var in d e x Bu f f e rO b j e ct = gl . c re a t eB u f f er () ;
8gl . b i n dB u f fe r ( g l . E L E ME N T _A R R A Y_ B U F FE R , in de x B u ff e r O b je c t
);
9gl.bufferData( gl.ELEMENT_ARRAY_BUFFER , new Ui n t1 6 Ar r ay (
in d s ) , gl. S T A T IC _ D RA W ) ;
10 .. .
11 gl . b i n dB u f fe r ( g l . A R RA Y _ BU F F ER , ve r sB u f f er O b j ec t ) ;
12 var po s At t r = g l . g e tA t t r ib L o c at i o n ( p r og r am , ’aVersPos’);
13 .. .
14 var uM V Lo c = g l . g e t Un i f o rm L o c at i o n ( p r og r am , "uMVMatrix");
15 gl . u ni f om M at ri x 4f v ( u MV Lo c , [. .. ]) ;
16 .. .
17 // b in d o th er a t tr i bu t e s an d un i f or m s
18 gl . d r a wE l e m en t s ( g l . T RI A NG L E S , le ng t h , gl . U N S IG N E D_ S H OR T
,0 ) ;
Vertex Shader:
1attribute vec3 aV er sP o s , aV e rs No r ma l ;
2attribute vec2 aT e xt u re Co o rd ;
3uniform mat4 uM VM a tr ix , uP Ma tr i x ;
4uniform mat3 uNMatrix;
5uniform vec3 uA mb C ol or , uL tD ir , uD i rC o lo r ;
6varying vec2 vT e xt u re Co o rd ;
7varying vec3 vLightWeighting;
8void main(void) {
9gl_Position= u PM a t ri x * u MV M at r i x * vec4(a V er s Po s . xy z ,
1.0);
10 vT e xt u re Co o rd = a T ex t ur e Co o rd ;
11 vL i g ht W ei g h ti n g = u A mb C ol o r + u Di r Co l or * m a x ( do t (
uN M a tr i x * aV e rs N o rm a l , uL t Di r ) , 0. 0 ) ;
12 }
Fragment Shader:
1varying vec2 vT e xt u re Co o rd ;
2varying vec3 vLightWeighting;
3uniform sampler2D uSampler;
4void main(void) {
5vec4 te x Co lo r = t ex t ur e 2D ( u Sa mp l er , v Te x tu r eC o or d ) ;
6gl_FragColor=vec4( t e xC o lo r . rg b * v L ig h tW ei g ht i ng ,
texColor.a);
7}
JavaScript:
1ve rs = [ . . .] ; / / ve r ti c es i n fo r m at i on
2in ds = [ . . .] ; / / in d ic e s i nf o r ma t io n
3.. . // h o ok J S AP I s to o b ta i n ar g u me n ts
4var UniGL_aVersPos=UniGLAttr( ’aVersPos’) ;
5var Un i GL _ uM V Ma t ri x = U ni GL U ni f or m ( ’uMVMatrix ’);
6.. .
7fo r ( Un i GL _I =0 ; Un i GL _I < At t rL en ;U n iG L _I + + ) {
8// T r an s fo r m ed J S v er t ex s h ad e r
9aV e rs Po s = U ni G L_ a Ve rs P os [ U n iG L_ I ] ;
10 uM V Ma tr i x = Un i GL _ uM V Ma t ri x ;
11 .. .
12 UniGL_Position=UniGLMultiply (UniGLMultiply( uPMatrix,
uM V Ma t ri x ) , Un i GL V ec 4 ( U ni G LE x tr a ct ( a Ve rs P os ,
[1 , 1 ,1 ]) , 1 .0 ) );
13 vT e xt u re Co o rd = a T ex t ur e Co o rd ;
14 vL i gh t We i gh t in g = U ni G LA d d ( uA mb C ol or , U ni G LM u lt i pl y (
uD ir C ol or , U ni G LM a x ( Un i GL Do t ( U ni G LM u l ti p ly ( u NM at r ix ,
aV e r sN o r m al ) , uL t D ir ) , 0. 0 ) ) );
15 // end of transformation
16 Un i G L_ v Te x t ur e C oo r d . pu s h ( v Te x tu r e Co o rd ) ;
17 Un i G L_ v Li g h tW e i gh t i ng . p u sh ( v L i gh t We i g ht i ng );
18 }
19 Un i GL _ C al l Fr a gm e nt S h ad e r ( Un i GL _ Po si t io n ,
Un i GL _v T ex t ur eC o or d , U ni G L_ v Li g ht We i gh t in g ) ;
Fragment Shader:
1#define N At t r ib u te N u mb e r
2uniform ivec3 UniGL_Position[N];
3uniform ivec2 Un i G L _v T e x tu r e C o or d [ N ] ;
4uniform ivec3 UniGL_vLightWeighting[N];
5uniform sampler2D uSampler;
6void main(void) {
7fo r ( U ni G L_ I = 0; U ni GL _ I < N ; Un i GL _I += 3) {
8if ( Un i GL _ In T ri a ng l eZ B uf f er ( g l_ Fr a gC oo r d , U n iG L_ I ) ) {
9vT e xt u re C oo r d = Un i GL _ I nt e rp o la t e ( g l_ Fr a gC o or d ,
Un iG L_ I , U ni G L_ v Te x tu r e Co o rd [ U n iG L _I ] ,
Un i GL _ v Te x tu r e Co o rd [U n iG L _I +1] , U ni G L _v T ex t u re C oo r d [
Un i GL _ I + 2] ) ;
10 vL i g ht W ei g h ti n g = . .. ;
11 // T r an s fo r m ed f r a gm e nt s ha d er
12 iv e c4 te x C ol o r = Un i G L_ t e xt u re 2 D ( u Sa mp l er ,
vT e xt u re Co o rd ) ;
13 gl_FragColor= U ni G L_ i 2f ( i v ec 4 ( U ni G L _M u lt i pl y ( t e xC o lo r
.r g b , v L i g h t We i g h t i ng ), t e x C o lo r . a ) ) ;
14 // end of transformation
15 }
16 }
17 }
Figure 3: A Running Example (Left: The original code, Right: The code rewritten by UN IG L—JavaScript WebGL APIs are hooked, the vertex
shader is rewritten as JavaScript code, and the fragment shader is still as fragment shader with floating-point operations redefined.)
We now show the source code of this rendering task of Fig-
ure 2in Figure 3(Left). The source code contains three parts:
JavaScript, Vertex Shader and Fragment Shader. First, the
JavaScript code prepares data, such as attributes, uniforms,
and texture, for both vertex and fragment shaders. Lines 4–13
(Left, JavaScript) show an example of passing attributes to
the vertex shader. Next, Lines 14–16 (Left, JavaScript) show
another example of passing uniforms to the vertex shader.
Second, the vertex shader code accepts attribute and uniform
values from the JavaScript and then performs operations, i.e.,
Lines 9–11 (Left, Vertex Shader), on each attribute in a paral-
lel manner. The outputs of the vertex shader to the fragment
shader are a special variable,
gl_position
, which indicates
the transformed vertices, and multiple varyings. Third, the
fragment shader accepts outputs, i.e., vertices and varying,
from the vertex shader, performs rasterization and interpola-
tion, and then runs the code (i.e., Line 5–6, Left, Fragment
Shader).
Now, let us describe the floating-point related operations
that cause the rendering result difference. First, the vertices,
i.e.,
gl_position
, and the varyings, i.e.,
vTextureCoord
and
vLightWeighting
, are passed and interpolated between the
vertex and the fragment shader. Such interpolation and ac-
companied rasterization involve floating-point operations and
may cause difference. Second, WebGL functions, such as
dot
at Line 11 (Left, Vertex Shader) and
texture2D
at Line 5 (Left,
Fragment Shader), include floating-point operations and may
cause difference. Lastly, floating-point operations, such as
Lines 9–10 (Left, Vertex Shader) and Line 6 (Left, Fragment
Shader), may cause difference.
Next, we use Figure 3(Right) to illustrate how UN IGL
rewrites the original code and prevents such differences
caused by floating-point operations. First, UN I GL will hook
all the JavaScript APIs, such as
bindBu f f er
and
bu f f erData
,
to obtain vertices and indices information and associate them
with attributes and uniforms in the vertex shader. Then,
UNI GL rewrites the original vertex shader by replacing
USENIX Association 28th USENIX Security Symposium 1649
Vertex
Shader
(1)
Hooking
JS APIs
Attributes, indices,
and uniforms
(2.i) Rewriting JS version of
vertex shader (3) Execution
(2.ii) Selection
Vertices and varyings
(5) Interpolation
& Rasterization
Texture and
uniforms (2.iii)
Processing
Fragment
Shader (2.iv) Rewriting
(7) Execution as fragment shader
Interpolated
varyings and
fragments
Rewritten
fragment
shader
(6) Fetching
previous
drawing
Input as
texture
Visual rendering results
(4) Preparation
Figure 4: Overall Architecture of UN IGL (Steps 1–4 are executed as
JavaScript, and Steps 5–7 as a fragment shader in a GLSL program).
floating-point operations like
dot
with JavaScript functions
like
UniGLDot
, and executes it as JavaScript at Line 9–15
(Right, JavaScript). Second, UN IGL collects the execution
results from JavaScript-based vertex shader (Lines 16–17,
Right, JavaScript) and then feeds them into a rewritten frag-
ment shader as uniforms (Line 2–4, Right, Fragment Shader).
Third, UN IG L rewrites the original fragment shader and exe-
cute it with customized rasterization and interpolation. The
rasterization process at Lines 7–8 (Right, Fragment Shader)
goes through all the triangles for each pixel on the canvas
and determines whether a given pixel lies inside a triangle.
If yes, UN I GL calculates the z-buffer of the given pixel for
the triangle, decides whether the triangle is in the front and
needs to be rendered, and also calculates pixel values based
on alpha. Then, the interpolation process (Lines 9–10, Right,
Fragment Shader) interpolates varyings based on vertices and
attributes passed from JavaScript as uniforms. Lastly, U NIGL
executes a rewritten fragment shader at Lines 12–13.
3 Design
We present the design of UNI GL in this section.
3.1 System Architecture
In this subsection, we show and describe the overall architec-
ture of UN I GL. The main function of UNI GL is encapsulated
as JavaScript files executed directly in the website runtime
context. The add-on part is a thin layer used to inject UN IGL
into the runtime context of the target website with WebGL
tasks. That is, the purpose of the add-on is to ensure the in-
jected UN IG L JavaScript code is executed before any website
code. Once the injected scripts are running, the add-on code
is disposable. We make this design choice so that UN IGL can
be easily transferred between browsers.
Once the main part of UN IG L is injected into the target
website, UN IG L performs seven detailed steps to render a
WebGL task on a canvas as shown in Figure 4. First, U NIGL
needs to perform some preparation tasks outside the three
stages in Figure 1. In Step (1), UN IGL hooks WebGL re-
lated JavaScript APIs to obtain four types of information: (i)
vertex shader (via
shaderSource
API), (ii) inputs to vertex
shader, such as attributes, indices and uniforms (via APIs,
such as
bu f f erData
and
bindBu f f er
), (iii) fragment shader
(via
shaderSource
API), and (iv) inputs to fragment shader,
such as texture and uniforms (via APIs, such as
texImage2D
and
texParameteri
). Then, in Step (2), UNI GL processes all
the information obtained in Step (1). Particularly, UNIGL
rewrites both vertex and fragment shaders in Step (2.i) and
(2.iv), and extracts and prepares inputs in Step (2.ii) and
(2.iii). For example, UN IG L reads indices and attributes, as-
sociates each attribute buffer with corresponding attribute
variable in the vertex shader, and then prepares data based
on the drawing mode (e.g.,
drawE lements
vs.
drawArray
,
and
gl.POI NT S
vs.
gl.LINES
vs.
gl.T RI ANGLE S
). Simi-
larly, UNIGL also extracts texture information, such as im-
age width and height, and texture mapping algorithm (e.g.,
GL_LIN EAR vs. GL_N EARE ST ).
After that, in Step (3), UNI GL executes the rewritten ver-
tex shader and generates outputs, i.e., vertices and varyings,
which also belongs to Stage 1 in Figure 1. Next, in Step (4),
UNI GL prepares inputs to the fragment shader by processing
the outputs in Step (3), i.e., Stage 2 in Figure 1. Specifically,
UNI GL performs backface culling on the triangles and it-
eratively divides the visible triangles by half so that each
rendering task only contains uniforms within the limit en-
forced by WebGL. Then, in Step (5), UNI GL loops through
all the pixels on canvas and determines whether each pixel
falls inside the triangles or on the lines depending on the
drawing mode. If yes, UN IGL interpolates all the varyings
based on the given pixel and vertices. If no, UNI GL fetches
previous drawing results from a special texture and uses the
pixel color in Step (6). Lastly, UN I GL executes the rewritten
fragment shader to calculates the pixel color in Step (7), i.e.,
performing Stage 3 in Figure 1.
3.2 Floating-point Operation Simulation
In this subsection, we present how to simulate floating-point
operations using integers, i.e., the integer simulation method
in Figure 1for fragment shader. Such method is used in both
Stage 2: Rasterization&Interpolation and Stage 3: Fragment
Rendering, i.e., Step (5) and (7) in Figure 4.
3.2.1 Floating-point Representation and Operation
UNI GL adopts two integers, i.e., one numerator (
p
) and the
other denominator (
q
), to represent an arbitrary floating-point
value in the fragment shader. In this paper, we also refer the
denominator as a base, because UN I GL can easily perform
operations, such as addition and subtraction, on two values
with the same base. Note that such representation also aligns
well with the physical meaning of WebGL floating-point val-
ues. Take coordinates for example. The original vertices or
texture coordinates are specified as an integer in terms of
the canvas or texture size, which can serve as the numerator,
and then the canvas or texture size can serve as the base. For
1650 28th USENIX Security Symposium USENIX Association
another example, 255 will be the base for all the color values,
because all RGB colors are within the range of 255.
One important operation for UN I GL’s floating-point num-
bers is to change base for a given number. Such operation
will be used when UNI GL converts simulated floating-point
values to real ones represented by WebGL, such as the spec-
ification of texture coordinates at Line 12 and color values
at Line 13 of Figure 3(Right, Fragment Shader). The choice
of a base depends on the underlying physical meaning of the
WebGL functions, e.g., UNI GL adopts 255 as the base for
gl_FragColor.
We now explain why the base representation can make
uniform rendering results across browsers. Specifically, al-
though a color value is represented as a float value internally
in WebGL, WebGL has to convert it back to an integer when
rendering the color on canvas. That is, if WebGL accepts a
value
p
in between
1/255
and
2/255
, it may render
p
as
1
or
2
depending on the underlying conversion algorithm. At
contrast, if WebGL accepts a value as either
1/255
or
2/255
,
the ambiguity disappears and the results are uniform across
browsers. In sum, UN IG L adopts different bases according to
the physical meaning when UN I GL passes the floating-point
value back to WebGL.
Next, we describe how to change base for a given num-
ber especially when it does not have the required base. In-
tuitively, we can multiply the value with the new base and
divide the product with the old base. However, such intuitive
approach does not work, because the division of one inte-
ger over another involves floating-point operations in some
WebGL implementations. That is, the division result differs
from one browser to another. Therefore, after obtaining the
quotient, UN IG L needs to search within a range (i.e.,
±1
) of
the quotient for the real quotient. Other than the base change
operation, UN IG L also supports basic arithmetic operations,
which follow fraction operations. Due to simplicity, we skip
details here. One thing worth noting is that UN IGL needs to
avoid result overflows—if so, UNI GL needs to increase the
base to accommodate a larger value.
In the next two subsections, we show how to use such base
representation of floating-point values and replace existing
ones in two important types of WebGL functions.
3.2.2 Floating-point Operations in Rasterization and
Interpolation
Rasterization and interpolation are automatically performed
in between the vertex and fragment shaders. Specifically, for
all pixels on the canvas and all triangles, rasterization needs
to decide whether the given pixel is inside the triangle and, if
so, calculate the z-buffer. Note that both procedures involve
floating-point values and operation, which need to adopt the
base representation during calculation. Then, the interpolation
calculates weights for three vertices at a given triangle and
then outputs the interpolated varying, i.e., a weighted sum
of the attribute values at three vertices. All the weights and
calculations are in the aforementioned base representation.
Another thing here, being different from normal rasteriza-
tion and interpolation, is that UNI GL divides the entire, rect-
angle canvas into two triangles with four vertices as shown in
Figure 5a instead of using the original vertices. The usage of
such vertices is necessary to design a GLSL-version of raster-
ization, because the fragment shader will only expose a pixel
to the GLSL program when the pixel is inside one triangle.
Therefore, if we adopt the original vertices as the inputs to the
fragment shader, some pixels, especially when they are on the
edge, may be considered as inside a triangle by one browser
but outside by another. The division shown in Figure 5a will
consider all pixels on the canvas as being within either of
these two triangles on any browser. This will give UNI GL the
capability to go through all the pixelsand decide whether a
pixel, such as
(x,y)
in Figure 5a, is inside triangles consisted
of the original vertices, i.e., (x1,y1)...(x4,y4).
3.2.3 Floating-point Operations in Fragment Shader
The fragment shader uses many float-point related functions,
such as “texture2D”, “normalize” and “sqrt”. In this subsec-
tion, we use texture mapping, i.e., “texture2D”, as an example
to show the procedure of adopting integer simulation and
replacing floating-point operations.
Texture mapping, in its normal definition, is a method of
applying a two-dimensional surface upon a three-dimensional
graphics model. There are many variations of texture mapping
algorithms, such as linear interpolation (i.e., GL_LINEAR)
and nearest neighbor (GL_NEAREST). Sometimes, mipmaps
are also generated to process the texture before mapping. In
this paper, we use linear interpolation as a proof of concept al-
gorithm to show how to redefine texture mapping in UNI GL.
One of the major tasks in redefining texture mapping is to
pass texture data from JavaScript to the fragment shader. The
naïve method is to utilize “uniforms” just as vertices. How-
ever, because there exists a limit for the number of “uniform”
variables and texture cannot be divided in multiple draws, we
have to rely on existing texture information stored in WebGL.
Here is how UN IG L redefines a linear interpolation algo-
rithm for texture mapping. UN IGL stores texture information
using the default WebGL method with a nearest neighbor
algorithm—therefore, WebGL will just directly fetch color
values from the texture instead of performing any computa-
tion. When UN IGL has a texture coordinate, say, for example,
1/base
in Figure 5c, UN IG L will first change the base to the
size of the texture. Note that we use a square-shape texture as
an example and a rectangle-shape will be similar.
Then, UN IG L fetches the colors, i.e.,
c1...c4
, of four texture
points in Figure 5c, which locate around the target texture
coordinate. Because UN I GL uses the texture size as the new
base, the ambiguity among browsers will disappear. Next,
UNI GL calculates two weights, i.e.,
w1
and
w2
, based on the
distance between the target texture coordinate and four texture
USENIX Association 28th USENIX Security Symposium 1651
Canvas
(x1, y1)
(x2, y2)
(x3, y3)(x4, y4)
(x, y)
(a) Rasterization
Canvas
(1)
(2)
(3)
(b) Canvas Division
1/size 2/size0
1/size
2/size
1/base
size/size
size/size
w1
w2
c1c2
c3c4
(1) Change
base to “size”
(2) Calc weights
(3) Calc color
(c) Texture Mapping
Figure 5: Explanation of Different UN I GL Operations. In subfigure (a), during rasterization, UNI GL needs to determine the triangle that each
point belongs to. Specifically, Point (
x
,
y
) is inside the triangle consisting of vertices (
x1
,
y1
), (
x2
,
y2
), and (
x3
,
y3
), but outside the other triangle
consisting of vertices (
x2
,
y2
), (
x3
,
y3
), and (
x4
,
y4
). Therefore, UN IGL will interpolate the values of all the varyings at (
x
,
y
) based on (
x1
,
y1
),
(
x2
,
y2
), and (
x3
,
y3
). In subfigure (b), UN IG L first divides the entire canvas into two parts, i.e, left and right, and then top and bottom. After
that, because the number of vertices in some divided parts is small enough to be handled by WebGL, UN IG L will not further divide such parts,
like top right and top left. If the number of vertices in a part is still larger than the minimum number of allowed uniform variables, UNI GL will
further divide the canvas, like cut (3). Subfigure (c) adopts a square texture as an example to show how the linear interpolation algorithm of
texture mapping works in UN IGL. UNI GL calculates an interpolated color value for a given point based on four color values around this point.
Table 1: WebGL Data and Corresponding JavaScript APIs that Ac-
cept such Data
Intercepted WebGL Data JavaScript APIs
GLSL Program createProgram, attachShader
Shader attachShader, getShaderSource
Buffer bufferData
Attribute vertexAttribPointer
Attribute Location getAttribLocation
Uniform uniform*** (e.g., uniform1f)
Uniform Location getUniformLocation
fetched points—these two weights can be in any base. Lastly,
UNI GL calculates the color for the target texture coordinate
using these two weights, i.e.,
color =w2w2c1+w1w2c2+
w2w1c3+w1w1c4.
3.3 Rendering Preparation
In this subsection, we introduce how to prepare inputs to
both rewritten vertex and fragment shaders, i.e., Steps (1),
(4), and (6). These steps do not have direct involvement with
floating-point values, but are essential in preparing the vertex
and fragment shaders in UN I GL.
JavaScript Hooking and Data Extraction.
UNI GL hooks
WebGL-related JavaScript APIs in Step (1) of Figure 4.
Specifically, UNIGL utilizes the dynamic feature of
JavaScript to redefine such JavaScript APIs, intercepts all
arguments, i.e., parameters to WebGL, processes the argu-
ments, and stores them in an internal data structure of UNIGL.
Table 1shows a list of WebGL data and corresponding
JavaScript APIs. Such data can be roughly divided into two
major categories: programs and inputs. “GLSL program” and
“shader data” in Table 1are intercepted by UNI GL for rewrit-
ing purpose. All others, such as “attribute” and “uniform”,
are inputs to the program—UN I GL intercepts them and then
feeds them to the rewritten programs. Both “attribute” and
“uniform” refer to the data, e.g., colors and vertices, and “at-
tribute location” and “uniform location” are the corresponding
variables defined in the shaders.
Backface Culling.
UNI GL adopts backface culling [11] in
Step (4) of Figure 4to determine whether a polygon, such as a
triangle, of a graphical object is visible. Specifically, UNI GL
calculates the normal vector of all the triangles and filters
these triangles of which the normal vector does not face the
camera.
Rendering Task Division.
Rendering task division, part of
Step (4), is designed specifically in UNI GL to overcome the
limit of the uniform variable numbers in fragment shader.
Figure 5b shows an illustration of such division. UN IGL
first divides the canvas vertically by half, e.g., division (1)
in Figure 5b, and then horizontally, e.g., division (2). Such
vertical or horizontal division will be performed alternatively
in each iteration on a small region until the number of vertices
in that region is smaller than the limit enforced by WebGL
implemented in a specific browser. Note that if a triangle
is partially inside a region, e.g., the right corner region in
Figure 5b, UN IG L will count all three vertices towards the
limit. The reason is that all three vertices are required to
determine whether a given pixel lies inside a triangle.
Reading Previous Draw Results.
In this part, we describe
how UNI GL handles multiple draws in Step (6). For example,
a WebGL program may first draw a triangle by calling one
GLSL program and then a rectangle by calling another. In
such multiple draws, the rendering results are treated as a
background in the latest draw. Because UN I GL goes through
all the pixels in the fragment shader each time, UN IGL needs
to read previous draw results. Specifically, UNI GL relies on
the readPixels API to obtain the canvas contents, constructs a
texture based on the contents and then passes the texture to the
fragment shader. Then, in the fragment shader, UNIGL first
reads the color value from the texture, and assigns the color
to
gl_FragColor
. Later on, if the current drawing renders a
1652 28th USENIX Security Symposium USENIX Association
1attribute vec2 vertPosition;
2void ma in ( ) {
3gl_Position =vec4( v er t Po s it i on , 0. 0 , 1 . 0) ;
4gl_PointSize = 1.0;
5}
Figure 6: Dummy Vertex Shader (The vertex shader performs a self-
mapping with a z-value as 0.0 and a w-value as 1.0. The point size
is also set to be 1.0.)
color on this pixel, the assigned color will be overwritten;
otherwise, the assigned color is treated as the background.
3.4 Rewriting and Rendering
In this subsection, we describe UN IGL’s rewriting and ren-
dering process, i.e., Step (2). In both Steps (2.i) and (2.iv),
UNI GL preprocesses the GLSL program, i.e., replacing pre-
processor directives with a hash symbol at the beginning, and
then parses the processed program into Abstract Syntax Tree
(AST). We then discuss how to rewrite vertex and fragment
shaders separately.
Vertex Shader. UN IGL traverses through the AST, redefines
corresponding node, e.g., replacing the operator plus with
a function UniGL_Plus, and then converts the AST back to
either JavaScript or GLSL code. All the type information is
kept the same because UN IGL has redefined all the types
in JavaScript to be the same as in GLSL. Note that one
additional step is that UN I GL needs to divide the
w
value
of
gl_Position
from the
x
,
y
and
z
values so that UN IGL
can switch the rendering results from an orthographic view
to a perspective view. This step was performed implicitly
in the original WebGL, and UNI GL needs to do so as well.
Fragment Shader. UNI GL traverses through the AST and
redefines the following three types of nodes: (i) operators,
(ii) constant float number, and (iii) type information related
to floating point values. First, UN IG L redefines all the ex-
isting operations, such as multiply, with the corresponding
GLSL function, such as UniGL_Multiply. Second, UNI GL
converts all the constant floating point values, e.g., 0.32 as
an alpha value, to our base representation, e.g., 32 as the
value and 100 as the base for all alphas. Lastly, UNI GL
need to convert all the types related to floating point values,
such as float and vec3, to the corresponding integer type,
such as int and ivec3.
Note that WebGL requires that all GLSL programs have
both vertex and fragment shaders. Therefore, UN IGL exe-
cutes a dummy vertex shader as shown in Figure 6. The
dummy vertex shader needs to set gl_PointSize, because the
default value also differs on different OSes, e.g., Mac vs. Win-
dows.
3.5 Execution of JavaScript Vertex Shader and Corre-
sponding Floating-point Operations
In this subsection, we describe the execution of JavaScript
vertex shader in Step (3). All the floating-point operations in
the vertex shader are thus executed on CPUs. We adopt five
runtime optimizations to speed up the execution as shown
below.
Multiple Web Workers. Once one frame comes in, UNI GL
puts the vertex rendering tasks of the frame into a queue.
Then, multiple workers keep fetching the tasks from the
queue, and run them in parallel.
Caching. UN IG L adopts a caching mechanism for matrix
operations, e.g.,
UniGLAdd
and
UniGLMulti pl y
at Lines
12 and 14 of Figure 3(Right, JavaScript), in Step (3). That
is, UN IG L will cache the calculation results of a matrix
operation, e.g., the multiplication of two matrices. If the
rewritten vertex shader asks for the results of an operation
upon the same matrices, UN I GL will directly return the
result directly instead of calculating it again.
Typed, fixed-size Array. UNI GL adopts typed arrays, such
as Float32Array, instead of the normal JavaScript array
to store data. The reason is that typed array are stored
in a contiguous memory region can fast accessed by the
browser. In addition, UNI GL needs to specify the length to
avoid array resizing. The reason is that array resizing may
involve additional memory allocation and data copy. Note
that we also need to avoid using some heavy JavaScript
array operations, such as Array.map().
Code and Data Separation. UN I GL separates the code and
the data for the rewritten shader. That is, the code will be
prepared in the hooked
useProgram
API, which does not
have an influence on the runtime performance, and JIT-ed
for performance speed-up. Note that UNI GL triggers the
JIT engine by executing the code once with initial data.
Then, further data will be prepared in the draw stage.
WebAssembly. UNIGL executes some heavyweight opera-
tions, such as matrix multiplication, using native code like
WebAssembly.
4 Implementation
We implemented a prototype of the core function of UNI GL
with around 8,500 lines of JavaScript code, around 650 lines
of GLSL code, and around 3,000 lines of code for auxil-
iary components such as WebAssembly and add-on. The
rewriting component of UN IG L is modified from one open-
source GitHub repository (namely,
https://github.com/
stackgl/glsl-transpiler
). Other than this repository, we
also use several other libraries, such as glMatrix.
UNI GL is open-source, available at repositories under this
GitHub user (
https://www.github.com/unigl/
). We also
provide a demo at this url (
http://test.unigl.org/
), a
modified version of Cao et al. [19]’s fingerprinting web-
sites, to demonstrate that UNI GL can prevent state-of-the-art
WebGL-based browser fingerprinting. All rendering results
are the same in this new, UNIGL rewritten version.
USENIX Association 28th USENIX Security Symposium 1653
5 Evaluation
We evaluate UNIGL prototype on three metrics: anti-
fingerprinting capability, performance, compatibility, and
CPU energy consumption.
5.1 Anti-fingerprinting Capability
We adopt a state-of-the-art WebGL-based browser finger-
printing work [19] as our benchmark to evaluate the anti-
fingerprinting capability and performance of UNI GL. Specif-
ically, the benchmark contains 17 different WebGL render-
ing tasks including plain WebGL tasks and these relying on
three.js, a WebGL library, to explore various WebGL features,
such as varyings, light and texture. The first column of Table 2
shows the names of all the rendering tasks and the second
column a rendering result example on a dell desktop installed
with Windows 10.
We evaluate UNIGL by asking Amazon Mechanical Turks
to visit our website—including a demo site of UNI GL to-
gether with the original fingerprinting site from Cao et al.—
using Firefox, Chrome and Safari. In total, we have collected
656 fingerprints from these three types of browsers. Among
all the 656 fingerprints, UN I GL only renders one unique fin-
gerprint for each rendering task across different browsers.
This unique fingerprint, being visually the same to the origi-
nal rendering result, is shown in the “Example” column under
UNI GL of Table 2. As a comparison, we also show the num-
ber of unique fingerprints of Cao et al. in the “# Unique
Results” column under “Original” of Table 2—this confirms
Cao et al.’s findings that WebGL is a high-entropy vector for
browser fingerprinting. We also list some more statistics in
Appendix A.
In addition to the Amazon Mechanical Turk experiment,
we also perform a local experiment that enumerates a large
varieties of factors across the graphics layers. Specifically,
we test UN IG L with the following different settings: OS
(Windows 7, 8, 10, iOS 10.14.1, and Ubuntu 18.04), graph-
ics card (Nvidia Geforce GTX 1070, Intel Iris plus Graph-
ics 640, AMD Radeon R9 M390, and AMD Radeon HD
6770m), drivers (Nvidia, Intel, and AMD drivers), screen res-
olution (all these provided by the OS, such as 2560x1440 and
1920x1080), and DPI scaling (100%, 125%, 150%, 175%,
200%, and 225%). UNI GL only produces one unique result,
which is the same as the Amazon Mechanical Turk experi-
ment.
5.2 Performance
We test the performance of UNIGL by using both micro-
and macro-benchmarks. All the experiments, except for the
crowdsourced results in Table 2, are performed on an iMac –
the machine has an Intel Core i5, 3.2 Hz, 4-core CPU, 24 GB
memory, and an AMD Radeon R9 M390 GPU with 2048 MB
VRAM.
Figure 7: Micro-benchmark of Vertex Shader.
Figure 8: Micro-benchmark of Fragment Shader (all the operations
in WebGL are using floating-point values; these in UN IGL adopts
integer simulation).
5.2.1 Micro-benchmark
In the micro-benchmark, we test several atomic WebGL op-
erations and compare the original version with the one de-
fined in UN I GL. Specifically, we run each operation in either
fragment or vertex shader for 2,000 times and calculate the
interval between two draws. Each experiment is performed
20 times to obtain a standard deviation. Note that we adopt
a simple model, i.e., a cube, in the micro-benchmark experi-
ment. When we are testing one shader, the other shader will
contain a one-line, dummy statement, i.e., the assignment of
either gl_Position or gl_FragColor.
Figure 7shows the micro-benchmark performance of the
vertex shader. The vertex shader of UN IGL outperforms the
one written in GLSL in some aspects, such as these operations
that have integers involved. The reason is that CPU is well
designed for integer operation when compared with GPU. On
the contrary, the original shader written in GLSL is better at
matrix operations, because such operations can be performed
in parallel using shading languages.
1654 28th USENIX Security Symposium USENIX Association
Table 2: Macro-benchmark WebGL Tasks [19] and Corresponding Rendering Results with UNI GL ( “# Vertices” means the number of vertices
in the model, which are two per line segment in a 2D model and three per triangle in a 3D model. “Example” is one rendering example collected
from users. In “# Unique Results” columns, X/Y means the number of unique fingerprints collected from all the users out of the total number
of fingerprints. “FPS” means frames per second—which is around 60 Hz due to the screen refresh rate. )
WebGL Task # Vertices
Original UNI GL
Example # Unique Results FPS Example # Unique Results FPS
Chrome Firefox Safari
Curve and Line 262 74/496 23/108 18/52 60.32±0.38 1/656 61.77±0.54
Curve and Line (AA) 262 83/496 32/108 21/52 60.78±0.54 1/656 61.83±0.97
Cube 36 4/496 2/108 5/52 60.67±0.49 1/656 62.50±0.80
Cube (AA) 36 55/496 20/108 23/52 60.46±0.15 1/656 62.39±1.36
Cube (Camera) 36 56/496 18/108 7/52 60.02±0.22 1/656 61.75±1.32
Monkey head (Texture) 2,904 5/496 18/108 2/52 60.14±1.17 1/656 61.88±1.61
Monkey head (Light) 2,904 36/496 11/108 15/52 59.95±0.60 1/656 61.07±1.02
Two models (Light) 2,988 44/496 18/108 14/52 60.02±1.19 1/656 61.90±0.97
Two models (Complex light) 2,988 52/496 6/108 20/52 60.18±0.40 1/656 60.02±1.13
Two models (Texture) 2,988 79/496 31/108 21/52 60.31±0.54 1/656 62.33±1.22
Two models (Transparency) 2,988 87/496 25/108 22/52 59.97±1.13 1/656 60.13±1.76
Two models (Tex&Light) 2,988 38/496 14/108 11/52 60.04±0.31 1/656 59.74±0.75
Thousands of rings (three.js) 5,376 53/496 25/108 15/52 60.52±0.53 1/656 57.47±1.87
Clipping plane (three.js) 36 44/496 14/108 19/52 59.98±0.44 1/656 59.67±1.29
Bubble (three.js) 974 49/496 17/108 22/52 60.20±1.52 1/656 60.07±1.43
Compressed Texture (three.js) 98 72/496 21/108 19/52 60.04±0.56 1/656 59.59±0.73
Shadow (three.js) 156 53/496 17/108 19/52 59.84±0.35 1/656 60.12±1.02
Combined fingerprint 123/496 41/108 26/52 1/656
Figure 8shows the micro-benchmark performance of the
fragment shader. Similar to the vertex shader, while UNIGL
is slower than the original WebGL in some cases, such as
“texture2D” as UN IGL redefines the function, it is worth not-
ing that UN IGL is faster than the original WebGL in many
other cases, such as “pow” and “multiplication”. The reason is
that an integer operation is indeed sometimes cheaper than a
floating-point one. For example, it takes less time to multiply
two integers than two floating-point values. Note that we are
referring to integer operations that exist in the original vertex
shader during this discussion. Floating-point values are still
represented as floats in the vertex shader of UN IG L.
5.2.2 Macro-benchmark
In this subsection, we use the WebGL tasks provided by Cao
et al. [19] as our macro-benchmark to measure the FPS of
these rendered by UNI GL. The column “FPS” under UNI GL
of Table 2shows the FPS of each rendering task and we also
show the FPS without UNIGL, i.e., these rendered directly
by WebGL in the same table. The performance of UNI GL
can satisfy the required screen refresh rate, i.e., 60 Hz. The
FPS of UN I GL for all the tasks are similar to the original one
rendered by WebGL alone.
There are two things worth noting. First, the FPS of UNIGL
is even sometimes a little bit higher than the one of We-
bGL. The reason is that when the model is simple, our
highly optimized vertex shader with the help of WebAssem-
bly is faster than the original one. Second, the FPSes of both
UNI GL and WebGL are a little bit higher than 60 Hz in
some tasks, because modern browsers reduce the precision of
per f ormance.now
to prevent timing attacks [7], which may
USENIX Association 28th USENIX Security Symposium 1655
Table 3: Overhead Breakdown for the “Two models (Complex light)”
Task
Procedure Overhead
Data Preparation 0.08±0.07ms
Backface Culling 2.16±0.06ms
Vertex Shader 2.26±0.18ms
Rendering Task Division 5.34±0.73ms
Fragment Shader 6.51±0.85ms
Total 16.35±0.74ms
Table 4: Vertex Shader Optimization (all numbers are averaged from
10 experiments and rounded to ms)
Unoptimized Vertex Shader 110 ms
Result Caching of Matrix Operation -24 ms
Typed, Fixed-size Array for Data -22 ms
Code and Data Separation -39 ms
Parallelization -19 ms
WebAssembly -4 ms
Optimized Vertex Shader 2 ms
lead to a small measurement error. Such measurement errors
are consistent across UN I GL and WebGL.
We further look at one specific task, i.e., “Two mod-
els (Complex light)”, and analyze the overhead brought by
UNI GL. Table 3shows the overhead breakdown by differ-
ent procedures of UNI GL. The rendering task division and
fragment shader are the most time-consuming procedures,
i.e., each taking one third of the entire overhead. Both data
preparation and backface culling are lightweight, taking up a
small portion of the overhead.
We then look at how our optimization reduces overhead
of UN IG L, especially the vertex shader, using the same task.
Specifically, we evaluate five optimizations and their impact
on the performance in Table 4. The unoptimized vertex shader
in JavaScript takes 110ms and each optimization reduces the
overhead to some degree. Code and data separation is the most
effective one, i.e., about 40ms reduction, because JIT engine
will execute code natively rather than on an interpreter. Then,
both caching and typed, fixed-size array speed up the shader
by reducing around 20ms, and parallelization also reduces the
overhead by around 19ms. Lastly, if we apply WebAssembly
optimization, the overhead can also be reduced by 4 ms.
5.3 Compatibility
In this section, we evaluate the compatibility of UNIGL with
existing WebGL applications. Specifically, in addition to the
WebGL tasks from Cao et al. [19], we run UNI GL using two
other real-world WebGL applications shown below:
Zygote Body. Zygote Body (
https://www.zygotebody.
com/
), formerly known as Google Body, is created by Zy-
gote Media Group to renders a manipulable 3D model of
human body from outside, such as skins, muscle tissues
and hairs, to inside, such as blood vessels and skeletons.
(a) Zygote Body (b) Google I/O Application
Figure 9: Two Screenshots of Zygote (Google) Body and Google
I/O Application Rendered by UN IGL
Google I/O 2011 Applications. Google has presented
WebGL applications (https://webglsamples.org/google-
io/2011/index.html) at its I/O event in 2011 to show the
new technique and performance.
Our evaluation result shows that UNIGL is compatible
with both applications. First, we run UNI GL with Zygote
Body—the human body is rendered correctly with no visual
difference. We can also manipulate it by looking at different
layers, such as skeleton and muscle. Second, we run UN IGL
with Google I/O applications—all the objects are shown and
displayed correctly with the right texture, moving on the can-
vas the same as ones with WebGL directly. Two screenshots
of both applications are also shown in Figure 9: Figure 9a
shows the front page of Zygote Body, a default rendering
of a human, and Figure 9b a screenshot of one Google I/O
application after it runs for two seconds.
5.4 CPU Energy Consumption
In this section, we evaluate the CPU package power of our
macro-benchmark. Specifically, we use CPUID’s HWMon-
itor [3], a program that monitors PC systems’ main health
sensors, to calculate the CPU package power consumption
for each macro-benchmark task. Note that our experiment is
performed on a Dell Desktop because HWMonitor is only
available on PC systems.
Figure 10 shows our evaluation results, i.e., CPU package
power consumption when each macro-benchmark task is ren-
dered by WebGL (hardware rendering), WebGL (software
rendering), and UN I GL. The power consumption for WebGL
(hardware rendering) is the smallest for all the tasks because
hardware rendering relies on GPU to perform computation.
UNI GL is the second, because UNI GL relies on CPU for ren-
dering vertex shader, but GPU for fragment shader. WebGL
(software rendering) is the highest as all the rendering tasks
are performed on CPU.
It is also worth noting that CPU package powers for “thou-
sands of rings” and “clipping plane” are the highest compared
with other tasks. The reason is that the vertex shader for both
tasks are computationally heavy. Take “thousands of rings”
for example. The position and shapes for all the rings are
calculated in the vertex shader.
1656 28th USENIX Security Symposium USENIX Association
Figure 10: CPU Package Power Comparison among WebGL (hardware rendering), WebGL (software rendering), and UN IG L. (Note that all
other WebGLs mentioned in the paper except for this figure and corresponding texts refer to the default hardware rendering.)
6 Discussion
We discuss several issues regarding UNI GL in this section.
Timing side-channel attacks. Timing information, such
as the rendering speed of WebGL tasks, may also be used
for fingerprinting. For example, Naghibijouybari et al. [43]
shows that timing side channels exist in GPU, e.g., WebGL
rendering tasks. Similarly, the execution time of floating-
point operations can also be used as a timing side chan-
nels [29,51]. Many existing works, such as Deterministic
Browser [18], JavaScript Zero [54], and CTFP [14], are pro-
posed to defend against such timing channels, and therefore
we would consider such timing-based fingerprinting out of
scope of the paper.
Self-modifying code (i.e., an strong adversary aware of
UNI GL). There are three techniques used to prevent self-
modifying code that is aware of the existence of UNI GL
from tampering the UNI GL code and logics. First, UNI GL
adopts anonymous closure to encapsulate all the core code
of UN IG L from access by any potentially malicious web-
site JavaScript. Specifically, anonymous closure makes sure
that all the private variables and original WebGL func-
tions, such as drawElements, are securely protected. Sec-
ond, UN IG L obtains all the system object, such as “unde-
fined”, to avoid tampering from an adversary. Lastly, the
add-on code injects the main function of UN IGL as the first
script to execute before any other website JavaScript. It is
worth noting that we are aware that there exists an active
Chrome bug [4] at the time when we write the paper, which
is about “document_start” hook on child frames. We be-
lieve that this bug should be fixed to follow the specification
of Chrome extension.
WebGL Vulnerability. WebGL may expose some low-level
vulnerabilities in device drivers to web applications [62].
As discussed in Milkomeda [62], WebGL has already im-
ported security checks to prevent an attacker exploiting
such vulnerabilities.
Fingerprinting via WebGL meta-information. We realize
that not only the rendering behaviors of WebGL tasks but
also the meta-information of WebGL engine and implemen-
tation can be used for fingerprinting. For example, as shown
by this website (
https://browserleaks.com/webgl
),
different WebGL meta-information, such as vendor, ren-
derer, and shader parameters, can all be used as part of
browser fingerprinting.
We would like to point out that such fingerprinting relying
on WebGL meta-information is relatively easy to prevent as
shown by Tor Browser’s in uniformization of the reported
values of such meta-information. Specifically, Tor Browser
changes and makes uniform the return values of WebGL
meta-information functions, such as getParameter(), get-
SupportedExtensions(), and getExtension(). Therefore, we
encourage one to rely on Tor Browser for prevention of
such fingerprinting.
Floating-point Value Precision. We now discuss the pre-
cision of floating-point values used in UNI GL. Our inte-
ger simulation of floating-point values can meet the needs
of graphics tasks, because WebGL does not need a high-
precision definition of floating-point variables. Specifically,
the semantic meaning of many WebGL variables only re-
quires a relatively low-precision value. Take color values
for example: Each color value only ranges from 0 to 255
and thus a high-precision, 16-bit floating-point value will
not represent more colors. In fact, many WebGL implemen-
tation only support a mediump (10 bits) or lowp (8 bits) for
float variables.
Future WebGL-based fingerprinting. State-of-the-art We-
bGL fingerprinting is based on differences in floating-
point operations. We empirically verify this via carefully-
designed experiments following WebGL specifications in
Section 2.1.1 and our evaluation of UN IGL against Cao
et al.’s WebGL fingerprinting [19]. Future WebGL finger-
printing techniques and those that do not rely on WebGL
are out of scope of the paper.
Ethic concerns. We discussed with our Institutional Re-
view Board (IRB) about the ethics of the proposed research
and experiment, because we require a human to run our
experiment on their machines. The conclusion is that the
proposed research does not require IRB approval. The rea-
son is that although browser fingerprinting may be used to
collect private information, the fingerprint itself, just like
USENIX Association 28th USENIX Security Symposium 1657
cookies, is just an identifier, which does not contain any
private information. Our experiment only collects finger-
prints but not any private information associated with the
fingerprint.
7 Related Work
We discuss related work in this section.
Browser Fingerprinting.
Browser fingerprinting is a second-
generation web tracking that goes beyond cookies or super
cookies [30
33,35,53] to utilize inherent features inside web
browsers. For example, there are many works [12,13,20,
23,45,63] performing measurement works on browser fin-
gerprinting. Browser fingerprinting can rely on many fea-
tures. Laperdrix et al. [34], i.e., AmIUnique, is a comprehen-
sive study on 17 features of browser fingerprinting. Then,
Vastel et al. studied the dynamics of fingerprints [59], i.e.,
how browser fingerprints change over time, and the privacy
implication of browser fingerprint inconsistencies [60]. Re-
searchers also study specific features of browser fingerprint-
ing, such as fonts [23], AudioContext [20], and JavaScript
engine [40,42]. The defense target of the paper is WebGL-
based fingerprinting, which was first proposed by Mowery et
al. [41] and then thoroughly examined by Cao et al. [19].
Floating-point Timing Channel.
A floating-point timing
channel [29,51] of web browser refers to that the duration of
a floating-point operation can be used to break same-origin
policy. Other than floating-point timing channel, many other
timing channels [16,22,24,25,28,39,46,57,58,64,65] have
also been studied. As a comparison, the side channel studied
in the paper is caused by the different results of floating-point
operations, such as conversion from low resolution to high
resolution, but not the different duration of floating-point op-
erations. Therefore, we consider that floating-point timing
channels are out of scope of the paper, and one should refer
to existing works [18] for solutions.
Defense against Fingerprinting.
To the best of knowledge,
none of existing works can defend against WebGL-based
browser fingerprinting while still preserving its functionality.
The reason is that we believe we are the first to point out
floating-point operations are the root cause for WebGL-based
browser fingerprinting. U NIGL is also the first system to
find out and then redefines such floating-point operations that
cause rendering discrepancies.
In the related work, Tor Browser [48], as discussed, is the
pioneer work in defending against browser fingerprinting,
but it disables WebGL for privacy. PriVaricator [44] adds
noises to browser fingerprinting, which can be defeated if the
adversary runs the fingerprinting multiple times. Similarly,
Multilogin Browser [5] also creates a virtual browser profile
with a random fingerprint. TrackingFree [47] only defends
against the first-generation web tracking, i.e., these based on
cookies or super cookies, but not browser fingerprinting.
Rewriting Technique.
In the past, both academia [21,27,38]
and industry [6,8] have adopted rewriting techniques in dif-
ferent scenarios. In academia, WebShield [38] and Browser-
Shield [52] rewrite webpages in a proxy to enable web defense
techniques. Erlingsson et al. [21] enforce cyber security poli-
cies by rewriting binaries. In industry, ShapeSecurity [8], a
commercial company, provide products to rewrite websites
and prevent bots and malware. Google’s PageSpeed Mod-
ule [6] also rewrites webpages to improve their performance.
As a comparison, there are unique challenges in rewriting
GLSL languages in UNI GL, because it contains two shaders
and many internal variables, such as varyings and uniforms.
Specifically, UNIGL not only redefines floating-point opera-
tions, but also implements rasterization and interpolation in
fragment shader so that corresponding floating-point opera-
tions in these two procedures can be made uniform.
Determinism.
Determinism is a technique used to defend
against side-channel attacks. For example, StopWatch [36,37],
Deterministic Browser [18], and DeterLand [61] adopt deter-
minism to defend against timing channels. Burias et al. [17]
design a deterministic information-flow control system to de-
fend against cache attacks and then Stefan et al. [56] prove
that such cache attacks are still possible given a reference
clock. Aviram et al. [15] use provider-enforced deterministic
execution to prevent timing channels within a shared cloud do-
main. As a comparison, UN I GL makes the execution results
the same but not the execution time across different browsers.
8 Conclusion
In this paper, we propose UNI GL, a novel system that rewrites
GLSL programs and renders them uniformly across different
browsers, thus preventing WebGL-based browser fingerprint-
ing. UN IG L redefines all the floating-point operations, either
explicitly written in the shader, or implicitly invoked by the
WebGL system.
We implemented an open-source prototype of UNI GL as a
browser add-on. Our evaluation shows that UNI GL can de-
fend against state-of-the-art WebGL-based fingerprinting, i.e.,
there exists only one rendering result when Amazon Mechan-
ical Turks visit our demo website from different browsers on
different machines. Our evaluation also shows that the perfor-
mance of UNI GL can satisfy the needs for the screen refresh
rate, i.e., the FPSes of graphics tasks rendered by UNI GL are
around 60 Hz.
In the future, we believe that browser vendors should inte-
grate UN IG L natively into browsers. If they choose to do so,
they can directly use integer simulation for all the components
including vertex shader, rasterization & interpolation engine,
and fragment shader, because the outputs from vertex shader,
though unavailable in the JavaScript-level, are accessible and
can be made uniform directly in native browser. Addition-
ally, a native implementation does not need the rendering task
division step in UN IG L because there will be no “uniform”
variable limit in the low-level.
1658 28th USENIX Security Symposium USENIX Association
Acknowledgment
We would like to thank our shepherd, Ben Stock, and anony-
mous reviewers for their helpful comments and feedback. This
work was supported in part by National Science Foundation
(NSF) grant CNS-18-12870 and an Amazon Research Award.
The views and conclusions contained herein are those of the
authors and should not be interpreted as necessarily represent-
ing the official policies or endorsements, either expressed or
implied, of NSF or Amazon.
References
[1] Canvas defender. https://multiloginapp.com/
canvasdefender-browser- extension/.
[2] Google maps meets webgl. https://www.youtube.com/watch?v=X3EO_
zehMkM.
[3] Hwmonitor—voltages, temperatures and fans speed monitoring. https://www.
cpuid.com/softwares/hwmonitor.html.
[4] Issue 793217: “document_start" hook on child frames should fire before control
is returned to the parent frame. https://bugs.chromium.org/p/chromium/
issues/detail?id=793217.
[5] Multilogin. https://multilogin.com/.
[6] Pagespeed module: open-source server modules that optimize your site automat-
ically. https://developers.google.com/speed/pagespeed/module/.
[7] Reduce resolution of performance.now to prevent timing attacks. https://bugs.
chromium.org/p/chromium/issues/detail?id=506723.
[8] Shape security. https://www.shapesecurity.com/.
[9] Trackoff privacy software. https://www.trackoff.com/en.
[10] Webgl games. https://www.crazygames.com/t/webgl.
[11] [wikipedia] back-face culling. https://en.wikipedia.org/wiki/
Back-face_culling.
[12] Gunes Acar, Christian Eubank, Steven Englehardt, Marc Juarez, Arvind
Narayanan, and Claudia Diaz. The web never forgets: Persistent tracking mech-
anisms in the wild. In Proceedings of the 2014 ACM SIGSAC Conference on
Computer and Communications Security, CCS ’14, pages 674–689, New York,
NY, USA, 2014. ACM.
[13] Gunes Acar, Marc Juarez, Nick Nikiforakis, Claudia Diaz, Seda Gürses, Frank
Piessens, and Bart Preneel. FPDetective: Dusting the web for fingerprinters. In
Proceedings of the 2013 ACM SIGSAC Conference on Computer and Communi-
cations Security, CCS ’13, pages 1129–1140, 2013.
[14] Marc Andrysco, Andres Nötzli, Fraser Brown, Ranjit Jhala, and Deian Stefan.
Towards verified, constant-time floating point operations. In Proceedings of
the 2018 ACM SIGSAC Conference on Computer and Communications Security,
CCS ’18, pages 1369–1382, New York, NY, USA, 2018. ACM.
[15] Amittai Aviram, Sen Hu, Bryan Ford, and Ramakrishna Gummadi. Determi-
nating timing channels in compute clouds. In Proceedings of the 2010 ACM
Workshop on Cloud Computing Security Workshop, CCSW ’10, pages 103–108,
New York, NY, USA, 2010. ACM.
[16] Andrew Bortz and Dan Boneh. Exposing private information by timing web
applications. In Proceedings of the 16th International Conference on World Wide
Web, WWW ’07, pages 621–628, New York, NY, USA, 2007. ACM.
[17] Pablo Buiras, Amit Levy, Deian Stefan, Alejandro Russo, and DavidMazieres. A
library for removing cache-based attacks in concurrent information flow systems.
In International Symposium on Trustworthy Global Computing, pages 199–216.
Springer, 2013.
[18] Yinzhi Cao, Zhanhao Chen, Song Li, and Shujiang Wu. Deterministic browser.
In Proceedings of the 23rd ACM SIGSAC Conference on Computer and Commu-
nications Security, CCS ’17, 2017.
[19] Yinzhi Cao, Song Li, and Erik Wijmans. (cross-)browser fingerprinting via os
and hardware level features. In Annual Network and Distributed System Security
Symposium, NDSS, 2017.
[20] Steven Englehardt and Arvind Narayanan. Online tracking: A 1-million-site mea-
surement and analysis. In Proceedings of the 22Nd ACM SIGSAC Conference on
Computer and Communications Security, CCS ’16, 2016.
[21] Ulfar Erlingsson and Fred B Schneider. Irm enforcement of java stack inspection.
In IEEE S&P, 2000.
[22] Edward W. Felten and Michael A. Schneider. Timing attacks on web privacy.
In Proceedings of the 7th ACM Conference on Computer and Communications
Security, CCS ’00, pages 25–32, New York, NY, USA, 2000. ACM.
[23] David Fifield and Serge Egelman. Fingerprinting web users through font metrics.
In Financial Cryptography and Data Security, pages 107–124. Springer, 2015.
[24] Ben Gras, Kaveh Razavi, Erik Bosman, Herbert Bos, and Cristiano Giuffrida.
Aslr on the line: Practical cache attacks on the mmu. In Annual Network and
Distributed System Security Symposium, NDSS, 2017.
[25] Ralf Hund, Carsten Willems, and Thorsten Holz. Practical timing side channel
attacks against kernel space aslr. In Proceedings of the 2013 IEEE Symposium
on Security and Privacy, SP ’13, pages 191–205, Washington, DC, USA, 2013.
IEEE Computer Society.
[26] Darius Kazemi. Counting uniforms in webgl. https://bocoup.com/blog/
counting-uniforms- in-webgl.
[27] Emre Kiciman and Benjamin Livshits. Ajaxscope: a platform for remotely mon-
itoring the client-side behavior of web 2.0 applications. In SIGOPS, 2007.
[28] Paul C. Kocher. Timing attacks on implementations of diffie-hellman, rsa, dss,
and other systems. In Proceedings of the 16th Annual International Cryptology
Conference on Advances in Cryptology, CRYPTO ’96, pages 104–113, London,
UK, UK, 1996. Springer-Verlag.
[29] David Kohlbrenner and Hovav Shacham. On the effectiveness of mitigations
against floating-point timing channels. In 26th USENIX Security Symposium,
USENIX Security 2017, Vancouver, BC, Canada, August 16-18, 2017., pages 69–
81, 2017.
[30] Balachander Krishnamurthy, Konstantin Naryshkin, and Craig Wills. Privacy
leakage vs. protection measures: the growing disconnect. In Web 2.0 Security
and Privacy Workshop, 2011.
[31] Balachander Krishnamurthy and Craig Wills. Privacy diffusion on the web: a
longitudinal perspective. In Proceedings of the 18th international conference on
World wide web, pages 541–550. ACM, 2009.
[32] Balachander Krishnamurthy and Craig E Wills. Generating a privacy footprint on
the internet. In Proceedings of the 6th ACM SIGCOMM conference on Internet
measurement, pages 65–70. ACM, 2006.
[33] Balachander Krishnamurthy and Craig E Wills. Characterizing privacy in online
social networks. In Proceedings of the first workshop on Online social networks,
pages 37–42. ACM, 2008.
[34] Pierre Laperdrix, Walter Rudametkin, and Benoit Baudry. Beauty and the beast:
Diverting modern web browsers to build unique browser fingerprints. In 37th
IEEE Symposium on Security and Privacy (S&P 2016), 2016.
[35] Adam Lerner, Anna Kornfeld Simpson, Tadayoshi Kohno, and Franziska Roes-
ner. Internet jones and the raiders of the lost trackers: An archaeological study of
web tracking from 1996 to 2016. In 25th USENIX Security Symposium (USENIX
Security 16), Austin, TX, 2016.
[36] Peng Li, Debin Gao, and Michael K. Reiter. Mitigating access-driven timing
channels in clouds using stopwatch. In 2013 43rd Annual IEEE/IFIP Interna-
tional Conference on Dependable Systems and Networks (DSN), Budapest, Hun-
gary, June 24-27, 2013, pages 1–12, 2013.
[37] Peng Li, Debin Gao, and Michael K. Reiter. Stopwatch: A cloud architecture for
timing channel mitigation. ACM Trans. Inf. Syst. Secur., 17(2):8:1–8:28, Novem-
ber 2014.
[38] Zhichun Li, Yi Tang, Yinzhi Cao, Vaibhav Rastogi, Yan Chen, Bin Liu, and Clint
Sbisa. Webshield: Enabling various web defense techniques without client side
modifications. In NDSS, 2011.
USENIX Association 28th USENIX Security Symposium 1659
[39] Yali Liu, Dipak Ghosal, Frederik Armknecht, Ahmad-Reza Sadeghi, Steffen
Schulz, and Stefan Katzenbeisser. Hide and seek in time - robust covert timing
channels. In Michael Backes and Peng Ning, editors, ESORICS, volume 5789 of
Lecture Notes in Computer Science, pages 120–135. Springer, 2009.
[40] Keaton Mowery, Dillon Bogenreif, Scott Yilek, and Hovav Shacham. Finger-
printing information in javascript implementations. In WEB 2.0 SECURITY &
PRIVACY (W2SP), 2011.
[41] Keaton Mowery and Hovav Shacham. Pixel perfect: Fingerprinting canvas in
html5. In W2SP, 2012.
[42] Martin Mulazzani, Philipp Reschl, Markus Huber, Manuel Leithner, Sebastian
Schrittwieser, Edgar Weippl, and FC Wien. Fast and reliable browser identifica-
tion with javascript engine fingerprinting. In WEB 2.0 SECURITY & PRIVACY
(W2SP), 2013.
[43] Hoda Naghibijouybari, Ajaya Neupane, Zhiyun Qian, and Nael Abu-Ghazaleh.
Rendered insecure: Gpu side channel attacks are practical. In Proceedings of
the 2018 ACM SIGSAC Conference on Computer and Communications Security,
CCS ’18, pages 2139–2153, New York, NY, USA, 2018. ACM.
[44] Nick Nikiforakis, Wouter Joosen, and Benjamin Livshits. Privaricator: Deceiving
fingerprinters with little white lies. In Proceedings of the 24th International
Conference on World Wide Web, WWW ’15, pages 820–830, New York, NY,
USA, 2015. ACM.
[45] Nick Nikiforakis, Alexandros Kapravelos, Wouter Joosen, Christopher Kruegel,
Frank Piessens, and Giovanni Vigna. Cookieless monster: Exploring the ecosys-
tem of web-based device fingerprinting. In IEEE Symposium on Security and
Privacy, 2013.
[46] Yossef Oren, Vasileios P. Kemerlis, Simha Sethumadhavan, and Angelos D.
Keromytis. The spy in the sandbox: Practical cache attacks in javascript and
their implications. In Proceedings of the 22Nd ACM SIGSAC Conference on
Computer and Communications Security, CCS ’15, pages 1406–1418, New York,
NY, USA, 2015. ACM.
[47] Xiang Pan, Yinzhi Cao, and Yan Chen. I do not know what you visited last sum-
mer - protecting users from third-party web tracking with trackingfree browser.
In NDSS, 2015.
[48] M Perry, E Clark, and S Murdoch. The design and implementation of the tor
browser [draft][online], united states, 2015.
[49] Mike Perry, Erinn Clark, Steven Murdoch, and Georg Kop-
pen. The design and implementation of the tor browser.
https://www.torproject.org/projects/torbrowser/design/.
[50] Jason Peterson. How to start building your own webgl-based vr
app. https://medium.com/adventures-in- consumer-technology/
how-to- start-building- your- own-webgl- based- vr-app- cdaf47b8132a.
[51] Ashay Rane, Calvin Lin, and Mohit Tiwari. Secure, precise, and fast floating-
point operations on x86 processors. In 25th USENIX Security Symposium,
USENIX Security 16, Austin, TX, USA, August 10-12, 2016., pages 71–86, 2016.
[52] Charles Reis, John Dunagan, Helen J. Wang, Opher Dubrovsky, and Saher Es-
meir. Browsershield: vulnerability-driven filtering of dynamic html. In OSDI:
USENIX Symposium on Operating Systems Design and Implementation, 2006.
[53] Franziska Roesner, Tadayoshi Kohno, and David Wetherall. Detecting and
defending against third-party tracking on the web. In Proceedings of the
9th USENIX Conference on Networked Systems Design and Implementation,
NSDI’12, pages 12–12, Berkeley, CA, USA, 2012. USENIX Association.
[54] Michael Schwarz, Moritz Lipp, and Daniel Gruss. Javascript zero: Real
javascript and zero side-channel attacks. In NDSS, 2018.
[55] Peter Snyder, Lara Ansari, Cynthia Taylor, and Chris Kanich. Browser feature
usage on the modern web. In Proceedings of the 2016 Internet Measurement
Conference, IMC ’16, pages 97–110, New York, NY, USA, 2016. ACM.
[56] Deian Stefan, Pablo Buiras, Edward Z Yang, Amit Levy, David Terei, Alejan-
dro Russo, and David Mazières. Eliminating cache-based timing attacks with
instruction-based scheduling. In European Symposium on Research in Computer
Security, pages 718–735. Springer, 2013.
[57] Tom Van Goethem, Wouter Joosen, and Nick Nikiforakis. The clock is still tick-
ing: Timing attacks in the modern web. In Proceedings of the 22Nd ACM SIGSAC
Conference on Computer and Communications Security, CCS ’15, pages 1382–
1393, New York, NY, USA, 2015. ACM.
[58] Tom Van Goethem, Mathy Vanhoef, Frank Piessens, and Wouter Joosen. Request
and conquer: Exposing cross-origin resource size. In Proceedings of the 21st
USENIX Conference on Security Symposium, Security, 2016.
[59] Antoine Vastel, Pierre Laperdrix, Walter Rudametkin, and Romain Rouvoy. Fp-
stalker: Tracking browser fingerprint evolutions.
[60] Antoine Vastel, Pierre Laperdrix, Walter Rudametkin, and Romain Rouvoy. FP-
Scanner: The Privacy Implications of Browser Fingerprint Inconsistencies. In
Proceedings of the 27th USENIX Security Symposium, Baltimore, United States,
August 2018.
[61] Weiyi Wu and Bryan Ford. Deterministically deterring timing attacks in deter-
land. In Conference on Timely Results in Operating Systems (TRIOS), 2015.
[62] Zhihao Yao, Saeed Mirzamohammadi, Ardalan Amiri Sani, and Mathias Payer.
Milkomeda: Safeguarding the mobile gpu interface using webgl security checks.
In Proceedings of the 2018 ACM SIGSAC Conference on Computer and Com-
munications Security, CCS ’18, pages 1455–1469, New York, NY, USA, 2018.
ACM.
[63] Ting-Fang Yen, Yinglian Xie, Fang Yu, Roger Peng Yu, and Martın Abadi. Host
fingerprinting and tracking on the web: Privacy and security implications. In
Proceedings of NDSS, 2012.
[64] Yinqian Zhang, Ari Juels, Alina Oprea, and Michael K. Reiter. Homealone: Co-
residency detection in the cloud via side-channel analysis. In Proceedings of
the 2011 IEEE Symposium on Security and Privacy, SP ’11, pages 313–328,
Washington, DC, USA, 2011. IEEE Computer Society.
[65] Yinqian Zhang, Ari Juels, Michael K. Reiter, and Thomas Ristenpart. Cross-vm
side channels and their use to extract private keys. In Proceedings of the 2012
ACM Conference on Computer and Communications Security, CCS ’12, pages
305–316, New York, NY, USA, 2012. ACM.
Appendix
A Statistics of Collected Fingerprints
In the appendix, we show some statistics about collected
fingerprints using the WebGL tasks provided by the original
Cao et al.’s website. Figure 11 shows the anonymous set for
the collected data, which is broken down into three different
browsers. The size of anonymous set is relatively small—if
we limit it to be three, we include 77% of all the collected
fingerprints. The largest anonymous set is just with about
10 fingerprints. Among all the browsers, Safari is the most
fingerprintable as compared with others: It is probably also
because the number of Safari users is relatively small.
=1 2~3 >3
Overall
Chrome
Firefox
Safari
0 0.2 0.4 0.6 0.8 1
Figure 11: Anonymous Set for Collected Fingerprints
1660 28th USENIX Security Symposium USENIX Association