No matter the scope of your application - even if it's a single page app - protecting the user's data is critical. Learn the best ways to keep user data secure.
The web has changed a lot. Many processes that are usually done on the server have moved to the client side. One of these is authentication.
In the past, we’ve had servers manage and store user sessions, which makes most of the authentication process secure.
Now that most of these operations have moved to the client side, where information can be easily accessed and leveraged on stateless APIs, it is important that we continue to adopt best practices and avoid vulnerabilities to ensure our application remains secure.
Protecting the user’s information should always be top priority, regardless of the scope or size of the application.
Single Page Apps (SPAs) are often tied to APIs, and these APIs, in the form of endpoints, help provide data that can be manipulated in the logic of these apps. Some of these data the APIs provide are sensitive, so before they can be accessed some form of authentication needs to be in place.
The server housing all the data receives submitted user credentials from the frontend application, authenticates it, and returns the appropriate response.
The best known solutions to authentication problems are the OAuth 2.0 and JSON Web Token (JWTs) specifications. JWTs give you a structured way to declare who a user is and what they can access. They can also be encrypted and signed for verification. JWTs take the following form: header.payload.signature
Authentication is sometimes mistaken for Authorization, but they are quite different. With Authentication, you are trying to identify the user with credentials you have received, while Authorization is determining if this identified user should have access to a particular resource or not.
When building frontend applications, a lot of things are considered as best practices to make your applications as secure as possible. Not all these completely eliminate the problem, but they take a huge step in ensuring a more secure application.
SSL stands for Secure Sockets Layer and is used to encrypt data that is transferred over the internet. This encryption allows your visitors to browse your website within a secure connection. SSL protects personal information, like phone numbers, addresses, name and credit card information when transferred.
This used to be an expensive feature to implement, but we now have providers that offer free SSL Certificates like Let’s Encrypt.
Aside from the securing of your website, an SSL certificate makes your site trustworthy: any visitor that sees that your site is protected with the “https” will have full faith in sending you their information and using your application.
By using JWT, you have a token returned to you from the server that can be used to make subsequent requests. The challenge with this is how best to store this token.
The browser offers different approaches to storing the data but each comes with its own vulnerabilities.
Web Storage: It’s common practice to store a token in window.localStorage
so that it can be easily retrieved when making an API request, but it was never designed to be secure.
window.localStorage.setItem('token', tokenReturned)
Although it is immune to CSRF, it is vulnerable to XSS. Since JWT payload/claims can actually be read without the private key (secret), it’s not secure to store it in localStorage.
HTTP Cookies: An HTTP cookie is a small piece of data, usually no more than 4kb that a server sends to the user’s web browser. Data can be stored more securely here, specifically in Secure
and HttpOnly
mode.
HTTP Cookies are immune to XSS but vulnerable to CSRF.
set-cookie: Expires=sun, 16 Sep 2018 17:43:00 GMT; Secure; HttpOnly
The Secure
flag ensures that the browser sends the cookie only over a HTTP connection.
The httpOnly
flag prevents any JavaScript code to be read from it.
As mentioned above, Cross-Site Scripting (XSS) is one of the major vulnerabilities for web applications. Fortunately, browsers offer and implement many features to help prevent it. This involves using security headers such as CSP, SRI, HSTS, or HPKP.
Content Security Policy (CSP): A CSP describes a series of rules that instruct the browser to allow or block resources from being loaded and executed by specifying the domains that the browser should consider to be valid sources of executable scripts.
Subresource Integrity (SRI): Using SRI enables browsers to verify that files they fetch (for example, from a CDN) are delivered without unexpected manipulation.
HTTP Strict Transport Security (HSTS): The HTTP Strict Transport Security is another HTTP response header that tells the browser that it should only allow HTTPS requests on all subsequent requests.
HTTP Public Key Pinning (HPKP): The header provides the ability to instruct the browser to verify a set of given cryptographic public keys against the requesting website.
HTTP Cookies: Already talked about this, but it’s weird to leave this empty 😬
As mentioned above, a more secure way of storing tokens is using HTTP Cookies, but it also opens you up to CSRF. A CSRF attack can be prevented by using Non-Simple Requests.
To understand this, we’d look into CORS.
CORS stands for Cross-Origin Resource Sharing and is a mechanism that uses additional HTTP headers to defend against one origin (domain) from accessing data of another origin. A Non-Simple Request triggers a “CORS-Preflight” and prevents accessing of data.
It’s very important for every developer, especially when building single-page frontend applications, to be aware of the possible security vulnerabilities and how to minimize the risk of attack.
Authentication in different apps varies, as different apps have different flows and requirements, but the need to be security conscious is universal.
Nosa is a Frontend Developer with a passion for turning designs into beautiful interactive interfaces.