Skip to content

Commit

Permalink
Adding fingerprint2 library and working some of its results into the …
Browse files Browse the repository at this point in the history
…v2 signature
  • Loading branch information
Hainish committed Feb 13, 2019
1 parent 56dcb9f commit 35c8510
Show file tree
Hide file tree
Showing 13 changed files with 242 additions and 53 deletions.
16 changes: 16 additions & 0 deletions db.py
Expand Up @@ -56,6 +56,22 @@ def set_version(self, version):
VALUES ('version', %s)""", (str(version),))
self.cxn.commit()

def migrate_to_2(self):
c = self.cxn.cursor()
c.execute("""ALTER TABLE `fingerprint`
ADD `fonts_v2` blob DEFAULT NULL,
ADD `supercookies_v2` varchar(255) DEFAULT NULL,
ADD `canvas_hash_v2` varchar(32) DEFAULT NULL,
ADD `webgl_hash_v2` varchar(32) DEFAULT NULL,
ADD `timezone_string` varchar(32) DEFAULT NULL,
ADD `webgl_vendor_renderer` varchar(255) DEFAULT NULL,
ADD `ad_block` varchar(5) DEFAULT NULL,
ADD `audio` varchar(32) DEFAULT NULL,
ADD `cpu_class` varchar(64) DEFAULT NULL,
ADD `hardware_concurrency` varchar(3) DEFAULT NULL,
ADD `device_memory` varchar(3) DEFAULT NULL""");
self.cxn.commit()

def count_sightings(self, cookie, signature):
c = self.cxn.cursor()
c.execute("""SELECT COUNT(cookie_id) FROM cookies
Expand Down
11 changes: 11 additions & 0 deletions examples/sql/schema.sql
Expand Up @@ -37,6 +37,17 @@ CREATE TABLE `fingerprint` (
`language` varchar(32) DEFAULT NULL,
`platform` varchar(32) DEFAULT NULL,
`touch_support` varchar(128) DEFAULT NULL,
`fonts_v2` blob DEFAULT NULL,
`supercookies_v2` varchar(255) DEFAULT NULL,
`canvas_hash_v2` varchar(32) DEFAULT NULL,
`webgl_hash_v2` varchar(32) DEFAULT NULL,
`timezone_string` varchar(32) DEFAULT NULL,
`webgl_vendor_renderer` varchar(255) DEFAULT NULL,
`ad_block` varchar(5) DEFAULT NULL,
`audio` varchar(32) DEFAULT NULL,
`cpu_class` varchar(64) DEFAULT NULL,
`hardware_concurrency` varchar(3) DEFAULT NULL,
`device_memory` varchar(3) DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY (`signature`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
Expand Down
24 changes: 20 additions & 4 deletions fingerprint/fingerprint_agent.py
Expand Up @@ -27,15 +27,31 @@ def detect_server_whorls(self):
vars_v1['plugins'] = u"no javascript"
vars_v1['video'] = u"no javascript"
vars_v1['timezone'] = u"no javascript"
vars_v1['language'] = u"no javascript"
vars_v1['platform'] = u"no javascript"
vars_v1['touch_support'] = u"no javascript"

vars_v2 = vars_v1.copy()

vars_v1['fonts'] = u"no javascript"
vars_v1['supercookies'] = u"no javascript"
vars_v1['canvas_hash'] = u"no javascript"
vars_v1['webgl_hash'] = u"no javascript"
vars_v1['language'] = u"no javascript"
vars_v1['platform'] = u"no javascript"
vars_v1['touch_support'] = u"no javascript"

return vars_v1
vars_v2['fonts_v2'] = u"no javascript"
vars_v2['supercookies_v2'] = u"no javascript"
vars_v2['canvas_hash_v2'] = u"no javascript"
vars_v2['webgl_hash_v2'] = u"no javascript"

vars_v2['timezone_string'] = u"no javascript"
vars_v2['webgl_vendor_renderer'] = u"no javascript"
vars_v2['ad_block'] = u"no javascript"
vars_v2['audio'] = u"no javascript"
vars_v2['cpu_class'] = u"no javascript"
vars_v2['hardware_concurrency'] = u"no javascript"
vars_v2['device_memory'] = u"no javascript"

return (vars_v1, vars_v2)

def _get_header(self, header):
return self.request.headers.get(header) or ""
37 changes: 36 additions & 1 deletion fingerprint/fingerprint_helper.py
Expand Up @@ -19,10 +19,45 @@ class FingerprintHelper(object):
'touch_support': "Touch Support"
}

whorl_v2_names = {
'user_agent': "User Agent",
'http_accept': "HTTP_ACCEPT Headers",
'plugins': "Browser Plugin Details",
'timezone': "Time Zone Offset",
'timezone_string': "Time Zone",
'video': "Screen Size and Color Depth",
'fonts_v2': "System Fonts",
'cookie_enabled': "Are Cookies Enabled?",
'supercookies_v2': "Limited supercookie test",
'canvas_hash_v2': "Hash of canvas fingerprint",
'webgl_hash_v2': "Hash of WebGL fingerprint",
'webgl_vendor_renderer': "WebGL Vendor & Renderer",
'dnt_enabled': "DNT Header Enabled?",
'language': "Language",
'platform': "Platform",
'touch_support': "Touch Support",
'ad_block': "Ad Blocker Used",
'audio': "AudioContext fingerprint",
'cpu_class': "CPU Class",
'hardware_concurrency': "Hardware Concurrency",
'device_memory': "Device Memory (GB)"
}


# Any value that is ever expected to be over 255 characters (the length of
# the 'value' field in 'totals') should be contained in this list.
md5_keys = [
'plugins', 'fonts', 'user_agent', 'http_accept', 'supercookies', 'touch_support']
'plugins',
'fonts',
'fonts_v2',
'user_agent',
'http_accept',
'supercookies',
'supercookies_v2',
'touch_support',
'webgl_vendor_renderer',
'cpu_class'
]

@classmethod
def value_or_md5(cls, whorls):
Expand Down
22 changes: 18 additions & 4 deletions fingerprint/fingerprint_recorder.py
Expand Up @@ -10,7 +10,7 @@
class FingerprintRecorder(object):

@classmethod
def record_fingerprint(cls, whorls_v1, cookie, ip_addr, key):
def record_fingerprint(cls, whorls_v1, whorls_v2, cookie, ip_addr, key):
# ensure no rogue values have been entered
valid_vars_v1 = list(FingerprintHelper.whorl_v1_names.keys())
valid_vars_v1.append('signature')
Expand All @@ -21,6 +21,16 @@ def record_fingerprint(cls, whorls_v1, cookie, ip_addr, key):
signature_v1 = hashlib.md5(serialized_whorls_v1.encode("utf-8")).hexdigest()
whorls_v1['signature'] = signature_v1

# ensure no rogue values have been entered
valid_vars_v2 = list(FingerprintHelper.whorl_v2_names.keys())
valid_vars_v2.append('signature')

sorted_whorls_v2 = sorted(whorls_v2.items())
serialized_whorls_v2 = json.dumps(sorted_whorls_v2)

signature_v2 = hashlib.md5(serialized_whorls_v2.encode("utf-8")).hexdigest()
whorls_v2['signature'] = signature_v2

# When multiple whorl versions are being calculated, valid_print should
# combine the whorls from both versions. There should never be a
# mismatch of a whorl between two versions. If, say, the canvas_hash
Expand All @@ -30,9 +40,13 @@ def record_fingerprint(cls, whorls_v1, cookie, ip_addr, key):
for i in whorls_v1:
if i in valid_vars_v1:
valid_print[i] = whorls_v1[i]
for i in whorls_v2:
if i in valid_vars_v2:
valid_print[i] = whorls_v2[i]

signatures = [
{ 'version': 1, 'signature': signature_v1 }
{ 'version': 1, 'signature': signature_v1 },
{ 'version': 2, 'signature': signature_v2 }
]

if cls._need_to_record(cookie, signatures, ip_addr, key):
Expand Down Expand Up @@ -67,14 +81,14 @@ def epoch_calculate_totals(epoch_beginning):
# been counted before
@staticmethod
def _need_to_record(cookie, signatures, ip_addr, key):
signature_v1 = signatures[0]['signature']
signature_v2 = signatures[1]['signature']

db = Db()
db.connect()
if cookie:
# okay, we have a cookie; check whether we've seen it with this
# fingerprint before
seen = db.count_sightings(cookie, signature_v1)
seen = db.count_sightings(cookie, signature_v2)
write_cookie = cookie
else:
seen = 0 # always count cookieless browsers
Expand Down
10 changes: 8 additions & 2 deletions main.py
Expand Up @@ -72,6 +72,9 @@ def migrate_db():

if db_version < 1:
db_version = 1
if db_version < 2:
db.migrate_to_2()
db_version = 2

db.set_version(db_version)

Expand Down Expand Up @@ -112,16 +115,19 @@ def fingerprint_nojs():

def fingerprint_generic(ajax_request, provide_additional_info=False):
# detect server whorls, merge with client whorls
server_whorls_v1 = FingerprintAgent(request).detect_server_whorls()
server_whorls_v1, server_whorls_v2 = FingerprintAgent(request).detect_server_whorls()
whorls_v1 = server_whorls_v1.copy()
whorls_v2 = server_whorls_v2.copy()
if ajax_request:
data = json.loads(request.data)
for i in data['v1'].keys():
whorls_v1[i] = str(data['v1'][i])
for i in data['v2'].keys():
whorls_v2[i] = str(data['v2'][i])

# record the fingerprint we've crafted
FingerprintRecorder.record_fingerprint(
whorls_v1, session['long_cookie'], request.remote_addr, key)
whorls_v1, whorls_v2, session['long_cookie'], request.remote_addr, key)

# calculate the values we'll need to display to the user
counts, total, matching, bits, group, uniqueness = EntropyHelper.calculate_values(
Expand Down
1 change: 1 addition & 0 deletions parcel/fp2.html
@@ -0,0 +1 @@
<script src="fp2.js"></script>
1 change: 1 addition & 0 deletions parcel/fp2.js
@@ -0,0 +1 @@
window.Fingerprint2_new = require('fingerprintjs2');
7 changes: 7 additions & 0 deletions static/dist/fp2.ada7e69f.js

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions static/dist/fp2.ada7e69f.map

Large diffs are not rendered by default.

0 comments on commit 35c8510

Please sign in to comment.