Protecting Your Website Visitors from Magecart
Many news reports have outlined how cybercriminals 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.
Although 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, I will dive deeper into CSP and the options that can help mitigate the skimmer threat model.
Example 1: inline JavaScript skimmer
The first attack scenario 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 or some other web application vulnerability that allows the attackers to insert JavaScript code into the response data stream (Figure 1).
The highlighted section of the HTML page shows the injected code. There are 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 third-party URL (Figure 2).
The domain name used to exfiltrate the customer data is purposefully named to look like a Google domain and 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 (Figure 3).
Inline JavaScript skimmer defense
The primary defense against inline JavaScript attacks is the use of 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 JavaScript skimmer code from executing while still allowing legitimate inline JavaScript code to function. Firefox would generate a CSP error similar to Figure 4 in the console.
Although 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 the data inside a script tag is allowed to run. What if we want to validate and allowlist exactly which 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 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 inline JavaScript code in Figure 5.
There are many tools that can be used to create a hash of this content. Report-URI has a handy web tool (Figure 6) that will generate a hash of the content for you.
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 have 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, but this does come with some increased overhead and management to ensure proper functionality. Keep in mind that for the scope of this blog post I am 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 Property Manager to configure the desired behavior as shown in Figure 7.
This example CSP behavior shows that our targeted policy will only be sent for a specific hostname and for a specific path location that 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, I discussed inline malicious JavaScript code, but 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 third-party domain (Figure 8).
In this example, there is a rogue JavaScript tag that calls in a remote JavaScript file from a third-party website. Let’s take a look at that page’s contents in Figure 9.
This obfuscated code is similar in functionality to the previous inline version. Please note the base64 decoded value I highlighted in the pop-up dialog box as it lists the third-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.
External JavaScript skimmer defense
Similar to the defense against inline JavaScript, the primary defense against external file reference attacks is the use of 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 a product to help assist customers with figuring this out and it is called Script Manager. Figure 10 shows an example dashboard graphic.
Important note: If you are an Akamai customer, you must also include specific domains in the CSP policy to ensure proper functionality on any Akamai products you might be using. For example, if you are using mPulse, you would need to ensure that the proper Akamai domains are listed to support mPulse configuration downloads and data beaconing functionality.
Once you have identified all authorized third-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 the legitimate domains of script sources, CSP could easily block the execution of the example injection we saw in Figure 8 to the billgetstatus.com domain.
Specify all script-src source URLs
In the previous example, we allowlisted the authorized domains for third-party JavaScript. This is a good first step for blocking these JavaScript skimmer attacks, but it could be possible for an attacker to add a script on a third-party domain that you have allowlisted. 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 allowlisting the entire ajax.googleapis.com domain.
Allowing external JavaScript with CSP nonces
If you don’t want to have to maintain an allowlist of all script-src sources in your CSP header, then you can use nonce values as I 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 third-party JavaScript calls from working.
Inheriting trust for External JavaScript with CSP strict-dynamic
Anyone who has attempted to allowlist third-party JavaScript sources has undoubtedly run into the issue of those files calling up other files. This cascading effect of interdependencies of files makes managing a CSP allowlist 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/third-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 similar to the 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, the file will be blocked by the browser. Let’s take a look at SRI in action and pretend that a Magecart attacker was somehow able to modify that jquery.min.js file to inject their JavaScript skimmer code as shown in the highlighted portion of the Burp proxy screenshot in Figure 11.
When the Firefox web browser receives this response, it will check the SRI integrity value, block the code from running, and will generate the error in the console seen in Figure 12.
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 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, but 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 (Figure 13).
Figure 14 shows a screenshot of Firefox about:config where CSP experimental features are disabled by default.
Same goes for Chrome chrome://flags/#enable-experimental-web-platform-features (Figure 15).
Until the browser vendors decide to actually ship these features and enable them, require-sri-for will not be enforced, with the exception of 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, I discussed different vectors used by Magecart-type attackers to inject their JavaScript skimmer code into websites. I also covered many different options using CSP and SRI to help mitigate these attacks. But don’t forget about 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 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. I am not proposing that CSP can be used as a panacea for all data exfiltration techniques. The approach that follows outlines current Magecart modus operandi tactics for data exfiltration and shows 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 XHR code in Figure 16 to send the captured customer data off to their domain.
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:
Why would an attacker use this mechanism? Organizations may not be prioritizing controlling image downloads and, therefore, may 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 plus 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. Organizations that are implementing CSP often 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. Figure 18 shows 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.
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 Intelligent Edge Platform has assigned to this unique transaction to the CSP header (Figure 19).
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
Kona Site Defender customers can enable a new rule that will identify and alert them to CSP violation reports that are configured to come back to the Akamaized customer domain (Figure 20).
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 Kona Site Defender, you can set the rule to Alert. If, however, you would like for Kona Site Defender 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 onto origin. Regardless of whether you choose Alert or Deny, Kona Site Defender reporting will start capturing events when a CSP violation report is observed at the edge.
Analyze CSP violation reports in Web Security Analytics
Once the previous rule is activated and CSP violation reports start coming in, you will be able to view them on the Web Security Analytics (WSA) dashboard (Figure 21).
Conclusion
The purpose of this blog post was to outline the common vectors used by JavaScript skimmer attackers and to illustrate how organizations could leverage SCP and SI policies to help protect their websites and customers. I also wanted to show how Akamai customers could use our Kona Site Defender platform to help implement these mitigations and to monitor telemetry received from end users. If you are an Akamai customer and would like to discuss these topics in more depth, please contact your Akamai representative.