Is a SPA less secure than a server rendered web application?

In this post, I try to explain some of the differences between a single page application and a server rendered application and why the application types have different threat models.

What is an Single Page Application (SPA)?

A single page application runs in the browser, and handles routing in the client without posting back to the server. These applications are usually implemented in technologies like Angular, React or Vue.js. The SPA usually has some sort of back-end API, which provides data for the application. The SPA then uses this data and renders it to HTML, usually using Javascript.

What is a server rendered web application?

A server rendered application renders HTML on the server and sends the HTML to the client browser. The routing is done on the server. This means more of the application, compared to the SPA, is run in a trusted zone. OpenID Connect Code flow, or the OpenID Connect Hybrid flow could be used for authentication and authorization and cookies are used to persist the session.

First difference is the amount of code run and used in the public zone

More code is run in the public zone in a SPA application, which means a larger part of the application is opened for attack. The UI usually implements some type of authorization switches, and this is all done in the browser. If this is implemented without the security protections, it could be attacked, but on a server rendered app, only the result is returned to the public zone. In a server rendered app, the authorization and the authentication is done on the server.

Securing the SPA application using cookies

When the SPA application uses an API on the same domain, with LAX or Strict Same site cookies and HTTP only, then cookie-based authentication can be used. Cookies are used to persist the session, like the server rendered application. Anti-Forgery cookies would be required and also a good CSP and XSS protection. Both the Anti-Forgery cookies and the Same Site cookie help prevent cross site attacks.

The SPA application does not handle tokens, and does not need to save these to a local storage , or session storage. The SPA can only use APIs in the same domain, and all APIs would need cross site protection. The requests are sent with the cookie which can be used on the server. This is only slightly worse than the server rendered application, with the only difference being the amount of code run in the public zone, meaning a greater risk for security mistakes. The public API is also required for a SPA. The server rendered application does not need a public API.

Securing the SPA using OIDC code flow with PCKE

If the SPA uses APIs from a different domain, then it needs access tokens, and also needs to manage these in the browser. This has disadvantages compared to the server rendered web application. Nothing what is done in the browser can be trusted.

The user can authenticate and authorize using the OpenID Connect code flow with PKCE. See these two specifications for details:

https://tools.ietf.org/html/rfc7636

https://openid.net/specs/openid-connect-core-1_0.html

This returns an access token, or a reference to an access token, and a JWT id_token. When validated and all is ok, the SPA needs to persist the tokens somewhere, for later usage. This is usually saved to local storage or session storage in the browser. The SPA application sends the access token with web socket requests, or HTTP API requests. The access token is being managed and used in the public zone, so greater risk exists, that the token could be leaked. This can be reduced by using reference tokens to the access tokens, and also by keeping the life span of the token short. Sending the token in the URL should be avoided where possible and the tokens should be handled with care. For example, if you use APIs from different hosts, the incorrect token should not be automatically sent.

So is a SPA less secure than a server rendered web application?

Yes/No, it depends. Per definition, more code from the application is run in the public zone, and so has a larger attack surface, but it does not need to be less secure, by using the correct precautions. Also for example, if an ASP.NET Core MVC application uses lots of Javascript and ajax requests, this is not much different to a SPA same domain application.

Links:

https://www.owasp.org/index.php/SameSite

https://dotnetcoretutorials.com/2017/01/15/httponly-cookies-asp-net-core/

https://tools.ietf.org/html/draft-parecki-oauth-browser-based-apps-02

The State of the Implicit Flow in OAuth2

https://tools.ietf.org/html/rfc7636

https://openid.net/specs/openid-connect-core-1_0.html

https://docs.microsoft.com/en-us/aspnet/core/security/?view=aspnetcore-2.2

An alternative way to secure SPAs (with ASP.NET Core, OpenID Connect, OAuth 2.0 and ProxyKit)

https://docs.microsoft.com/en-us/aspnet/core/security/anti-request-forgery?view=aspnetcore-2.2

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.

%d bloggers like this: