HTTPS, XSS, and CSRF make up just a fraction of all possible security concerns on the web. However, they come up so often that I think it can be quite awkward for any front-end developer to not have some understanding of them.
HTTP, as you’ve heard a million times, stands for HyperText Transfer Protocol. It defines the structure of the message payloads going back and forth between clients and servers.
Think of HTTPS as “HTTP” + “S”: HTTP that’s augmented to be secure with SSL (Secure Socket Layer) / TLS (Transport Layer Security) protocol. In case you’re wondering, TLS is simply a more modern name for SSL.
Before a client can properly communicate with a server, they’ll need to go through what’s known as TLS handshake. The TLS handshake allows both parties to share a common encryption key for encrypting messages they write and decrypting messages they receive. After all, we wouldn’t want some malicious third-party to sniff the contents in these payloads.
Sharing a symmetric key is tricky, of course. Both parties can’t just simply send their keys to each other in plain form –– any third-party could also intercept this transmission. Thus, we’ll have to encrypt this key itself (a little meta, huh) using public key cryptography.
Three agents are involved in this process: A client, a server, and a certificate authority. The steps are as follows:
- The client pings the server 🔊
- The server sends its SSL certificate 📜, signed by a trusted certificate authority, to the client
The client uses the certificate authority’s public key (pre-installed on the client) to decrypt the certificate. By decrypting the certificate, the client is able to:
- Verify the identity of the server 👮♂️👍
- Obtain the public key of the server
- The client generates a symmetric key and encrypts it with the server’s public key
- The client sends this encrypted symmetric key to the server
- The server receives the encrypted symmetric key and decrypts the payload with its own private key.
- The client and server now share a common symmetric key 🔑 🤝 🔑.
In subsequent requests, both client and server simply use the symmetric key to decrypt and encrypt payloads. This is primarily because asymmetric encryption algorithms (e.g. RSA) are generally much slower / computationally expensive than their symmetric counterparts (e.g. AES).
XSS (Cross-Site Scripting) starts with a “X” instead of a “C” so that folks don’t confuse it with CSS (Cascading Style Sheets).
XSS, in a layman terms, describes a situation where a user is able to inject their code into a web application and execute it in a manner that’s unintended by the application. This code is usually passed via a channel which accepts user input. As front-end developers, text and text area inputs come to mind, but uploaded files can also be potential sources of trouble.
For example, a malicious user might customise their bio field on a social networking platform to include an inline script. If the application fails to prevent this script from being persisted or rendered as HTML, then unsuspecting clients who visit this user’s bio will inadvertently run the injected script.
Prevent these basic forms of XSS is relatively straightforward. You’ll want to sanitise content in two directions:
- The user-supplied content that your application receives as input should be stripped of unwanted code
- The user-supplied content that your application renders should also be stripped of unwanted code
You can also define a Content Security Policy, which allows you to ”[specify] the domains that the browser should consider to be valid sources of executable scripts”.
Plenty of UI frameworks already sanitise content out of the box (and provide certain escape hatches if you wish to opt out of this feature), so you usually don’t have to think too hard about warding off XSS attacks. Nonetheless, as web developer, it’s critical that you keep this attack vector in mind so that your users aren’t compromised.
CSRF, which stands for Cross-Site Request Forgery, consists in making a client trigger an unwanted request. In particular, the attacker uses the victim’s own credentials to make the request (i.e. the credentials are “forged”).
For example, an attacker might send a victim an innocent looking email that contains a tag for
<img src="https://foobar.io/api/dangerous" />. When the victim opens this email, loading the
img tag causes the victim to make a GET request to this
dangerous API. Since (unexpired) authentication cookies are typically attached to user requests, the victim will be making this request as an authenticated user –– and the server is likely to respond successfully, as if the request was made on the application’s own frontend.
It’s generally a good idea to ensure that GET requests don’t modify the application’s persisted state, in order to reduce the impact of exploits like these.
Could CSRF occur in the form of other REST methods too? Of course! We won’t explore them in detail, but know that there are plenty of things you can do to prevent CSRF across the board, such as:
- Disabling CORS (Cross-Origin Resource Sharing)
- Generating CSRF tokens that are issued on page loads.
Check out this document for a more comprehensive set of recommendations.
HTTPS, XSS, and CSRF don’t come close to encompassing the full range of security risks that your application might be exposed to, but I hope this refresher has been useful to you in some way.
If you’re serious about web security, you might want to be familiar with the top 10 vulnerabilities in web applications, as outlined by the Open Web Application Security Project (OWASP).