gorhill / httpswitchboard

Point & click to forbid/allow any class of requests made by your browser. Use it to block scripts, iframes, ads, facebook, etc.
GNU General Public License v3.0
1.33k stars 84 forks source link

Front page on www.tsn.ca goes blank when user agent spoofing is enabled #261

Closed gorhill closed 10 years ago

gorhill commented 10 years ago

As per http://www.wilderssecurity.com/threads/http-switchboard-for-chrome-chromium.356427/page-27#post-2369931:

Last night i discovered a problem with the following website: -www.tsn.ca It does not like the httpsb extension. The webpage initially loads the graphics but then goes all white! The only fix I could find was if I disable httpsb extension; disabling Matrix filtering won't even fix it [...] It looks like I found the problem; when I clear the checkbox for "Spoof User-Agent string by randomly picking a new one below every 15 minutes" the website will load normally

My findings:

In order to fix issue #252, I had to create a fake window.navigator object. But this was really tedious, as it appeared that my fake navigator object was trashed by the browser at some point when the page was loading. To prevent this, I freeze the fake navigator object, which means that nobody can change it. tsn.catries to add a property to the object, which fails, and which results in the failure of the whole page

gorhill commented 10 years ago

Looks like freezing the fake window.navigator is not necessary. I had to create many prototypes until I got it right, so apparently I came to think freezing the object was needed while it is not.

gorhill commented 10 years ago

It will take time to investigate, it's failing somewhere else and I have to find where in this maze of javascript.

my-password-is-password commented 10 years ago

Try adding ||www.tsn.ca/scripts/min/hub/foot/139748129.js to blocked rules in Ubiquitous rules.

Its some tracking stuff that calls trackPage() in the file http://www.tsn.ca/scripts/min/hub/head/139748129.js

function trackPage() {
        s.events = "";
        if (s.linkTrackVars && s.linkTrackVars.length && s.linkTrackVars.length >= 1 && s.linkTrackVars.substring(0, 1) == ",") {
            s.linkTrackVars = s.linkTrackVars.substring(1);
        }
        if (s.linkTrackEvents && s.linkTrackEvents.length && s.linkTrackEvents.length >= 1 && s.linkTrackEvents.substring(0, 1) == ",") {
            s.linkTrackEvents = s.linkTrackEvents.substring(1);
        }
        if (s.events && s.events.length && s.events.length >= 1 && s.events.substring(0, 1) == ",") {
            s.events = s.events.substring(1);
        }
        autoSetHierarchy();
        setBdu();
        var s_code = s.t();
        if (s_code) {
            document.write("<div style='display: none; margin: 0; padding: 0; height: 0; overflow: hidden;'>" + s_code + "</div>");
        }

s_code is the tracking image when the page goes blank. Inspect the page and you can see its the same html code from that function.

I'm not sure if blocking that .js file breaks the rest of the page though.

gorhill commented 10 years ago

It doesn't seem to have anything to do with HTTTPSB

I don't know, when I disable UA spoofing, the page doesn't go blank, so clearly somewhere in there, HTTPSB spoofing cause the page to fail, and it could be that one of the property in navigator.useragent is not properly emulated.

It's nice though that you found a workaround, I will pass it on to the user at Wilder Security.

my-password-is-password commented 10 years ago

Theres a difference in appVersion, the ua spoof starts off with "Mozilla/5.0 ..." while when spoof is off the appVersion starts with just "5.0 ...".

[ SpoofedNavigator ]
appCodeName: "Mozilla"
appName: "Netscape"
appVersion: "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/33.0.1750.154 Safari/537.36"
cookieEnabled: true
doNotTrack: "1"
geolocation: Geolocation
getStorageUpdates: function () { return this.navigator[k].apply(this.navigator, arguments); }
javaEnabled: function () { return this.navigator[k].apply(this.navigator, arguments); }
language: "en-US"
mimeTypes: MimeTypeArray
navigator: Navigator
onLine: true
platform: "Win32"
plugins: PluginArray
product: "Gecko"
productSub: "20030107"
registerProtocolHandler: function () { return this.navigator[k].apply(this.navigator, arguments); }
sayswho: "Chrome 33.0.1750.154"
userAgent: "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/33.0.1750.154 Safari/537.36"
vendor: "Google Inc."
vendorSub: ""
[ Navigator ]
appCodeName: "Mozilla"
appName: "Netscape"
appVersion: "5.0 (Windows NT 5.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/34.0.1847.137 Safari/537.36"
cookieEnabled: true
doNotTrack: "1"
geolocation: Geolocation
language: "en-US"
mimeTypes: MimeTypeArray
onLine: true
platform: "Win32"
plugins: PluginArray
product: "Gecko"
productSub: "20030107"
sayswho: "Chrome 34.0.1847.137"
userAgent: "Mozilla/5.0 (Windows NT 5.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/34.0.1847.137 Safari/537.36"
vendor: "Google Inc."
vendorSub: ""

Heres some code from one of the js file from the site that causes the problem. It does parseFloat() on the appVersion.

s.n = navigator;
s.u = s.n.userAgent;
s.ns6 = s.u.indexOf('Netscape6/');
var apn = s.n.appName,
    v = s.n.appVersion,
    ie = v.indexOf('MSIE '),
    o = s.u.indexOf('Opera '),
    i;
if (v.indexOf('Opera') >= 0 || o > 0)
    apn = 'Opera';
s.isie = (apn == 'Microsoft Internet Explorer');
s.isns = (apn == 'Netscape');
s.isopera = (apn == 'Opera');
s.ismac = (s.u.indexOf('Mac') >= 0);
if (o > 0)
    s.apv = parseFloat(s.u.substring(o + 6));
else if (ie > 0) {
    s.apv = parseInt(i = v.substring(ie + 5));
    if (s.apv > 3)
        s.apv = parseFloat(i)
} else if (s.ns6 > 0)
    s.apv = parseFloat(s.u.substring(s.ns6 + 10));
else
    s.apv = parseFloat(v);   <------- is NaN when ua spoof is on, is 5 when ua spoof is off

then there's a check later on using s.apv,

if (s.d.images && s.apv >= 3 && (!s.isopera || s.apv >= 7) && (s.ns6 < 0 || s.apv >= 6.1)) {
...
  return ''
}
return '<im' + 'g sr' + 'c="' + rs + '" width=1 height=1 border=0 alt="">'

When its true ( spoof off ) it returns '' for s_code ,in the code from my last post, and doesn't do the document.write.

When its false ( spoof on ) it returns the tag for s_code and it does the document.write.

Should it be something like spoofedNavigator.appVersion = spoofedUserAgent.substr(spoofedUserAgent.indexOf('/')+1); in contentscript-uaspoof.js ?

gorhill commented 10 years ago

Wow thanks for the help, this really saves me a lot of time. Now I have to look for the best fix, which apparently is to just find the first string segment which starts with a digit, as per http://www.whatwg.org/specs/web-apps/current-work/multipage/timers.html#dom-navigator-appversion

gorhill commented 10 years ago

Code above doesn't work with many of the listed UA here. Ok I will use the /, and ultimately it is up to the user to enter UA strings which are common (that's the point of spoofing), and apparently the common ones always include the / separator as you pointed out.

my-password-is-password commented 10 years ago

What if you do a parseFloat() first and then if its NaN you look for /? And if it is a float return the whole string? That would work on the example you post earlier. 1.0 (VMS; en-US) Mellblomenator/9000.

Right?

gorhill commented 10 years ago

Nah, / is fine in the end given the purpose of UA spoofing in HTTPSB. The example at whatwg.org is for the value of appVersion, not the whole UA string. I think they just want to show that it can be more than just a version number, it can a version number and then a whole lot of other stuff following.