JavaScript and Daylight Savings for tracking users.

Published on by

Each country has their own timezone - although timezones are not generally unique variations in the offset can enable a website using JavaScript to pinpoint your location and operating system to an alarming degree of accuracy. Most countries time differs from UTC by increments of 1 hour and this is generally the case for every 15 degrees you travel east or west of the meridian - of course there are some exceptions, countries such as Iran have offsets of 3hrs 30mins, Nepal (+5:45) and Chatham Island (+12:45). If your unfortunate enough to live in Nepal, Iran, or Chatham Islands its very easy for JavaScript to identify your location just using Date.getTimeZoneOffset().

Similarly the following areas have distinct timezones:

  • Marquesas Islands -09:30
  • Venezuela -04:30
  • Labrador and Newfoundland -03:30
  • Brazilian Ocean Islands -02:00
  • Iran +03:30
  • Afghanistan +04:30
  • Nepal +05:45
  • Myanmar +06:30
  • Caiguna-Eucia +08:45
  • Lord Howe Island +10:30
  • Norfolk Island +11:30
  • Kiribati Line Islands +14:00

This only affects a few million people in a few specific locations and it makes it hard to establish what country someone is in who shares for example, the -11:00 timezone. However, many countries, states or territories observe or at some stage have experimented with DST (Daylight Savings Time). Michigan for example experimented briefly with DST in 1975, Western Australia in 1972 and Fiji in 2009. Places tend to choose different start and end dates and up until 2008 Brazil used to change the time that they entered DST each year. These differences can be used to distinguish a users country from other countries in the same offset.

Operating systems require a list of these changes in order to know when to change the time. While the name of the timezone and the dates that the clock changes is not directly accessible via the JavaScript Date object the current timezone can be inferred by calculating the dates that the TimeZoneOffset changes.

Using the Date object its possible to loop through all the days from 1970 to 2010 and observe when the TimeZoneOffset changes (1970 is the earliest that the time zone database goes back). By recording the dates when the offset changes we can create a fingerprint that may help to locate a users position:

var d        = new Date();
var i        = d.getTime();
var oldTime  = d.getTimezoneOffset();
var fp       = '';

d.setTime(0);

for (var i = 0; i < 1317731928000; i += 86400000) {
     d.setTime(i);
     newTime = d.getTimezoneOffset();
     if (newTime != oldTime) {
        timeZone += (newTime + '@' + Math.round(i / 1000) + ';');
        oldTime = newTime;      
     }
}

When run on Linux in the Firefox browser the script will create strings such as the following which are unique and identify users in New South Wales, Australia:

-600@39618001; -660@55346401; -600@71067601; -660@86796001; -600@102517201; -660@118850401; -600@134571601; -660@150300001; -600@166021201; -660@181749601; -600@197470801; -660@213199201; -600@228920401; -660@244648801; -600@260370001; -660@276098401; -600@291819601; -660@308152801; -600@323874001; -660@339602401; -600@355323601; -660@371052001; -600@386773201; -660@402501601; -600@418222801; -660@433951201; -600@449672401; -660@466005601; -600@481726801; -660@497455201; -600@513176401; -660@528904801; -600@544626001; -660@560354401; -600@576075601; -660@591804001; -600@607525201; -660@623253601; -600@638974801; -660@655308001; -600@671029201; -660@686757601; -600@702478801; -660@718207201; -600@733928401; -660@749656801; -600@765378001; -660@781106401; -600@796827601; -660@812556001; -600@828882001; -660@844610401; -600@860331601; -660@876060001; -600@891781201; -660@907509601; -600@923230801; -660@938959201; -600@954680401; -660@970408801; -600@986130001; -660@1002463201; -600@1018184401; -660@1033912801; -600@1049634001; -660@1065362401; -600@1081083601; -660@1096812001; -600@1112533201; -660@1128261601; -600@1143982801; -660@1159711201; -600@1175432401; -660@1191765601; -600@1207486801; -660@1223215201; -600@1238936401; -660@1254664801; -600@1270386001; -660@1286114401;

A good example is that of Istanbul (Turkey), Minsk (Belarus) and Jerusalem (Israel) - All share the +0200 Timezone but all have observed DST at differing times since 1970 creating three different signatures:

Istanbul:
-180@39132001; -120@57790801; -180@70581601; -120@89240401; -180@102031201; -120@120690001; -180@133480801; -120@152139601; -180@165535201; -120@183589201; -180@196984801; -120@215643601; -180@228434401; -120@247093201; -180@259884001; -120@278542801; -180@291333601; -120@309992401; -180@323388001; -120@341442001; -180@354837601; -120@372891601; -180@386287201; -120@404946001; -180@417736801; -120@436395601; -180@449186401; -120@467845201; -180@480636001; -120@499294801; -180@512690401; -120@530744401; -180@544140001; -120@562194001; -180@575589601; -120@594248401; -180@607039201; -120@625698001; -180@638488801; -120@657147601; -180@669938401; -120@688597201; -180@701992801; -120@720046801; -180@733442401; -120@752101201; -180@764892001; -120@783550801; -180@796341601; -120@815000401; -180@827791201; -120@846450001; -180@859845601; -120@877899601; -180@891295201; -120@909349201; -180@922744801; -120@941403601; -180@954194401; -120@972853201; -180@985644001; -120@1004302801; -180@1017093601; -120@1035752401; -180@1049148001; -120@1067202001; -180@1080597601; -120@1099256401; -180@1112047201; -120@1130706001; -180@1143496801; -120@1162155601; -180@1174946401; -120@1193605201; -180@1207000801; -120@1225054801; -180@1238450401; -120@1256504401; -180@1269900001; -120@1288558801;
Jerusalem:
-180@39477601; -120@55371601; -180@71532001; -120@86821201; -180@102981601; -120@118875601; -180@134431201; -120@150325201; -180@165880801; -120@181774801; -180@197330401; -120@213224401; -180@228780001; -120@244674001; -180@260834401; -120@276123601; -180@292284001; -120@308178001; -180@323733601; -120@339627601; -180@355183201; -120@371077201; -180@386632801; -120@402526801; -180@418082401; -120@433976401; -180@450136801; -120@466030801; -180@481586401; -120@497480401; -180@513036001; -120@528930001; -180@544485601; -120@560379601; -180@575935201; -120@591829201; -180@607989601; -120@623278801; -180@639439201; -120@655333201; -180@670888801; -120@686782801; -180@702338401; -120@718232401; -180@733788001; -120@749682001; -180@765237601; -120@781131601; -180@797292001; -120@812581201; -180@828741601; -120@844635601; -180@860191201; -120@876085201; -180@891640801; -120@907534801; -180@923090401; -120@938984401; -180@955144801; -120@970434001; -180@986594401; -120@1002488401; -180@1018044001; -120@1033938001; -180@1049493601; -120@1065387601; -180@1080943201; -120@1096837201; -180@1112392801; -120@1128286801; -180@1144447201; -120@1159736401; -180@1175896801; -120@1191790801; -180@1207346401; -120@1223240401; -180@1238796001; -120@1254690001; -180@1270245601; -120@1286139601;
Minsk:
-180@39045601; -120@57790801; -180@70495201; -120@89240401; -180@101944801; -120@120690001; -180@133999201; -120@152139601; -180@165448801; -120@183589201; -180@196898401; -120@215643601; -180@228348001; -120@247093201; -180@259797601; -120@278542801; -180@291247201; -120@309992401; -180@323301601; -120@341442001; -180@354751201; -120@372891601; -180@386200801; -120@404946001; -180@417650401; -120@436395601; -180@449100001; -120@467845201; -180@481154401; -120@499294801; -180@512604001; -120@530744401; -180@544053601; -120@562194001; -180@575503201; -120@594248401; -180@606952801; -120@625698001; -180@638402401; -120@657147601; -180@670456801; -120@688597201; -180@701906401; -120@720046801; -180@733356001; -120@752101201; -180@764805601; -120@783550801; -180@796255201; -120@815000401; -180@828309601; -120@846450001; -180@859759201; -120@877899601; -180@891208801; -120@909349201; -180@922658401; -120@941403601; -180@954108001; -120@972853201; -180@985557601; -120@1004302801; -180@1017612001; -120@1035752401; -180@1049061601; -120@1067202001; -180@1080511201; -120@1099256401; -180@1111960801; -120@1130706001; -180@1143410401; -120@1162155601; -180@1174860001; -120@1193605201; -180@1206914401; -120@1225054801; -180@1238364001; -120@1256504401; -180@1269813601; -120@1288558801;

This technique is handy for helping to establish the identify of users who are attempting to mask their locations by using proxy servers alone. Different operating systems may also yield slightly different results enabling you to use this technique to fingerprint both their OS and location.

To give an idea of just how granular this method can be the above map from Wikipedia is partitoned into timezones that have been the same since 1970. Different colours indicate that the geographical areas timezone has deviated at least once.