Code exposure is also an interesting challenge and has become a lot more relevant with the development of different frameworks becoming much more sophisticated. If we look at this screenshot, which is from the Next.js documentation, my question is, what code is running server-side and which is running on the client? At first glance, it's very difficult to know. Even just with 20 lines of code, figuring out what is happening server-side versus on the client is difficult. And so you need to be able to separate these two concerns because secrets, for instance, being accessed on the server is not a problem, whereas secrets, being available in the client bundle, is.
The simple solution to this is to prevent it happening at build time. And there is a module available called Server-Only that makes this really simple. You just import this in the code that you know should only ever be on the server in your database access layer, for instance, or where you're dealing with API keys to make a remote request to a third-party API. That's the kind of code that should only ever be executing on your server. And if it's in the client, you made a mistake. How do you detect that? An import for server-only will cause a build error, so that if that code is accidentally brought into the client, you'll get an error in your logs and it won't be deployed.
Thinking more about your application once it is deployed, there are a number of security headers that you should review and set to help improve the overall security of your application. Now, a lot of this is help preventing against mistakes, because there's no one thing that will secure your application. Security isn't a binary state. It's not secure or insecure. It's about having different layers of security to improve your posture gradually, because when one of them fails, you want to have something else that is providing a layer of protection.
Now, the first one of these is around strict transport security. Now, this is a really simple setting that is a lot easier today than it was a few years ago, because it tells browsers that your site should only ever be accessed over HTTPS. This is almost the default now for applications, and indeed, browsers will start showing warnings when you're accessing content over HTTP, so it's less of an unusual setting. But it allows you to set this default so that a browser will never access your site or your application over HTTP.
Now, the content type options is worth setting because it prevents against vulnerabilities related to content sniffing. This is quite sophisticated in terms of the attacks, and requires certain vulnerabilities to exist in your code, but it's a nice security setting to help try and avoid those. Now, permissions policy and referrer policy, these are about the privacy side of things. So permissions policy sets a specific list of features and APIs that your site wants to access. So, for example, if you don't need the webcam, and you don't need the location of the user, then you just don't list these in the permissions policy, and the browser will prevent your site from accessing them. This is useful to prevent against the risk of malware being injected into your site, perhaps through a third-party CDN breach, and it will just minimize the risk, minimize the impact of a breach if that does happen. Now, referrer policy controls how much referrer information is included when navigating away from a page. So you've all seen, probably, in your analytics the referrer information, so you can find out where visitors are coming to your website from. This allows you to define what appears in that, whether it's nothing at all, or just the top-level domain, or whether further information about the exact page is included. Now, this can be useful for sensitive sites where you might only want to share that the top domain was a referrer, rather than specific pages, or nothing at all. Then finally, content security policy is perhaps the most important of these, but it's also the most difficult, because the default policy will break most applications unless you had it deployed from the beginning, because the default is to allow nothing.
Comments