Here’s a Hint: Your Browser Isn’t Safe!
Don’t be that that person! You know, the IT professional who takes a cavalier attitude towards information security and then becomes a headline.
- Facebook: 50 million users
- FIFA: 3.4 terabytes of data and 70 million documents
- Google+: 500K accounts
- British Airways: 380K transactions
- T-Mobile: 2 million customers
- Marriott Hotels: 427 million customers
If we’ve learned nothing as professionals over the past decade, it’s that Information Systems of all varieties and sizes are under increasing attack from casual hackers, criminal elements, and nation states.
Not only are the number of breaches on the rise, but so is the ensuing monetary damage. Global estimates set the average cost to deal with a data breach at $3.86 million. Of course, this is an average, and the actual expenditure depends on the amount of data involved and the complexity and sophistication of the security penetration.
A further breakdown of average cost estimates is:
- $148 per record
- $40 million per 1 million records
- $350 million per 50 million records
From a purely selfish perspective think about the intrusiveness that results from efforts to contain and correct the effects of a breach. When organizations find that they’ve suffered a breach an “all hands on deck” mentality ensues, security consultants and law enforcement are engaged, executive management places IT under closer scrutiny, and productive work grinds to a halt.
“If it’s not fun, you are not doing it right” … Fran Tarkenton
Most information security programs focus on protecting foundational IT components including networks, PC’s and servers, storage, and data centers. Placing the focus on infrastructure is essential, but it’s not the only component of a mature information security program.
Application security includes a variety of techniques which enable the process of finding, fixing, and preventing exploitable vulnerabilities in application software. These techniques span the entire application lifecycle and include:
- Code reviews conducted by security professionals whose goal is to identify security flaws in unique to the application.
- Blackbox security audit based on using an application
- Review application design, within the framework of a threat model, before writing any source code.
- Using automated test tools that are specifically designed to identify security vulnerabilities.
- Implement crowdsourced bounty programs to leverage white hat hackers to locate and fix vulnerabilities before they can be exploited.
The most useful information security processes are based on the concept of layered security. A tiered approach provides defense in depth to prevent and contain incursions by providing protective measures tailored to each type of asset.
Given that applications are one of the inner layers it only makes sense to prioritize application security. It also makes sense when you consider that applications are an externally facing component and are therefore provide would-be hackers with an obvious pathway into the system.
Web applications have a high degree of exposure and risk since browsers are inherently unsafe. This is not an indictment of browsers; it is a statement of fact based on the architecture imposed by the execution environment. It is almost a rite of passage for new Web Developers to attempt and fail at securing data in the browser.
One area that is especially sensitive is that of keys and secrets required for authentication with cloud-based services. For example, applications using the GitHub API must supply a token to identify itself as part of the authentication process. However, it’s vital to keep secrets private since if compromised, a bad actor could use them to steal source code or vandalize a repo.
A trap that frontend developers often fall into is believing that they are secure by keeping secrets, such as private keys and tokens, someplace other than in source code. However important it may be for application secrets to be maintained someplace other than in source code, they aren’t secure if the client runs in a browser.
Let’s examine this further by looking into one technique used to separate data from source code and how easy it is to fall into the trap of thinking that it provides a degree of security.
Environment variables are used to externalize data by moving it from source code into a file, like the
.env file. The additional step of adding this files name to
git push commands from uploading it to the GitHub repo where, for public repos, it would be available to anyone.
Not only does this hide the environment variable value in the code, but referencing it by a well-defined name also adds clarity to the source program.
Okay, it’s not really a secret, but it is often overlooked that the
.env file is not encrypted. In the case of Create React App, this can be verified using the Developer Tools option of your browser to examine the bundle located in the
build/static/js directory. Here you’ll find that
0.chunk.js contains the environment variables and their values in plaintext.
So how is using environment variables better than defining secrets in source code? Doesn’t this mean the application is still at risk?
The answer is that placing secrets in environment variables provides no significant increase in security nor does it decrease risk. The simple fact is that client-side data in the browser cannot be adequately secured and at best this technique only keeps sensitive data out of plain sight.
It is tempting to consider a scenario where code splitting would be used to defer the download of scripts containing environment variables until after the application has authenticated the user. But this violates the concept of defense in depth if the client computer is compromised since the file system will be accessible to bad actors.
Unlike the frontend, backend applications can be adequately secured to protect sensitive data. These protections include the use of OAuth services to provide an additional level of authentication and access control, encryption to protect data at rest, and protocols such as HTTPS and TLS to protect data in motion.
The dilemma of how to protect application secrets can be solved by implementing a server-side application API that acts as a proxy to insulate the frontend app from the service providers it uses. Rather than using secrets on the frontend to authenticate to a service, the API authenticates from the backend application to the external service, makes the requests, and then returns only the results to the frontend. At no point are private keys or secrets exposed to the frontend.
Providing users with the peace of mind that you’ve taken the steps necessary to secure their information requires careful planning, a well-thought-out security strategy based on defense in depth, and attention to detail.
It’s not enough to rely on “islands of technology.” Robustly addressing security requires an understanding of how information flows between components to identify gaps, weaknesses, and how to resolve them.
It is encouraging if the issue of frontend application security concerns you and you’ve grappled with this problem. As a Web Developer, recognizing and accepting that security starts with you shows that you are a responsible individual and you take your craft seriously.
Keep it up and be safe out there!
For more information about using environment variables in your applications see the following article.
(open source and trusted by devs everywhere ❤️)