Brief us your requirements below, and let's connect
1101 - 11th Floor
JMD Megapolis, Sector-48
Gurgaon, Delhi NCR - India
1st floor, Urmi Corporate Park
Solaris (D) Opp. L&T Gate No.6
Powai, Mumbai- 400072
#12, 100 Feet Road
Banaswadi,
Bangalore 5600432
UL CyberPark (SEZ)
Nellikode (PO)
Kerala, India - 673 016.
Westhill, Kozhikode
Kerala - 673005
India
In the first part, we explained the theoretical principles of Browser Fingerprinting. In this part, we will realize a concept-proof application to demonstrate the principle.
Table of Contents
We will, therefore, run a website that will collect browser information. We choose to code the server-side in PHP. Our probes will collect information about the browser on parallel and upload the information to the server-side.
The function AnalyzeHeaders will process the headers sent by the browser (user-agent etc…)
function AnalyzeHeaders($headers,$uuid)
{
include("Variables.php");
/*
$test_success
$Connection
$User-Agent
$Accept
$Accept-Encoding
$Accept-Language
$Accept-Charset
$Cache-Control
$Content-Length
$Content-Type
$Expect
$If-Match
$If-Modified-Since
$If-None-Match
$If-Range
$If-Unmodified-Since
$Max-Forwards
$Pragma
$Range
$TE
$Upgrade
$Via
$Warning
$misc_headers
*/
foreach ($headers as $name => $value) {
echo "<div>$name: $value</div>";
Tracer("Header data $name : $value",1,$uuid);
}
$headers["uuid"]=$uuid;
$headers["testname"]="headers";
$headers["test_success"]=1;
Tracer("post Header data to ".$hostserver."/test_result_sql.php",1,$uuid);
curl_post_async($hostserver."/test_result_sql.php",$headers);
}
We use javascript to collect primary information about plugins and micro-versions of the plugins. Most of the information is obtained through the navigator object.
function getNavInfos()
{
var plugs="<table border='1'><tr><th>plug-in name</th><th>description</th><th>filename</th></tr>";
var plug2="";
for(i=0;i<navigator.plugins.length;i++)
{
plugs=plugs+"<tr id='description'><td>"+navigator.plugins[i].name+"</td><td>"+navigator.plugins[i].description+"</td><td>"+navigator.plugins[i].filename+"</td></tr>";
plug2=plug2+"[PLUGIN NAME="+navigator.plugins[i].name+"][PLUGIN DESCRIPTION="+navigator.plugins[i].description+"][PLUGIN FILENAME="+navigator.plugins[i].filename+"])";
//level2 mime types
var nav2=navigator.plugins[i];
if(nav2.length != null)
{
for(j=0;j<nav2.length;j++)
{
if((nav2[j].type!=null)&&(nav2[j].description!=null))
{
plugs=plugs+"<tr><td>"+nav2[j].type+"</td><td>"+nav2[j].description+"</td><td>"+nav2[j].suffixes+"</td></tr>";
plug2=plug2+"([mime type="+nav2[j].type+"][mime description="+nav2[j].description+"][mime suffixes="+nav2[j].suffixes+"])";
}
}
}
}
plugs=plugs+"</table>";
var language=navigator.language;
var product=navigator.product;
var mimeTypes=null;
var appVersion=navigator.appVersion;
var plugins=plug2;
var onLine=navigator.onLine;
var platform=navigator.platform;
var vendor=navigator.vendor;
var appCodeName=navigator.appCodeName;
var cookieEnabled=navigator.cookieEnabled;
var geolocationEnabled=((navigator.geolocation==null)?"false":"true");
var appName=navigator.appName;
var productSub=navigator.productSub;
var userAgent=navigator.userAgent ;
var vendorSub=navigator.vendorSub;
var test_success=1;
if(product==null)
{
test_success=0;
}
//post to sql
if (typeof console == "undefined") var console = { log: function() {} };
jQuery.post("test_result_sql.php", { testname: 'navigator_javascript' , test_success: test_success , var_language:language , var_product:product , var_mimeTypes:mimeTypes , var_appVersion:appVersion , var_plugins:plugins , var_onLine:onLine , var_platform:platform , var_vendor:vendor , var_appCodeName:appCodeName , var_cookieEnabled:cookieEnabled , var_geolocationEnabled:geolocationEnabled , var_appName:appName , var_productSub:productSub , var_userAgent:userAgent , var_vendorSub:vendorSub , uuid:window.uuid},function( data ) {
Tracer("test navigator javascript post:"+ data,1,window.uuid);
} );
//alert(plugs);
return "language="+navigator.language+"<br>"+
"product="+navigator.product+"<br>"+
"mimeTypes="+navigator.mimeTypes+"<br>"+
"appVersion="+navigator.appVersion+"<br>"+
"plugins="+plugs+"<br>"+
"onLine="+navigator.onLine+"<br>"+
"platform="+navigator.platform+"<br>"+
"vendor="+navigator.vendor+"<br>"+
"appCodeName="+navigator.appCodeName+"<br>"+
"cookieEnabled="+navigator.cookieEnabled+"<br>"+
"geolocation Enabled="+((navigator.geolocation==null)?"false":"true")+"<br>"+
"appName="+navigator.appName+"<br>"+
"productSub="+navigator.productSub+"<br>"+
"userAgent="+navigator.userAgent +"<br>"+
"vendorSub="+navigator.vendorSub+"<br>";
}
function getNavInfosTXT()
{
plugs="";
for(i=0;i<navigator.plugins.length;i++)
{
plugs=plugs+"decription="+navigator.plugins[i].name+",name="+navigator.plugins[i].description+",filename="+navigator.plugins[i].filename+"%";
//level2 mime types
var nav2=navigator.plugins[i];
if(nav2.length != null)
{
for(j=0;j<nav2.length;j++)
{
if((nav2[j].type!=null)&&(nav2[j].description!=null))
{
plugs=plugs+",type="+nav2[j].type+",description="+nav2[j].description+",suffixes="+nav2[j].suffixes+",";
}
}
}
}
//alert(plugs);
return "language="+navigator.language+"<br>"+
"product="+navigator.product+"<br>"+
"mimeTypes="+navigator.mimeTypes+"<br>"+
"appVersion="+navigator.appVersion+"<br>"+
"plugins="+plugs+"<br>"+
"onLine="+navigator.onLine+"<br>"+
"platform="+navigator.platform+"<br>"+
"vendor="+navigator.vendor+"<br>"+
"appCodeName="+navigator.appCodeName+"<br>"+
"cookieEnabled="+navigator.cookieEnabled+"<br>"+
"geolocation Enabled="+((navigator.geolocation==null)?"true":"false")+"<br>"+
"appName="+navigator.appName+"<br>"+
"productSub="+navigator.productSub+"<br>"+
"userAgent="+navigator.userAgent +"<br>"+
"vendorSub="+navigator.vendorSub+"<br>";
}
Javascript will run a certain amount of checks. For example, it can detect the OS version:
function os_test(uuid)
{
try{
var os_js_test_success=1;
var os_js=null;
if (typeof BrowserDetect == "undefined")
{
os_js_test_success=0;
os_js=null;
}else if(BrowserDetect.OS==null)
{
os_js_test_success=0;
os_js=null;
}
else
{
os_js=BrowserDetect.OS;
window.document.getElementById('OS').innerHTML=os_js;
}
jQuery.post("test_result_sql.php", { testname: 'os_javascript' , test_success: os_js_test_success ,os:os_js, uuid:uuid},function( data ) {
Tracer("test os javascript post:"+ data,1,window.uuid);
} );
}
catch(err)
{
Tracer(err.description,3,window.uuid);
}
}
Our javascript probes can also detect the information related to the screen:
function getViewPort()
{
var viewportwidth;
var viewportheight;
if (typeof window.innerWidth != 'undefined')
{
viewportwidth = window.innerWidth,
viewportheight = window.innerHeight
}
else if (typeof document.documentElement != 'undefined'
&& typeof document.documentElement.clientWidth !=
'undefined' && document.documentElement.clientWidth != 0)
{
viewportwidth = document.documentElement.clientWidth,
viewportheight = document.documentElement.clientHeight
}
// older versions of IE
else
{
viewportwidth = document.getElementsByTagName('body')[0].clientWidth,
viewportheight = document.getElementsByTagName('body')[0].clientHeight
}
return viewportwidth+'x'+viewportheight;
}
function getScreenInfos(session_id)
{
jQuery.post("test_result_sql.php", { testname: 'screen' , test_success: 1 , Height: screen.availHeight, Width: screen.availWidth ,colorDepth:screen.colorDepth,totalheight:screen.height,pixelDepth:screen.pixelDepth,totalwidth: screen.width ,uuid:session_id},function( data ) {
console.log("test screen post:"+ data);
} );
return "Height="+screen.availHeight+",Width="+screen.availWidth+",colorDepth="+screen.colorDepth+",totalheight="+screen.height+",pixelDepth="+screen.pixelDepth+",totalwidth="+screen.width;
}
If the Flash plugin is present (and enabled) in the browser we check the hardware information. They are reached through the Capabilities object.
public function hardware():Array {
var hardw:Array = new Array();
hardw[0]=Capabilities.avHardwareDisable;
hardw[1]=Capabilities.hasAccessibility;
hardw[2]=Capabilities.hasAudio;
hardw[3]=Capabilities.hasAudioEncoder;
hardw[4]=Capabilities.hasEmbeddedVideo
hardw[5]=Capabilities.hasMP3
hardw[6]=Capabilities.hasPrinting
hardw[7]=Capabilities.hasScreenBroadcast
hardw[8]=Capabilities.hasScreenPlayback
hardw[9]=Capabilities.hasStreamingAudio
hardw[10]=Capabilities.hasVideoEncoder
hardw[11]=Capabilities.isDebugger
hardw[12]=Capabilities.language
hardw[13]=Capabilities.localFileReadDisable
hardw[14]=Capabilities.manufacturer
hardw[15]=Capabilities.os
hardw[16]=Capabilities.pixelAspectRatio
hardw[17]=Capabilities.playerType
hardw[18]=Capabilities.screenColor
hardw[19]= Capabilities.screenDPI
hardw[20]= Capabilities.screenResolutionX
hardw[21]= Capabilities.screenResolutionY
hardw[22]=Capabilities.serverString
hardw[23]= Capabilities.version;
return hardw;
}
As well as the font information:
package {
import flash.display.Sprite;
import flash.display.LoaderInfo;
import flash.text.Font;
import flash.external.ExternalInterface;
public class FontList extends Sprite {
public function FontList() {
var params:Object = loadParams();
loadExternalInterface(params);
}
private function loadParams():Object {
return LoaderInfo(this.root.loaderInfo).parameters;
}
private function loadExternalInterface(params:Object):void {
ExternalInterface.marshallExceptions = true;
ExternalInterface.addCallback("fonts", fonts);
ExternalInterface.call(params.onReady, params.swfObjectId);
}
public function fonts():Array {
return Font.enumerateFonts(true).sortOn("fontName", Array.CASEINSENSITIVE);
}
}
}
If java is present and enabled in the browser, we use it to retrieve hardware information and general information about the system:
import com.sun.servicetag.SystemEnvironment;
import java.lang.management.ManagementFactory;
public class Config extends java.applet.Applet{
public void paint(java.awt.Graphics g){
try{
g.drawString("System Informations: ",50,10);
SystemEnvironment se = SystemEnvironment.getSystemEnvironment();
g.drawString("CpuManufacturer:"+se.getCpuManufacturer(),50,40);
g.drawString("HostID:"+se.getHostId(),50,60);
g.drawString("Host Name:"+se.getHostname(),50,80);
g.drawString("OS Architecture:"+se.getOsArchitecture(),50,100);
g.drawString("OS Name:"+se.getOsName(),50,120);
g.drawString("OS Verstion:"+se.getOsVersion(),50,140);
g.drawString("Serial no:"+se.getSerialNumber(),50,160);
g.drawString("System model:"+se.getSystemModel(),50,180);
g.drawString("System Manufacturer:"+se.getSystemManufacturer(),50,200);
com.sun.management.OperatingSystemMXBean mxbean = (com.sun.management.OperatingSystemMXBean)ManagementFactory.getOperatingSystemMXBean();
// g.drawString("Available Processors:"+mxbean.getAvailableProcessors(),50,220);
g.drawString("TotalRAM:"+mxbean.getTotalSwapSpaceSize()/(1024*1024*1024)+""+"GB",50,240);
g.drawString("RAM SIZE :" + (mxbean.getTotalPhysicalMemorySize()/(1024*1024*1024))+ " GB ",50,260);
}
catch(Exception e)
{
g.drawString(e.getMessage());
}
}
Additionally, we also get a list of fonts:
public class listFonts extends Applet {
public void init() {
setBackground(Color.white);
GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
String [] fonts = ge.getAvailableFontFamilyNames();
String fontslist="";
List lst = new List(fonts.length,false);
for ( int i = 0 ; i < fonts.length ; i++ )
{
lst.add(fonts[i]);
fontslist=fontslist+fonts[i]+";";
}
setLayout(new BorderLayout());
add("Center",lst);
try {
getAppletContext().showDocument
(new URL("javascript:postFontJava(\"" + fontslist +"\")"));
}
catch (MalformedURLException me) { }
}
public String getAppletInfo() {
return "Font list:";
}
Finally, if Silverlight is present and enabled in the navigator, we use it to get system information:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Text;
using System.IO;
using System.Windows.Browser;
namespace SilverlightApplication1
{
public partial class MainPage : UserControl
{
public string Encode(string str)
{
byte[] encbuff = System.Text.Encoding.UTF8.GetBytes(str);
return Convert.ToBase64String(encbuff);
}
public MainPage()
{
InitializeComponent();
// Collect system info
StringBuilder sbStringBuilder = new StringBuilder();
sbStringBuilder.AppendLine("-------BROWSER INFO---------");
sbStringBuilder.AppendLine("Browser Name = " + HtmlPage.BrowserInformation.Name);
String BrowserName = HtmlPage.BrowserInformation.Name;
sbStringBuilder.AppendLine("Browser Version = " + HtmlPage.BrowserInformation.BrowserVersion.ToString());
String BrowserVersion = HtmlPage.BrowserInformation.BrowserVersion.ToString();
sbStringBuilder.AppendLine("UserAgent = " + HtmlPage.BrowserInformation.UserAgent);
String UserAgent = HtmlPage.BrowserInformation.UserAgent;
sbStringBuilder.AppendLine("Platform = " + HtmlPage.BrowserInformation.Platform);
String Platform = HtmlPage.BrowserInformation.Platform;
sbStringBuilder.AppendLine("CookiesEnabled = " + HtmlPage.BrowserInformation.CookiesEnabled.ToString());
String CookiesEnabled = HtmlPage.BrowserInformation.CookiesEnabled.ToString();
sbStringBuilder.AppendLine("ProductName = " + HtmlPage.BrowserInformation.ProductName.ToString());
String ProductName = HtmlPage.BrowserInformation.ProductName.ToString();
sbStringBuilder.AppendLine("ProductVersion = " + HtmlPage.BrowserInformation.ProductVersion.ToString());
String ProductVersion = HtmlPage.BrowserInformation.ProductVersion.ToString();
sbStringBuilder.AppendLine("-------O.S INFO---------");
sbStringBuilder.AppendLine("OSVersion: " + Environment.OSVersion);
String OSVersion = ""+Environment.OSVersion;
//sbStringBuilder.AppendLine("System start: " +
// Environment.TickCount.ConvertToNiceTime());
sbStringBuilder.AppendLine("CLR Version: " + Environment.Version);
String CLRVersion = ""+Environment.Version;
sbStringBuilder.AppendLine("Number of processors: " + Environment.ProcessorCount);
String Numberofprocessors = ""+Environment.ProcessorCount;
// Environment.
//Get GPU infos
System.Collections.ObjectModel.ReadOnlyCollection<String> ClientInfos = Analytics.ClientInformation;
String sClientInfos = "";
sbStringBuilder.AppendLine("-------CLIENT INFOS---------");
try
{
IEnumerator<String> cienum = ClientInfos.GetEnumerator();
while (cienum.MoveNext())
{
String cinfo = cienum.Current;
sbStringBuilder.AppendLine(cinfo);
sClientInfos = sClientInfos + cinfo + ";";
}
}
catch (Exception e)
{
// e.StackTrace();
}
System.Collections.ObjectModel.ReadOnlyCollection<AudioCaptureDevice> ccd = CaptureDeviceConfiguration.GetAvailableAudioCaptureDevices();
String audioCaptureDevices = "";
IEnumerator<AudioCaptureDevice> ccdie = ccd.GetEnumerator();
sbStringBuilder.AppendLine("-------AUDIO CAPTURE DEVICES---------");
while (ccdie.MoveNext())
{
sbStringBuilder.AppendLine("---------------");
AudioCaptureDevice acd = ccdie.Current;
sbStringBuilder.AppendLine("name: " + acd.FriendlyName);
audioCaptureDevices = audioCaptureDevices + acd.FriendlyName + ";";
}
System.Collections.ObjectModel.ReadOnlyCollection<VideoCaptureDevice> cvcd = CaptureDeviceConfiguration.GetAvailableVideoCaptureDevices();
String videoCaptureDevices = "";
IEnumerator<VideoCaptureDevice> vcdie = cvcd.GetEnumerator();
sbStringBuilder.AppendLine("-------VIDEO CAPTURE DEVICES---------");
while (vcdie.MoveNext())
{
sbStringBuilder.AppendLine("---------------");
VideoCaptureDevice vcd = vcdie.Current;
sbStringBuilder.AppendLine("name: " + vcd.FriendlyName);
videoCaptureDevices = videoCaptureDevices + vcd.FriendlyName + ";";
}
Analytics an = new Analytics();
System.Collections.ObjectModel.ReadOnlyCollection<GpuInformation> gpucollect = an.GpuCollection;
IEnumerator<GpuInformation> gpuenum = gpucollect.GetEnumerator();
String GPU = "";
sbStringBuilder.AppendLine("-------GPU---------");
while (gpuenum.MoveNext())
{
sbStringBuilder.AppendLine("---------------");
GpuInformation gpuinfo = gpuenum.Current;
sbStringBuilder.AppendLine("Device ID=" + gpuinfo.DeviceId);
GPU = GPU + "Device ID=[" + gpuinfo.DeviceId + "]";
sbStringBuilder.AppendLine("Vendor ID=" + gpuinfo.VendorId);
GPU = GPU + "Vendor ID=[" + gpuinfo.VendorId + "]";
sbStringBuilder.AppendLine("Driver=" + gpuinfo.DriverVersion);
GPU = GPU + "Driver=[" + gpuinfo.DriverVersion + "]";
GPU = GPU + "//";
}
this.CPU_INFOS.Text = sbStringBuilder.ToString();
//GET THE LIST OF FONTS
String fonts = "";
var typefaces = System.Windows.Media.Fonts.SystemTypefaces;
sbStringBuilder.AppendLine("---- Fonts -----");
foreach (System.Windows.Media.Typeface face in typefaces)
{
System.Windows.Media.GlyphTypeface g;
// ComboBoxItem comboBoxItem = new ComboBoxItem();
face.TryGetGlyphTypeface(out g);
FontSource fs = new FontSource(g);
var fontname = g.FontFileName;
fonts = fonts + fontname.ToString() + ";";
sbStringBuilder.AppendLine(fontname.ToString());
}
this.CPU_INFOS.Text = sbStringBuilder.ToString();
//export the data to javascript
try
{
this.log.Text = "Execution of postSilverlightTest in javascript: ";
HtmlPage.Window.Eval("postSilverlightTest('" + BrowserName + "','" + BrowserVersion + "','" + UserAgent + "','" + Platform + "','" + CookiesEnabled + "','" + ProductName + "','" + ProductVersion + "','" + OSVersion + "','" + CLRVersion + "','" + Numberofprocessors + "','" + sClientInfos + "','" + audioCaptureDevices + "','" + videoCaptureDevices + "','" + GPU + "','" + fonts + "');");
this.log.Text = this.log.Text +"OK";
}
catch (Exception e)
{
string error = e.ToString();
this.log.Text = this.log.Text + error;
}
}
}
}
Once all our probes are coded and the “glue” between the plug-ins, javascript and PHP have been created, we run our experiment, we gather and collect visitor’s IPs, geolocation and browser fingerprint in a SQL database.
Here is an example of the computation of a browser fingerprint:
Conclusion: When running the experiment, we did not found so far duplicated fingerprint and we were able to identify returning visitors who had changed just a few parameters, showing how flexible the fingerprint was. It demonstrates that tracking cookies are not necessarily needed to uniquely identify visitors. Such techniques should be taken seriously because they have very strong implications in terms of privacy.
Annex 1: full link for project code source download:
https://drive.google.com/file/d/1dmjCfyarnb6THjlHE6Iq9G5Q_dk6YhcV/view?usp=sharing
Acodez is a leading website design and web development company in India. We offer all kinds of web design and web development services to our clients using the latest technologies. We are also a top digital marketing agency providing SEO, SMM, SEM, Inbound marketing services, etc at affordable prices. For further information, please contact us.
Contact us and we'll give you a preliminary free consultation
on the web & mobile strategy that'd suit your needs best.
Advanced Content Delivery Network (CDN) Strategies for Global Web Performance
Posted on Oct 31, 2024 | Web DevelopmentWebAssembly In Modern Web Development: How It Can Revolutionize Web Performance
Posted on Oct 17, 2024 | Web DevelopmentWhat is Hyper-Personalization and Why Is It Becoming Increasingly Important?
Posted on Sep 24, 2024 | Web Development