This blog was previously published on blog.tcell.io.
Just because your payment processor has PCI Level 1 doesn't mean you can ignore cross-site scripting (XSS). If you handle money, you process credit cards (since it's pretty hard to email cash). To prevent fraud, the card industry has created the PCI Data Security Standard. So, if you're processing cards, you'll be safe if you follow the specific guidance in PCI, right?
Recent events have shown that payments have been subjected to sustained attack, demonstrating that PCI DSS compliance is a necessary component, but is not adequate protection when taken in isolation.
In fact, the card industry has gone beyond the technology of the PCI DSS and has defined PCI compliance levels (here are Visa's definitions) ranging from Level 1 (the highest-volume processors) to Level 4 (the lowest-volume processors). Higher-volume processors have more stringent requirements because they are a more attractive target, and therefore higher-risk.
Modern web design is like car manufacturing. Just as car manufacturers depend on suppliers for components and even whole sub-assemblies, so do web application developers. Relying on subcontractors for expertise helps reduce risk. Why learn the intricacies of developing ignition systems when you can buy one from Bosch? Similarly, why learn the details of protecting payments when you can rely on a service to do so?
Payment processors make PCI compliance easy, but not security
In fact, one of the reasons to use a payment processing service is that your PCI compliance becomes much easier—in effect, saying, "Hey, I use this PCI Level 1 service, so I'm relying on them to do most of the heavy security lifting."
For example, Stripe has an extensive PCI section in its documentation. Generally speaking, a payment processing service will make it easy for you because all its documentation is readily available (and if it's not, you probably should consider it a bad sign).
So far, so good. You can use a service to make PCI compliance easier. Yay, outsourcing! Letting organizations focus on what they're good at is less distracting and more efficient. How could this possibly go wrong?
Most of the PCI DSS was written with the assumption that you'd have almost all of the code for your application under your control, and it's still getting used to the idea that meeting PCI DSS requirements now requires cooperation among several companies. Letting Stripe handle your payments is an important component of your overall security, but the story doesn't end there.
Protecting payment card data from XSS
Where relying completely on your payment processor goes awry is that as a developer, you are still responsible for interactions between app components. Yes, the payment processing pages or frames will be well-defended, but anything else that is part of your web application can read the contents of the payment frame. Want to have a chat window? Well, if you don't write your own, the scripts that run the chat window can read payment details. That makes any web application component into a possible attack vector, but very few non-payment-related components will have recognized the need to implement a PCI-style deep security program.
To continue with our automotive metaphor, we just started working with the application component that is the equivalent of a Takata airbag. It's part of our application, so we're responsible for making sure it's secure. But it's not our code—and, in fact, it can interact with our code in ways we don't understand.
So, what can we do? Browser scripts and multiple sources of content is a classic XSS setup: two pieces of code come together in the user's browser and interact in a way where data is exposed. If an attacker can get a rogue script to run next to your payment processing page, they can read anything they want. The only ways to stop it are to prevent the script from loading or to prevent the script from sending any compromised data.
The first option isn't really an option. We're likely using the script because it does something faster, better, and cheaper than we are able to. Insisting that we control every line of code in our own application is no longer viable. So, we have to turn our attention to preventing the attack from working.
Protect your customers visiting your website or app from XSS
The best way to stop XSS attacks from having an effect while maintaining the freedom to use all the best-available web components is to prevent a rogue script from communicating results. Web standards give us the tool for this: HTTP's Content Security Policy (CSP), which is like an application-level firewall. Developers can instruct the browser to only permit communications to a set of allowed sites. The application tries to connect to your site for data? Allowed. It needs to communicate to a chat provider? Allowed. An attacker wants to send stolen data to their server? Blocked!
As web application architecture has become increasingly atomized, the role of the application developer has become one of design and assembly, while much of the heavy lifting was left to platform companies. Ensuring application security when application code is distributed across multiple code bases (or even companies) requires different security tools and approaches than when all code is developed in-house. CSP is an important new addition to the security toolbox, especially because it prevents attacks that occur in an end user's browser, where control has typically been very limited.