At Computest Security, we love code. We regularly review new code bases, from websites to mobile apps. Today, we’ll share the lessons learned and explore the fascinating world of frontend frameworks. Why should you use a framework for your website at all? And what are the main issues we see when applications use such a frontend framework?
What is a Frontend Framework?
A framework is a toolkit—a starting point for developing your website. It standardizes the way you structure your software, the code, and takes care of many things that every website needs, like data storage or building pages. The latter is a prime example of what a framework offers for the "front" of the website, hence the name frontend framework. Based on our experiences with vulnerabilities in practice, here are the three most important tips for safely using frontend frameworks.
1. Don’t Trust Your Frontend
The frontend is called the frontend because it’s the part of the website code that runs on the visitor’s computer, laptop, or mobile device. This means you shouldn’t trust the frontend. Someone with malicious intent can easily view or modify the frontend's source code. Therefore, it's crucial that the backend, the server-side of the website, doesn't rely on the frontend to perform security checks; it should do them independently. This includes verifying user authentication and whether an authenticated user has access to sensitive data. Additionally, the frontend's source code is public, so it’s not the place for sensitive information or secrets like passwords or API keys.
2. Know Your Framework’s Limitations
A frontend framework is incredibly useful, especially for preventing one particular vulnerability that afflicts a third of websites: cross-site scripting (XSS). If a website is vulnerable to XSS, a malicious individual can use a piece of harmful code to attack other site visitors. Typically, the attacker can't target everyone on the site without extra steps, like getting the victim to click on a specific malicious link.
Frontend frameworks are effective tools for preventing XSS vulnerabilities as many automatically apply the correct encoding, ensuring input is rendered as data rather than code. Despite this, frontend frameworks aren't magic solutions, and you must account for many exceptions as a developer. We’ll dive into specifics shortly. If you aren’t a developer, you can skip ahead to point 3 about updates.
2.1 Theory of Frameworks
Cross-site scripting arises when user input reaches locations in the frontend where it isn't interpreted as text but as HTML or JavaScript. For example, if we build a search feature displaying how many results a search term yielded, we might forget to HTML-encode the search term. This oversight allows the creation of links with malicious JavaScript, which, upon clicking, executes that code. With JavaScript, attackers gain access to sensitive victim data.
There are essentially three basic XSS variants, categorized based on where the user input lands. In the above example, it ends up between element tags, in 'innerHTML', but XSS can also occur with input placed in an HTML attribute.
Lastly lies a unique variant involving special URL prefixes like 'javascript:'
2.2 XSS and Frontend Frameworks
Some frameworks rigorously protect against all three basic XSS variants, while others only guard against the first. Let’s examine three frameworks.
2.2.1 Angular
If you consistently use interpolation in Angular ({{ }}), you’re covered. Angular is intelligent enough to recognize the contexts mentioned earlier. However:
- Avoid direct interaction with DOM elements outside Angular. For example, manipulating the DOM using ElementRef. Doing so uses built-in browser APIs where user input might not be handled safely.
- Don’t override Angular’s safety features. You can mark certain content as safe using functions like bypassSecurityTrustHTML, but this bypasses Angular’s escaping function and poses a risk of XSS vulnerabilities.
- Avoid generating templates dynamically, such as appending strings to templates or using another templating language. Escaping only occurs during template rendering, so the template itself must be trusted. Any user input incorporated into the template poses XSS risks.
2.2.2 Vue.js
Vue.js also offers strong support. When using text interpolation ({{ }}), user input is HTML-encoded, making it safe for inclusion between HTML tags. Nonetheless, consider:
- In most cases, user input in dynamic attribute bindings is secure, yet caution with attributes like 'src' and 'href' remains necessary, as Vue.js only encodes double quotes ("). A 'javascript:' prefix, therefore, could persist.
- Vue.js allows event handlers with v-on directives or directly on 'native' event attributes, but be wary: user input in such attributes is treated and executed as JavaScript. HTML encoding through text interpolation does little as the input isn't in an HTML context but a JavaScript one.
- Similarly to Angular, direct DOM manipulation in Vue.js, such as using v-html, render functions, or JSX, interprets input as HTML, posing risks when combined with (potential) user input.
- Like Angular, dynamically generating templates in Vue.js is risky. Escaping happens upon rendering, so untrusted templates due to added user input risk XSS.
2.2.3 React
React follows a similar suit. JSX serves to define HTML elements, evaluating JSX content as JavaScript expressions, which are then HTML-encoded, ensuring safe containment between HTML tags. Nonetheless, be aware of:
- React also escapes only double quotes (") in attributes. Hence, be cautious with 'src' and 'href' attributes where 'javascript:' prefixes could remain.
- In React, direct DOM manipulation via dangerouslySetInnerHTML or DOM interaction with findDOMNode/createRef omits React's standard escaping, leaving XSS vulnerabilities.
- It’s common in React to instantiate components using the spread operator (e.g., <div { ...properties }>). However, a user altering the properties-object can inject script through 'dangerouslySetInnerHTML', resulting in XSS exposure.
3. Keep Software Updated
Software updates and dependency management are always a security challenge, certainly for frontend frameworks. It's crucial to periodically check for new vulnerabilities as they frequently arise and may pertain to your situation. Tooling can aid; many package managers can automatically check for known vulnerabilities (like npm audit), while dependency scanners can automatically create update pull requests (such as Dependabot).
Lastly, be critical of the software you depend on. Each additional library increases your attack surface, possibly harboring unknown vulnerabilities, needing timely updates, and potentially getting compromised themselves. Thus, limit software dependencies and use only trusted sources.
Conclusion
Want to safely use a frontend framework? Here’s how:
- Don’t trust your frontend. Use the backend for secrets and vital security checks.
- Be aware of your framework’s limitations. A framework is only safer if used correctly.
- Monitor software updates and ensure timely security patches.
Curious whether your frontend is secure? Let us review your source code. We’ll conduct in-depth research to identify vulnerabilities and provide feedback on architectural and design choices, helping you address weaknesses.
Contact us via: info@computest.nl.