Barclays Online Banking gives 3rd Parties access to login pages

Banks aren't exactly known for living on the bleeding edge - even where good security practice moves on, they tend to be years behind. For better or worse, they lean toward preferring stability and consistency over chasing the latest and greatest.

However, this issue doesn't really fall under that traditional niche of "well, banks will be banks".

Barclays bank (and others) are giving 3rd party scripts access to their Internet Banking login pages - the result is that a compromise or mistake at their supplier could compromise their customer's login credentials.

I highlighted this issue a few months back, and Barclays replied with "deliberate, not an issue" (paraphrasing a bit there), so I'm now getting around to writing it up.

 

The user visible issue

I stumbled on this because the way in which they've implemented this behaviour is also fairly fragile.

My adblocker was (IMO correctly) blocking the third party domain, but this resulted in the login form locking up for about 30s whilst it's attempt to submit stats timed out.

So, I created a screencast to help explain the issue and sent it over to Barclays.

If we ignore the security aspect for a second, the developer part of me is also riled.

They're failing to sanely handle circumstances where their request fails - this is the internet, a proportion of requests fail all the time - and locking the browser session up. Security or not, it's bad code.

 

Barclays say no

Barclay's social media team were very approachable, and helpful.

Unfortunately, it's (obviously) not their remit to fix stuff like this, so they escalated to the web team, who paid lipservice to the report.

They have said that the ad blocker could be causing the issues. Can you turn off all analytics using your cookie preferences, and then change your ad blocker to allow our online banking website and all other sites. We use some additional sites such as (the http://we-stats.com that could be getting blocked) to help us protect and monitor your account.

Not only does the video note that it's my adblocker blocking it, so does the text I sent with it.

Getting an initial report rebuffed with absolute nonsense is  - unfortunately - not uncommon, so I pushed back

Twitter conversation with Barclays

The bit that really matters security wise is

so if they get compromised - and it does happen, just look at the Solarflare stuff hitting the fan at the moment - that's my credentials compromised

Although, honestly, I'd have settled for them just fixing their JS so that the page doesn't block.

That final request (being able to speak direct to someone) was ultimately rejected.

The web-teams explanation was that we-stats does "biometric fingerprinting" in order to try and spot trends and block fraudulent logins

Thanks for getting back to us again Ben. The team have advised the tool that we use (the http://we-stats.com that you're blocking) builds up a behavioural biometric of your use of online banking, and so if anyone else ever tries to access his login, that tool will help to spot and block them. It’s all there for your protection.

...

Bollocks

Let's just examine that claim for a minute:

if anyone else ever tries to access his login, that tool will help to spot and block them

That's a nice thing to say, but it's demonstrably not actually true.

Between the video above and conversations with Barclays, we've established that my adblocker is blocking their tool. And yet, crappy coding aside, I'm still able to login to my account.

If someone gets my credentials, then, it doesn't matter whether their tool has built up a "behavioural biometric" of my use or not because it can be prevented from acting:

  1. Alice logs into Barclays regularly, and doesn't block anything
  2. Alice accidentally leaks her creds (via a phishing page, or whatever)
  3. Bob has Alice's creds
  4. Bob goes to the Barclays login page, but blocks third party domains
  5. Bob logs in and raids Alice's savings

The system is supposed to offer protection at step 4 (preventing Bob from logging in), but Bob has prevented the system from running.

As a result, the company behind we-stats have built up a detailed biometric profile of Alice for no good reason.

The system, as described is fundamentally flawed because it relies on  client-side enforcement.

 

GDPR?

I don't pretend to be an expert in GDPR compliance, but at this point I was sufficiently motivated to go and do some digging.

Twitter Convo with Barclays 2 (summarised in text)

There seems to have been some effort put into keeping the owner of we-stats.com anonymous, but with a bit of sleuthing around the internet, it looks like it's owned by Biocatch.

The message above does contains an inaccuracy: Biocatch are Israeli rather than American.

The underlying point, though, remains the same - they're a non-EU company, and Barclays GDPR statement doesn't seem to make any reference to them or the services they're providing - presumably because they've decided to ignore the transparency that GDPR was supposed to bring and instead write

Our service providers and agents (including their subcontractors). This may include, for example, third-party collection agents we use, or where we pass your details to someone who will print your statements, deliver a gift or provide a gesture of goodwill

I took one last shot, asking the social media team to send the web-team a link to my ticket (MISC-45) in case something was perhaps being miscommunicated somewhere along the line, within that ticket I added a comment to try and lay out the issue as well as suggest a mitigation

Comment on MISC-45 (link leads there)

Ultimately, the team responded to reiterate that

that we use (the http://we-stats.com that you're blocking) builds up a behavioural biometric of your use of online banking, and so if anyone else ever tries to access his login, that tool will help to spot and block them.

So, not only were they happy to leave a gaping hole, they weren't going to fix the bit that had been bugging me either (don't want to wait 30s to enter text into a field? turn your adblock off mate...).

The social media team suggested that the only way to escalate it further would be to raise a complaint.

So, I went to Barclay's complaint form... which hung, because I was blocking we-stats. Once I was able to enter text, I still had to keep the text of the complaint brief, because Barclays have implemented a character limit of 2000 chars (I'm sure that doesn't cause any issues with complex complaints...).

Nothing has come of that complaint since.

Which is perhaps unsurprising: The domain we-stats.com was added to the EasyPrivacy adblock list 2 years ago - which presumably means that Barclays have been breaking user's login flow for 2 years.

 

Sub Resource Integrity (SRI)

Having 3rd party scripts on the same page as a login form is never good, but there are mitigations that can be applied.

One of these is using Sub Resource Integrity (SRI) when referencing scripts etc.

With SRI, you specify the checksum of the file you're referencing - the browser then fetches the resource, and if the checksum doesn't match then it'll refuse to load it. So, if someone compromises your supplier (the 3rd party) and changes scripts, your users don't get compromised (as their browser will refuse to run the script).

Barclays are not using SRI for their we-stats related stuff, but clearly have heard of it as evidenced by this fairly ugly snippet

           window.utag_cfg_ovrd = window.utag_cfg_ovrd || {};
            window.utag_cfg_ovrd.dom_complete = true;
            window.utag_cfg_ovrd.noview = true;
            (function(a,b,c,d){
                a='https://tags.tiqcdn.com/utag/barclaysuk/barclays-olb/PROD-C/utag.js';
                if (true === true) {
                    b=document;c='script';d=b.createElement(c);d.src=a;d.type='text/java'+c;d.async=true;d.integrity='sha256-T3f8dCQeu5ho0tgq44nodCaM8vjO/wlUHW+WM2PBvyU=';d.crossOrigin='anonymous';
                } else {
                    b=document;c='script';d=b.createElement(c);d.src=a;d.type='text/java'+c;d.async=true;
                }
                a=b.getElementsByTagName(c)[0];a.parentNode.insertBefore(d,a);
            })();

What they're doing here is building a reference out to a tagging/analytics service - presumably the obfuscation is there to try and prevent people from blocking it.

The result of this function is the addition of the following to the page head.

<script src="https://tags.tiqcdn.com/utag/barclaysuk/barclays-olb/PROD-C/utag.js" type="text/javascript" async="" integrity="sha256-T3f8dCQeu5ho0tgq44nodCaM8vjO/wlUHW+WM2PBvyU=" crossorigin="anonymous"></script>

That's it - of all the scripts they're loading, the only one using SRI is a tagging service...

TiqCDN, incidentally, are operated by Tealium - who offer enterprise tracking and analytics - that's another 3rd party with access to the login form then.

Or Not

However, even this example of good practice is an illusion, because utag.js adds an external JS file to the DOM without SRI

a.src+=(a.src.indexOf('?')>0?'&':'?')+'utv='+(a.v?utag.cfg.template+a.v:utag.cfg.v);utag.rpt['l_'+a.id]=a.src;b=document;this.f[a.id]=0;if(a.load==2){utag.DB("Attach sync: "+a.src);a.uid=a.id;b.write('
<script id="utag_'+a.id+'" src="'+a.src+'"></scr'+'ipt>')

So, whilst Barclays customers are protected from compromise of the file utag.js they are not protected from compromise of the JS files it then goes on to reference.

Running with adblock disabled shows that

  • the script that's called is tags.tiqcdn.com/utag.v.js?[identifier string]
  • utag.v.js is 2byte response body (//)

The request is clearly used to submit information via the querystring, but if an attacker were able to manipulate the response, the browser would execute it as with any other script - they could have achieved exactly the same by using a tracking pixel.

What makes it especially laughable, though, is that the value appears to be static (two slashes) - even if there was a reason they need it to be a script, they could trivially have included a SRI hash when adding the <script> tag to the DOM.

 

Content Security Policy (CSP)

Barclays do implement CSP headers, which helps limit the level of mischief that could be achieved by compromising a script.

default-src *
 worker-src 'self' blob: 
 object-src 'self' blob: 
 child-src blob: 
 frame-src *.krxd.net *.intranet.barcapint.com:* *.barclays.intranet *.barclays.co.uk *.barclays.com https://h.online-metrix.net https://barclays-pr-staging.grgtest.co.uk https://www.barclayspremierrewards.co.uk barclayload: rolbdss-v3.uk.barclays
 style-src 'self' *.barclays.co.uk https://barclaysbankplc.tt.omtrdc.net https://stags.bluekai.com https://tags.bluekai.com https://contentukbarclays-test63-barclays.adobecqms.net https://contentukbarclays-test-barclays.adobecqms.net https://contentukbarclays-test-blue-barclays.adobecqms.net https://www.barclays.mobi 'unsafe-inline' *.intranet.barcapint.com:* *.barclays.intranet rolbdss-v3.uk.barclays https://tags.tiqcdn.com https://collect.tealiumiq.com
 script-src 'self' *.barclays.co.uk https://barclaysbankplc.tt.omtrdc.net https://stags.bluekai.com https://tags.bluekai.com *.krxd.net https://h.online-metrix.net 'unsafe-inline' 'unsafe-eval' eval barclayload: *.intranet.barcapint.com:* *.barclays.intranet rolbdss-v3.uk.barclays https://tags.tiqcdn.com https://collect.tealiumiq.com
 img-src 'self' blob:  data:  *.barclays.co.uk https://adservice.google.com https://4482330.fls.doubleclick.net https://5452834.fls.doubleclick.net https://aax-eu.amazon-adsystem.com https://ad.doubleclick.net https://adfarm.mediaplex.com https://altfarm.mediaplex.com https://eu-gmtdmp.gd1.mookie1.com https://gb-gmtdmp.mookie1.com https://googleads.g.doubleclick.net https://ib.adnxs.com https://pixel.quantserve.com https://pubads.g.doubleclick.net https://secure.adnxs.com https://sp.analytics.yahoo.com https://t.mookie1.com https://www.facebook.com https://www.googleadservices.com https://stags.bluekai.com https://tags.bluekai.com https://cdn.krux.net https://tlg.mookie.com http://idsync.rlcdn.com https://idsync.rlcdn.com http://r.nexac.com https://r.nexac.com http://kr.ixiaa.com https://kr.ixiaa.com http://d.agkn.com https://d.agkn.com http://aa.agkn.com https://aa.agkn.com http://usermatch.krxd.net https://usermatch.krxd.net http://beacon.krxd.net https://beacon.krxd.net http://r.dlx.addthis.com https://r.dlx.addthis.com http://e.visualdna.com https://e.visualdna.com https://barclaysbankplc.tt.omtrdc.net https://h.online-metrix.net https://contentukbarclays-test63-barclays.adobecqms.net https://contentukbarclays-test-barclays.adobecqms.net https://contentukbarclays-test-blue-barclays.adobecqms.net https://www.barclays.mobi *.intranet.barcapint.com:* *.barclays.intranet rolbdss-v3.uk.barclays https://tags.tiqcdn.com https://collect.tealiumiq.com

Whilst it's good that an attempt has been made to limit things, the inclusion of unsafe-eval and unsafe-inline doesn't exactly instil confidence.

Barclays have also missed a trick here - having a CSP is one thing, but it's a lot more useful if you monitor its enforcement -  you want to know if/when something that violates the CSP occurs.

The report-to (previously report-uri) directive exists to allow monitoring CSP and can be used as an early warning that you've introduced a cross-site scripting vuln, or perhaps added a resource without updating your CSP.

The information submitted is fairly well constrained:

{
  "csp-report": {
    "document-uri": "https://foo.example.com/somepage",
    "referrer": "",
    "violated-directive": "script-src-attr",
    "effective-directive": "script-src-attr",
    "original-policy": "default-src 'self'; script-src 'report-sample' 'self' https://www.google-analytics.com/analytics.js https://www.googletagmanager.com/gtag/js; style-src 'report-sample' 'self'; report-uri https://demo.endpoint.invalid;",
    "disposition": "enforced",
    "blocked-uri": "inline",
    "line-number": 1,
    "source-file": "https://some.evil.script/",
    "status-code": 0,
    "script-sample": "dobad(document)"
  }
}

So whilst some care is still needed, it's use is still much lower risk than embedding random 3rd party resources.

 

Working Example

Getting back to we-stats.com though, for those wondering what it does when it's not blocked - the answer is it chats a lot.

We Stats submissions

We can see too, that once up and running, requests start being made to a logging domain - logs-6bb5a42d.eu.v2.we-stats.com

Comms to and from both endpoint are themselves obfuscated.

A quick de-obfuscation of the calling code shows that they've include a zlib library, though even after de-base64'ing it doesn't look like zlib. The script's >6000 lines long, so I gave up looking.

Ultimately, they're tracking when and where you click - from reading Biocatch's literature it looks like one of the things they're trying to gauge is whether you know your way around the interface. You'd hope that they're not capturing the contents of form fields, or keypresses, but there's no way to verify (and mistakes do happen).

 

Mitigation

Barclays obviously feel they need to use we-stats.com in order to protect their customers. So, in the spirit of that, let's be fairly explicit about what they could fix to help achieve that and mitigate risk

  • Don't trigger we-stats on pages where secrets are entered (i.e. login pages)
  • Use SRI to ensure that a change to referenced assets isn't a show-stopper for security - ensuring 3rd party providers are using it properly too
  • Rework and fix things so that Content Security Policy no longer needs unsafe-eval and unsafe-inline
  • Use report-to to monitor the effectiveness of CSP, gaining an early indicator of potentially serious issues.
  • Fix the codebase so that a failure to communicate with we-stats doesn't block the page
  • Update the GDPR policy to include some transparency on what the service is collecting

 

Conclusion

I'll start by saying that I'm picking on Barclays a bit here - they're not the only ones using we-stats. I found evidence on the net that Natwest and Halifax have previously used it. I would point out though, that despite having an account with them, I never noticed Natwest's use because my adblocker blocking it didn't lock up the interface.

Banks have a hard balance to strike, they need to try and ensure account security without overstepping the bounds of usability. Banking, of course, has always been notably conservative around new technology.

But, the sad truth is that Barclays have really screwed the pooch here.

  • Third party services/resources are used on login pages
  • This is partly in order to offer account take-over protection - except that protection can be circumvented by the very people the technology is supposed to protect from
  • The way the technology has been integrated is questionable, leading to pages blocking if the XHR requests fail
  • There's only a single use of Sub-Resource Integrity, except that the referenced script then immediately undermines it by referencing additional scripts without SRI.
  • The tagging/analytics provider inexplicably uses an "empty" javascript file rather than a safer alternative
  • Content-Security-Policy is used but is undermined by the use of various unsafe- options
  • The effectiveness of their CSP header is completely unmonitored due to lack of report-uri/report-to - if someone finds an XSS vuln, they've lost a valuable early warning mechanism
  • GDPR compliance in this area seems questionable to me

If their stated aim is to improve security, then unfortunately they've missed the goal more than a few times.

What they seem to have done, is invest in security theatre (they've previous form for that too) taking on board a whole load of complexity for little tangible gain. The outcome of complexity is almost always that people find gaps to slip through.

Having said all of this, the bit that still annoys me is Barclay's initial response.

Any sane developer should consider "your page locks up if..." as a bug. It doesn't matter why the request for the resource is failing (this is the internet and you should expect that requests will fail and/or be blocked - especially if you're referencing known trackers), locking a page up is never an acceptable outcome.

 

 
 Share