Securing SPAs is a Team Sport

Lori MacVittie Miniatura
Lori MacVittie
Published August 05, 2019

One of the interesting - and more frustrating - things I've noted over the years is the difference between how network engineers and application developers see apps. We've seen this in the way applications are depicted on network diagrams and, conversely, the way networks are shown on application architecture diagrams. 

Dev vs Net POV

Needless to say, each has a very simplistic view of the other. 

That's also true for security, whose role in protecting not just networks and applications but the very business has become paramount. It's important that security teams get outside the boxes on typical architectural diagrams to really understand applications. A significant percentage of (successful) attacks are executed at the application layer. The longer we fail to recognize the unique characteristics of various types of applications, the longer those applications remain vulnerable. 

Today's discussion is going to focus on SPAs. That's "Single Page Applications" for those wondering what this particular TLA stands for. 

An Introduction to SPAs 

A single page application is just that - a single web page that serves as a framework for all application-related tasks. This architecture harkens back to the days of Web 2.0 and the emergence of AJAX as a method of 'refreshing' individual DOM (Document Object Model) elements rather than reload the entire page. Performance was greatly enhanced with this technique, and is the forerunner of the modern, single page application.

These apps more closely mirror the behavior of a mobile app, where the client UI is loaded when it's first opened and communication with the server involves only data. That means every call to the server contains nothing more than data, and any changes to the UI happen on the client. This dramatically reduces the amount of data being sent back and forth and, as you can imagine, means better performance. These kinds of apps use APIs to exchange data.

Generally, we've been operating under the assumption that most of those APIs are implemented using REST principles. That means each object (generally considered to be tied to a single UI element) has its own API that can be invoked to execute CRUD (create, read, update, and delete) transactions. From a security perspective, that makes things somewhat easier because you can expect data in specific formats for a given API (URI) call. The data sent to "/update/product/123" is going to consistently be the same serialized object, while data sent to "/delete/order/4433" will be a different serialized object. That means traditional practices of tying specific policies to specific URIs can be used to secure that API. 

The Single URI Pattern 

Now, SPAs may - or may not - follow this pattern. Emerging practices around SPAs can and do use the same API to conduct transactions as well as a more traditional function-to-URI mapping. With a single URI pattern SPA, the URI does not change - but the serialized objects sent back and forth between the server do.

This is reminiscent of SOA/XML transactions, in which a single endpoint (URI) would be used to invoke multiple functions. The function (endpoint) targeted was contained within the serialized XML data or sometimes inserted into a custom HTTP header. This model led to the need for SOA/XML gateways that were responsible for receiving the request and determining which function was being invoked before routing it to the right endpoint (server). 

With SPAs, you may be dealing with multiple API calls or just a few. In all cases you're likely dealing with the need to secure data in some format (maybe XML, more likely JSON). That means you need to be aware that content carries the risk. Because some data may be used to dynamically generate UI elements (or otherwise manipulate the DOM back on the client), it's important to seek and destroy potentially malicious code on every submission. 

The Security Disconnect 

Unfortunately, if a single URI is used to exchange data for varying functions, the traditional practice of attaching policies to URIs isn't going to work. In fact, that can break security because such policies are often trained to expect specific payload formats. API gateways, too, often tie policies (routing, metering, access) to a specific URI. That means the practice of using just a few URIs (API calls) to handle many more functions with varying data formats can break existing security.

This is an example of why it's increasingly important for security and dev (not DevOps, but developers) to work more closely from the first line of code through deployment. There are things developers can do early on to make it easier for security to put in place the proper protections - such as inserting an HTTP header with an indicator that makes it possible to execute the right policy. Something as simple as "X-Code: 'order'" would enrich requests in a way that security solutions could identify - and subsequently scan - the data for potential exploits.

Architecturally, this may require a smart L7 proxy that can extract the code and rewrite the URI before routing the request to the appropriate security solution (WAF, API Gateway, etc.) This approach also works if the smart L7 proxy can speak the data format language, such as JSON, and developers include in every exchange some code or endpoint name that can be used to rewrite and route to the right place. 

Secure Spa Architecture

Optimally, incorporating the application layer security into the app itself would net the best balance of performance and security. That's not always possible, however, and sometimes creative architectural solutions are required to achieve the goal of security. 

Security is a Team Sport

Generally speaking, changes in the way developers distribute various responsibilities across the client and the server have a significant impact on the way application service infrastructure interacts with the subsequent requests and responses. It's important for security, developers, and application service infrastructure teams to be involved in the entire SDLC. An architectural solution takes time to implement, too. If it's left "until the end" you're tacking on days - or weeks, or maybe even months - of additional time to market. Or you're going to market without security services, which has its own set of risks (and consequences).  

Collaboration from day one of development is the best - and fastest - way to ensure that apps are available, fast, and secure when they roll into production.