Akamai Diversity

Akamai Security Intelligence & Threat Research

Protecting Your Website Visitors from Magecart: Trust but Verify

There have been many news reports recently which outline how cyber criminals have successfully injected credit card skimming JavaScript code into the checkout process pages of various websites.  Dubbed Magecart, these attacks refer to a number of threat actors who are using similar tactics to skim customer data from e-commerce websites.

While Magecart is the current threat example, the larger threat is that of malicious JavaScript skimmer code. This blog post will provide some insights into skimmer attacks and offer mitigation options to prevent your site from being used as part of these attacks and to help protect your customers.

These mitigation options leverage Content Security Policy (CSP) response headers and Subresource Integrity (SRI) security features offered in modern web browsers.  In a previous blog post, I introduced Security Response Headers and briefly discussed CSP.  In this blog post, we will dive deeper into CSP and options that can help mitigate the Skimmer threat model.

Example 1: Inline JavaScript Skimmer

The first attack scenario we will discuss is if an attacker is able to inject malicious skimmer JavaScript directly inline into one of your web pages. This compromise could be achieved through Stored Cross-site Scripting (XSS) or some other web application vulnerability which allows the attackers to insert JavaScript code into the response data stream. Here is an example screenshot:

Example Inline JS Skimmer Code

The highlighted section of the HTML page shows the injected code. There is some simple obfuscation techniques used, such as base64 encoding, which attempts to hide the code's intentions and purpose. This code attempts to steal customer data and then send it off to a 3rd party URL shown in the following screenshot:

Data Exfiltration URL

There are many websites that are still currently compromised with this payload. The domain name used to exfiltrate the customer data is purposefully named to look like a Google domain and to try to blend in with normal traffic. If we inspect the URL on the urlscan.io website, we can see an example of what the data exfiltration URL looks like and what type of data is being passed in the "image_id" query_string parameter.

Urlscan.io Analysis Page

Example 1: Inline JavaScript Skimmer Defense

The primary defense against inline JavaScript attacks is using a CSP policy with the script-src directive.  

Disallow Inline JavaScript

If your web page should not have any inline JavaScript at all, then it is easy to prevent any rogue scripts from being executed by simply specifying:

Content-Security-Policy: script-src 'self'

This policy would only allow external JavaScript files to be referenced from the same host as the policy.  This would prevent the inline JavaScript skimmer code example from executing.

Allowing Inline JavaScript with CSP Nonces

If your web page has inline JavaScript that can not be refactored and externalized, then there is another CSP script-src mitigation option called nonce:

'nonce-<base64-value>'

A whitelist for specific inline scripts using a cryptographic nonce (number used once). The server must generate a unique nonce value each time it transmits a policy. It is critical to provide an unguessable nonce, as bypassing a resource's policy is otherwise trivial. See unsafe inline script for an example. Specifying nonce makes a modern browser ignore 'unsafe-inline' which could still be set for older browsers without nonce support.

The updated CSP policy header could look like this:

Content-Security-Policy: script-src 
'nonce-1182b04d9fA988B6EcD336EEfbe'

This would mean that any JavaScript in the page (both inline and/or externally referenced) would need to include a nonce attribute that matches the one from the CSP script-src sources list:

<script nonce="1182b04d9fA988B6EcD336EEfbe">
 var something = 1;
</script>

By adding the nonce source to the script-src directive, you could prevent the rogue inline JS skimmer code from executing while still allowing legitimate inline JavaScript code to function.  Firefox would generate a CSP error similar to the following in the console:

CSP nonce Violation Message in Firefox

While this certainly is an improvement in security, there is one limitation - we are not validating the contents of the JavaScript.  We are simply saying that data inside a script tag is allowed to run. What if we want to validate and whitelist exactly what code is allowed to execute?

Nonce Implementation Considerations

CSP nonce values must be unpredictable and change with every page invocation.  Google has some good information on this topic.  This scenario is a bit reminiscent of Cross-site Request Forgery (CSRF) mitigations using synchronizer tokens.  The main issue organizations need to figure out is how to add these CSP nonce values to the responses.  If you are using an application templating system such as Closure, you may be able to use it to add in the CSP nonces.  

Validating Inline JavaScript with CSP Hashes

If you want to increase security by validating the contents of inline JavaScript, then you can specify the hash option for script-src.

'<hash-algorithm>-<base64-value>'

A sha256, sha384 or sha512 hash of scripts or styles. The use of this source consists of two portions separated by a dash: the encryption algorithm used to create the hash and the base64-encoded hash of the script or style. When generating the hash, don't include the <script> or <style> tags and note that capitalization and whitespace matter, including leading or trailing whitespace. See unsafe inline script for an example. In CSP 2.0 this applied only to inline scripts. CSP 3.0 allows it in the case of script-src for external scripts.

Before specifying the actual hash value in a CSP header, you would first need to identify the proper hash value of the JavaScript code.  Let's say you wanted to create a hash of the following inline JavaScript code:

Example Inline JavaScript Code to Hash

There are many tools that can be used to create a hash of this content.  Report-URI has a handy web tool that will generate a hash of the content for you:

Script Hash Tool

Now that you have a proper hash of the script contents, you can update your CSP policy header to look like this:

Content-Security-Policy: script-src 

'sha256-qbkLHiRG75A4WIrn2wzD7RZfJeOXOiHCb80Vs2pjF5o='


Now your inline JavaScript snippet from the previous screenshot will be allowed to run.  Keep in mind the following:

  • All of the inline JavaScript code would need to have unique hashes calculated for them to properly execute.

  • Multiple hash values can be specified in the CSP header to allow for all script tags to work.

  • If any of the inline JavaScript code needs to legitimately change in the future then new hashes would need to be calculated.

  • If your script content is not static and may contain dynamic data, you might have to default back to using nonce instead.

There is an obvious security benefit in applying CSP hash validation to inline scripts, however this does come with some increased overhead and management to ensure proper functionality.  Keep in mind that for the scope of this blog post we are focusing on combating a specific threat - malicious skimmer code on checkout pages.  If you wanted to apply this CSP policy to a specific checkout page on your site, you could use Akamai's Property Manager to configure the desired behavior as shown in this screenshot:

CSP Behavior Logic in Property Manager

This example CSP behavior shows that our targeted policy will only be sent for a specific hostname and for a specific path location which corresponds with our checkpage where customers would be entering their credit card data.  Perhaps this is the only page on your website where you utilize CSP hashes. You could very well use different, easier CSP policies on the rest of your site or even none at all. If you start with a targeted CSP use-case and focus on securing your checkout pages then CSP hash management becomes feasible.  

Example 2: External JavaScript Skimmer

In the previous sections, we discussed inline malicious JavaScript code however that is not the only attack path being used by Magecart threat actors.  Let's take a quick look at an example URL with JavaScript skimmer code referenced on a 3rd party domain:

Example JS Skimmer Script Tag

In this example, there is a rogue JavaScript tag that calls in a remote JavaScript file from a 3rd party website.  Let's take a look at that page's contents.

Obfuscated JS Skimmer Code

This obfuscated code is similar in functionality to the previous inline version.  Do note the base64 decoded value I highlighted in the popup dialogue as it lists the 3rd party URL for data exfiltration.  It is using a similar technique of trying to blend in with the ReactJS domains. As a matter of fact, if you attempt to access the main URL it will redirect you to the React website.

Example 2: External JavaScript Skimmer Defense

Similar to inline JavaScript, the primary defense against external file reference attacks is using a CSP policy with the script-src directive.  

Specify All script-src Source Domains

What are all the authorized domains for your page to obtain JavaScript files from?  Akamai actually has products to help assist customers with this task and it is called Script Manager.   Here is an example dashboard graphic:

Script Management Dashboard

Important Note - Akamai customers must also include specific domains in the CSP policy to ensure proper functionality on any Akamai products they might be using.  For example, if you are using mPulse, you would need ensure that the proper Akamai domains are listed to support mPulse configuration downloads and data beaconing functionality.  

Once you have identified all authorized 3rd party script locations including Akamai mPulse domains, advertising and analytics
networks, you can then modify your CSP header like this:

Content-Security-Policy: script-src 'self' c.go-mpulse.net
s.go-mpulse.net *.mpstats.us *.akstat.io *.doubleclick.net
www.google-analytics.com

Now that you have a listing of all of the legitimate domains of script sources, CSP could easily block the execution of the example injection we saw previously to the billgetstatus.com domain.

Specify All script-src Source URLs

In the previous example, we whitelisted the authorized domains for 3rd party JavaScript.  This is a good first step for blocking these JavaScript skimmer attacks however it could be possible for an attacker to add a script on a 3rd party domain that you have whitelisted.  In this case, you could tighten up the CSP policy by specifying script sources down to the file level.

Let's say that you are using jQuery to interact with Google's APIs.  You could update your CSP header's script-src list to specify the exact URL for the jQuery version you are using like this:

Content-Security-Policy: script-src 'self'
 https://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js

This would only allow loading of that exact file over HTTPS versus whitelisting the entire ajax.googleapis.com domain.

Allowing External JavaScript with CSP Nonces

If you don't want to have to maintain a whitelist of all script-src sources in your CSP header, then you use nonce values as we covered in the previous section.  Remember, the CSP policy header could look like this:

Content-Security-Policy: script-src 'nonce-1182b04d9fA988B6EcD336EEfbe'

The externally referenced JavaScript call would need to include a nonce attribute that matches one from the CSP script-src sources list:

<script src="//ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js" nonce="1182b04d9fA988B6EcD336EEfbe"><script>

The presence of these nonce attributes that match the CSP header nonce value prevents the rogue 3rd party JavaScript calls from working.

Inheriting Trust for External JavaScript with CSP strict-dynamic

For anyone who has attempted to whitelist 3rd party JavaScript sources, you undoubtedly ran into the issue of those files calling up other files.  This cascading effect of interdependencies of files makes managing a CSP whitelist challenging. It is for this reason that CSP v3 introduced the concept of strict-dynamic.  

'strict-dynamic'

The strict-dynamic source expression specifies that the trust explicitly given to a script present in the markup, by accompanying it with a nonce or a hash, shall be propagated to all the scripts loaded by that root script. At the same time, any whitelist or source expressions such as 'self' or 'unsafe-inline' will be ignored. See script-src for an example.

The updated CSP policy header could now look like this:

Content-Security-Policy: script-src 'nonce-1182b04d9fA988B6EcD336EEfbe' 'strict-dynamic' 

Validating External JavaScript with SRI

If you want to validate the actual contents of external/3rd party JavaScript files, you would need to utilize a web browser feature called Subresource Integrity (SRI).  SRI allows you to validate the remote script contents by specifying an integrity attribute to your script calls.  Before using the attribute, however, you first need to calculate the proper hash of the file contents. This is a similar process that must be done with CSP hash usage.  Here is an example using cURL and openssl to calculate a sha384 hash:

$ curl -s https://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js | openssl dgst -sha384 -binary | openssl base64 -A 

lifoBlbdwizTl3Yoe612uhI3AcOam/QtWkozF7SuiACaf5UJl5reOYu4MigVxrCH
 


Now that you have a proper hash, you can use it in the integrity script attribute like this:

<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js" integrity="sha384 lifoBlbdwizTl3Yoe612uhI3AcOam/QtWkozF7SuiACaf5UJl5reOYu4MigVxrCH" crossorigin="anonymous"></script>


With SRI now activated for this remote JavaScript resource, if the contents of that file ever change it will be blocked by the browser.  Let's take a look at SRI in action. Let's pretend that a Magecart attacker was somehow able to modify that jquery.min.js file to injection their JavaScript skimmer code as shown in the highlighted portion of this Burp proxy screenshot:

 

Simulated JavaScript Skimmer Code Injected into jquery Data

When the Firefox web browser receives this response, it will check the SRI integrity value, block the code from running and will generate the following error in the console:

SRI Hash Validation Error Message

Requiring SRI for External JavaScript

SRI is great for validating file content integrity.  The only problem is this - what if an attacker finds a way to sneak a new JavaScript call onto the page that does not have the SRI integrity attribute specified?  In this case, we can combine the power of CSP and SRI together with a new CSP directive called require-sri-for.  For example, here is an updated CSP policy:

Content-Security-Policy: script-src 'self' https://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js; require-sri-for script

This is a great feature for ensuring that all scripts on the page have SRI enforced, however there is one current limitation.  Although most modern browsers support this feature, it isn't actually shipped yet and enabled. Browser compatibility shows that end users must enable experimental feature options in their browsers for this to work.

Browser Support for require-sri-for option

Here is a screenshot of Firefox about:config showing CSP experimental features are disabled by default.

Firefox Configuration

Same goes for Chrome chrome://flags/#enable-experimental-web-platform-features:

Chrome Configuration

Until such a time as the browser vendors decide to actually ship these features and enable them, require-sri-for will not be enforced.  That is except for those advanced users that have these features enabled.  This doesn't mean that you should not use this feature. You should enable it now and when browsers start supporting the feature by default it will be enforced.

Data Exfiltration Defense

In the previous sections, we discussed different vectors used by Magecart-type attackers to inject their JavaScript skimmer code into websites.  We also covered many different options using CSP and SRI to help mitigate these attacks. Don't forget about the the data exfiltration component of this attack sequence!  Getting their JavaScript skimmer code injected into checkout pages doesn't do any good if the final step of exfiltrating the customer's sensitive data off to the attacker's site is not successful.

Important Note - There is much debate in the academic and practitioner communities around the effectiveness of CSP to prevent data exfiltration.  We are not proposing that CSP can be used as a panacea for all data exfiltration techniques.  The approach that follows is to outline current Magecart modus operandi tactics for data exfiltration and to show how CSP can be used to limit their effectiveness.  

Exfiltration with XMLHttpRequest (XHR)

In the case of the Newegg Magecart compromise, the attackers used the following XHR code to send the captured customer data off to their domain:

Newegg Magecart Code

 Controlling XHR with CSP connect-src

CSP v3 connect-src can control the following script interface APIs:

  • <a> ping

  • Fetch

  • XMLHttpRequest

  • WebSocket

  • EventSource

If you know that your checkout page should never be using any of these features, then use the following directive:

Content-Security-Policy: connect-src 'none' 

This would prevent the Magecart code from being able to initiate one of these connection types to send snarfed data off to the attackers.

Exfiltration with Image() Constructor

Another sneaky method of sending captured data off to the attacker's site is to use Image fetching functionality.  Here is an example showing the use of the Image() constructor:

JavaScript Skimmer Code Using Image Constructor

Why would an attacker use this mechanism?  Organizations might not be prioritizing controlling Image downloads and may therefore have left open this gap that attackers can use as a method of data exfiltration.  If you know that your checkout page should only be calling image files from your own domain, then use the following directive:

Content-Security-Policy: img-src 'self'

This CSP directive would have prevented the JavaScript skimmer code from using an Image call to exfiltrate data.

CSP Violation Reporting

Implementing these CSP + SRI controls is the top priority for preventing Magecart attacks and protecting your website visitors.  A close second priority is receiving CSP violation report telemetry. Oftentimes organizations who are implementing CSP use reporting during the initial testing phases but then will disable it for normal operation.  This is unfortunate as this capability is critical for being able to quickly identify outbreaks of new attacks against your customers. CSP reporting is controlled via the report-uri or report-to (CSP v3) directives.

Akamai customers can use Property Manager to set these CSP headers as discussed previously.  In this screenshot, we show adding a CSP header with a report-uri directive that points back on-domain so that any violation reports sent by clients will come back through the Akamai platform.

 

Property Manager Showing CSP Header Configuration

Another point to highlight here is the use of Property Manager built-in variables.  In this case, I am using the AK_REQUEST_ID variable inside a query_string parameter of report-uri.  I am doing this so that when the CSP header is set, Property Manager will dynamically add in the request ID that the Akamai Edge platform has assign to this unique transaction to the CSP header.

 

CSP Header Includes Request ID Data

This data can be useful when analyzing CSP violation report data if you need to trace back requests on Akamai's platform.

Enable CSP Violation Report Rules in Kona Site Defender (KSD)

KSD customers can enable a new rule that will identify and report on CSP violation reports that are configured to come back to the Akamaized customer domain.

New KSD Rule for CSP Report Alerting

Notice the different rule options that are available.  Keep in mind - these rule actions are being applied to CSP violation reports that are being sent from the web client as defined by report-uri or report-to directive in the CSP response header.  If you already have CSP reporting configured to send violation telemetry back to Origin and you would simply like to additionally log violation report data in KSD, you can set the rule to Alert.  If, however, you would like for KSD to act as an actual CSP report-uri endpoint, you can configure the rule to Deny. This would stop the CSP violation report at our Edge platform and not forward it into Origin.  Regardless of whether you choose Alert or Deny, KSD reporting will start capturing events when a CSP violation report is observed at the Edge.

Analyze CSP Violation Reports in Web Security Analytics (WSA)

Once the previous rule is activated and CSP violation reports start coming in, you will be able to view them in the WSA dashboard.

CSP Violation Reports in WSA

Conclusion

The purpose of this blog post was to outline the common vectors used by JavaScript skimmer attackers and how organizations could leverage Content Security Policy and Subresource Integrity policies to help protect their websites and customers.  I am also wanted to show how Akamai customers could use our Kona Site Defender platform to help implement these mitigations and also to monitor telemetry received from end users. If you are an Akamai customer and would like to discuss these topics in depth, please contact your Akamai representative.  

 

Leave a comment