To understand this, let’s get back to the basics.
The LOCATION attribute can be a:
- Relative Path: It is used to load JS files from the same origin e.g /js/script.js
- Absolute Path: e.g. hxxps://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js
1st Party/3rd party…4th party?
1st party: JS loaded from the same location as the webpage (e.g. webpage: hxxps://www.webpage.com and JS url: hxxps://www.webpage.com/assets/js/somescript.js )
3rd party: JS loaded from different location as the webpage is considered to be 3rd party (e.g. webpage: hxxps://www.webpage.com and JS url: hxxps://code.jquery.com/jquery-3.3.1.min.js )
3rd party JS can be further classified as:
- Statically loaded: these scripts are part of the HTML source code of the webpage as sent by the server
- Dynamically loaded (4th party): these script are loaded by statically loaded scripts during run-time
The Root of the Problem
Consider the following to understand the problem in a nutshell:
The following is a simple, crude version of an exploit that’s similar to the BA/NegEgg hack:
- html page loading an expected external JS script (1stOr3rdparty.js):
- External JS: 1stOr3rdParty.js. This script, hypothetically, originally contained the functionality needed by the webpage. However, later on, it got compromised, and a malicious piece of JS was injected in to it as shown below. The malicious code tries to steal the data, namely the username and password, that the user submits from the original webpage.
- This looks simple and straightforward – well, it is. The hardest part though is protecting against it.
Revisiting 1st party/3rd party:
If the location’s location is the same as where the script is hosted (e.g. British Airways and Newegg’s case), there are a few scenarios:
- The location itself was hacked. i.e. in case of British Airways, it appears that, the location where the website hxxps://www.britishairways.com is hosted was actually hacked:
Yes, a first party breach is very serious. While the attacker can do a lot more to compromise, infecting a JS is quite a sneaky way to steal customer data.
2. The location where modernizr was pulled from was breached:
3. One more possible scenario involves XSS vulnerability (not associated with BA/Newegg/Ticketmaster):
If the location of the external JS file has different origin as of the webpage:
What loads what….what?
The following scenarios depicts how complicated the system can get when 3rd party JS is loaded in to a webpage. Also, as an example and consideration, at the time of this blog, CNN’s homepage loaded scripts from 39 different locations.
Now if any of these locations are breached, the attackers can embed malicious code in to existing code content.
- Sub-resource Integrity (SRI): This standard essentially lets web developers include a hash of the code that will be included when the script resource is fetched. If the specified hash does not match with calculated hash when the code is fetched, the script is not allowed to execute. This is a way for the developer to ensure that the entrusted code is ran. Example:
<script src="https://example.com/example-framework.js" integrity="sha384-oqVuAfXRKap7fdgcCY5uykM6+R9GqQ8K/uxy9rx7HNQlGYl1kPzQho1wx4JwY8wC" crossorigin="anonymous"></script>
Note: SRI may not work well if there was a 1st party breach.
- Content Security Policy (CSP): This standard lets web developers generate a “whitelist” of locations from where resources can be loaded from (e.g. scripts, images), or locations where data can be sent to (e.g. forms, ajax etc). This is a great way to block any exploitation attempts against. Example policy (github):
Content-Security-Policy: default-src 'none'; base-uri 'self'; block-all-mixed-content; connect-src 'self' uploads.github.com status.github.com collector.githubapp.com api.github.com www.google-analytics.com github-cloud.s3.amazonaws.com github-production-repository-file-5c1aeb.s3.amazonaws.com github-production-upload-manifest-file-7fdce7.s3.amazonaws.com github-production-user-asset-6210df.s3.amazonaws.com wss://live.github.com; font-src assets-cdn.github.com; form-action 'self' github.com gist.github.com; frame-ancestors 'none'; frame-src render.githubusercontent.com; img-src 'self' data: assets-cdn.github.com identicons.github.com collector.githubapp.com github-cloud.s3.amazonaws.com *.githubusercontent.com; manifest-src 'self'; media-src 'none'; script-src assets-cdn.github.com; style-src 'unsafe-inline' assets-cdn.github.com
Note: CSP may not work well with 1st party breach.
In addition to these standards, IFRAME isolation with sandbox is another technique that can be very powerful. This technique is explained here.
- First party breaches can be tricky to handle because, by the nature of the attack, the attacker has finer control over the webpage content. The attacker can possibly change SRI hashes, as well as manipulate CSP policy.
- SRI hashes do not work in the following scenarios:
- If the end server where the script is server from, is not CORS enabled.
- If the code changes frequently or based on dynamic URL parameters.
- Hashes can only be enabled for scripts that are embedded by the developer of the website. However, enforcing SRI on scripts that are further loaded dynamically (4th party), won’t be possible by the developer. As we saw earlier, external JS loading is a web in itself, and the developer cannot guarantee that all the actors would enforce SRI.
- It is extremely challenging to constantly keep the policies up to date with ever so changing web application content. This definitely calls for a need for automation.
- Malicious domain gets whitelisted in CSP: vetting 3rd party domains can be a tricky task. Despite a good vetting process, there’s always a chance of a miss. If a malicious domain gets whitelisted, the attacks will be whitelisted too.
Contact us at firstname.lastname@example.org with feedback on the blog or how we can help you.