JavaScript is the front-end of the entire internet. Whether you transpile TypeScript down into JavaScript, create fast little node.js scripts, or build a beautiful-but-dumb front end that calls a much more interesting collection of APIs, it’s literally everywhere. Because JavaScript is so prolific, it’s a prime target for attackers. In this article we will cover ten tips for writing more secure JavaScript.
The number one item to discuss when it comes to JavaScript security is always cross-site scripting (XSS). Cross-site scripting is a form of injection; it means an attacker has confused your application into either interpreting or executing their malicious code instead of treating it as data. User input should always be treated as data, but unfortunately computers can be fooled if we are not careful.
XSS is the one type of injection that works only in JavaScript. It is also the only type of injection that attacks the user directly, by taking control of the browser and using it against the victim. All other types of injections do not attack the user; for instance, SQL injection attacks the database server, command injection attacks the host operating system that the system is running on, and LDAP injection attacks the LDAP server. You get the picture.
With XSS, an attacker can use the browser to access your cookies (including your session information, if you have stored it inside your cookie in an insecure way), external scripts (if you haven’t locked that down using Content Security Policy), install a keylogger, vandalize your website, etc. Anything that JavaScript is cable of doing, an XSS attack can also do; the only limits are an attacker’s imagination.
Although instances of XSS have declined over the years, thanks to various forms of awareness and education (such as The OWASP Top Ten Risks to Web Apps), newer JavaScript frameworks performing output encoding mechanically, and groups taking safety extra critically than ever earlier than, it’s sadly nonetheless a excessive threat drawback.
To get rid of your possibilities of having XSS have an effect on your purposes, carry out the next actions:
- Carry out enter validation on all user-supplied or user-modifiable knowledge. After you carry out enter validation, if it’s a must to settle for doubtlessly hazardous characters (equivalent to <, >, ‘, “, -, and so forth.) it’s best to shield your utility by both escaping them (including a backslash in entrance) or sanitizing them out (actually changing them with one other character or simply eradicating them altogether).
- Carry out output encoding on something that can be exhibited to the display screen, together with something that is likely to be displayed (as an example if you’re returning one thing from an API that can be displayed by your entrance finish). In case you can have your framework do that give you the results you want, that’s the best and infrequently handiest means to make sure you do that appropriately. Output encoding can change into fairly sophisticated, particularly if you’re doing inline JavaScript. Nobody desires to do nested encoding!
- Use the Content material Safety Coverage header (CSP) to record all the third-party parts that you’ll enable as a part of your app, particularly scripts. The very first thing a malicious XSS assault will do is attempt to name out to a different, a lot bigger, malicious script on the web. Most fields solely enable 50 or 100 characters, which isn’t plenty of area to jot down code for an assault. If they’re able to name out to a malicious website on the web, then name a for much longer script, your improve the chance exponentially.
- Add the
httpsOnlyflag to your cookies to make sure that for those who did handle to overlook one thing, the attacker won’t ever be capable to entry your session info out of your cookies. Attempting to entry your cookies is usually the second factor a XSS assault will attempt to do, so don’t allow them to entry that delicate info. - Carry out guide code assessment, use a static (SAST) or dynamic (DAST) evaluation instrument, or carry out a penetration check to be completely positive that you just didn’t miss something!
React, Angular, and Vue.js mechanically carry out output encoding, and still have many, many different superb options. When utilizing any framework, watch out to test if there are harmful capabilities that it’s best to keep away from or watch out with, equivalent to React’s dangerouslySetInnerHTML and Angular’s bypassSecurityTrustAs* capabilities.
As tempting as it might be to incorporate JavaScript instantly inside your HTML for those who’re “simply attempting to do one thing actually fast”, it vastly will increase the potential for XSS (and creates upkeep points for later). On high of that, it’s a multitude. Maintain your JavaScript in separate exterior information to keep up that additional layer of safety and group. You may outline your scripts in a CSP header to maintain all the things good and orderly. That is much like inline SQL, after we mix consumer enter after which feed it on to the database to execute…harmful conditions occur.
We’re not neanderthals, which suggests in fact we wish to write good, clear, syntactically right code. Strict mode helps us do that by tightening the language’s guidelines that will help you write safer, cleaner, and extra predictable code. You need to be utilizing strict mode in all languages that it’s provided, not simply JavaScript.
Strict mode prevents silent errors, disallows unsafe actions, blocks you from utilizing reserved phrases (equivalent to let) for something aside from what they had been meant, prevents unintended world variables, and it makes the usage of this safer and extra predictable. Plus, strict mode can also be supposed to enhance efficiency, assist you to catch bugs earlier, steers you towards finest practices, and it improves safety.
Many of those dangers are well-known, and builders within the open-source neighborhood have created instruments that mitigate them. Use useful, free and open-source software program (FOSS) libraries and instruments that will help you write safer code, equivalent to:
- DomPurify for sanitizing enter in opposition to XSS.
- Retire.js to search for outdated, unsupported, or in any other case harmful JavaScript libraries.
- Npm Audit, Yarn Audit, Snyk CLI (free model) to test your dependencies are updated.
- DOM Snitch is a Google undertaking which created an experimental Chrome extension that permits builders and testers to establish insecure practices generally present in client-side code.
- Nodejsscan a free static evaluation instrument for node.js apps.
- Semgrep Community edition, Bearer CLI (free model), Horusec, and so forth. to carry out free static evaluation. All of them work on a number of languages, together with JavaScript.
- Zap to carry out free dynamic evaluation (DAST) Observe: get permission out of your boss earlier than operating Zap at work! This can be a hacker instrument and operating it in opposition to any web site or app with out written permission is prohibited. This instrument could cause injury if used incorrectly. Please learn up on it earlier than you utilize it. The opposite instruments are by no means harmful to make use of.
Be clear in your code that textual content is textual content, and that no matter is inside your variable is not code that ought to be executed or interpreted. We be sure that textual content is textual content by placing something from the consumer right into a secure knowledge aspect to your JavaScript or CSS. For instance, don’t use innerHtml (which is rendered); as an alternative use innerText or textContent, that are clearly text-only, for show, and to not be interpreted. At all times be clear that one thing is textual content; don’t let the DOM (doc object mannequin) resolve, as a result of generally it will get it unsuitable.
In case you should set aspect.setAttribute with knowledge from a variable (which is usually a consumer equipped worth, and is subsequently doubtlessly harmful), solely use secure, static attributes, relatively than attributes which are dynamic (changeable). Examples of secure attributes embody: align, alink, alt, bgcolor, border, cellpadding, cellspacing, class, shade, cols, colspan, coords, dir, face, top, hspace, ismap, lang, marginheight, marginwidth, a number of, nohref, noresize, noshade, nowrap, ref, rel, rev, rows, rowspan, scrolling, form, span, abstract, tabindex, title, usemap, valign, worth, vlink, vspace, width). Don’t use dynamic, unsafe attributes for aspect.setAttribute, equivalent to onclick or onblur. Attributes the place one thing ‘occurs’ or modifications aren’t secure, and you shouldn’t use them with user-supplied knowledge (equivalent to no matter knowledge is saved right into a variable).
Whereas we’re on the subject of utilizing variables (consumer knowledge)…they need to solely be positioned inside CSS property values, not into contexts. Once more, we don’t need them doubtlessly making our software program act in unpredictable methods.
Instance: <type> selector { property : $varUnsafe; } </type>
When performing enter validation for safety causes (not for usability, pace, or some other cause), the checks should be carried out on the backend, not within the entrance finish. Anybody with an intercept proxy, equivalent to Zap or Burp Suite, is ready to ‘intercept’ your entrance finish’s request, make modifications to it, after which cross it onto the backend as if it was not interfered with. If performed properly, the backend has no concept if somebody made any modifications to a request after it left the entrance finish. One of these assault or testing can be carried out on the identical machine because the particular person utilizing the appliance, that means they might not want to fret about encryption, they might have direct entry in clear textual content to your whole request.
Why is that this unhealthy? Think about you’ve gotten enter validation in your JavaScript that claims you might be prepared to simply accept a-z, higher and decrease case, in addition to all numbers, however nothing else. It accepts this knowledge after which displays to again to the display screen for the consumer to learn. The app would theoretically reject the next enter “‘ or 1=1 --” as a result of a number of of these characters aren’t in your allowlist. Nonetheless, think about an attacker is utilizing your utility with an intercept proxy. The attacker enters “Good day” into the sphere, and it passes the enter validation. They then intercept your request, change the sphere to say “ ‘ or 1=1 --”, after which sends it onto your utility. If there was no enter validation on the backend, the appliance would use that knowledge nonetheless it usually would, on this case doubtlessly appending it to an SQL assertion equivalent to ‘choose * from desk customers the place username like %’ & your_now_malicious_variable_here & ‘ and password = ‘ & password_variable.
Though it is a simplified instance, hopefully you may see that enter validation, for safety causes, should be carried out on the backend. You may all the time carry out it on the front-end as properly, for pace and value. You simply want to make sure the ultimate say is all the time on the server.
Keep away from the next, often-problematic, JavaScript capabilities. Particularly and particularly if you’ll use them with consumer equipped or user-modifiable knowledge. In case you should use them, proceed with excessive warning. eval(), innerHTML, outerHTML, Operate(), escape(), unescaped(), doc.write(), doc.writeln(), unescapeHTML(), decodeURI() and encodeURI(), with(), constructors that use a string argument (which suggests a variable), setTimeout(), setInterval(), new operate, and setAttribute() (recall: for those who use setAttribute, use static values solely).
Carry out all the opposite safe coding methods that you’d for some other utility, equivalent to performing enter validation / sanitization / escaping, utilizing parameterized queries as an alternative of inline/dynamic question constructing, encrypting your knowledge in transit and at relaxation, and utilizing dependable techniques for authentication, authorization, session administration, id, and secret administration, and so forth.
Of the usual objects that most individuals take into account to a part of ‘safe coding’, guaranteeing that your staff follows a safe system improvement life cycle (S-SDLC) is absolutely the most vital one. After I say a safe SDLC, I imply that your staff provides extra actions and processes to make sure that the software program you might be constructing and sustaining is secure, dependable, and rugged. A number of the actions you can add to any methodology would come with menace modeling, safe code assessment, automated dynamic testing, software program composition evaluation or different verification of your third social gathering dependencies, hardening of your software program provide chain, creating safety consumer tales, or together with safety necessities alongside all of your different undertaking necessities. Any safety actions that you just add to your SDLC will assist guarantee we create extra strong and reliable techniques that your customers can depend on. The extra you add the higher!
The journey to writing safer JavaScript begins with small, constant modifications. Select one or two finest practices and put them into motion at the moment. As you begin to see their affect, take a second to share what you’ve realized with a buddy or colleague. Via data sharing and incremental enhancements, we are able to make JavaScript not solely extra stunning and highly effective, but additionally safer for everybody.

