- Security best practices
- Audit dependencies using a package manager
- Add Subresource Integrity (SRI) checking to external scripts
- Validate user input
- Escape or encode user input
- Use a CSRF token that’s not stored in cookies
- Ensure secure cookie transmission
Cross-site scripting (XSS)
In an XSS attack, the attacker injects a malicious client-side script into a web page. They usually achieve this by bypassing the same-origin policy of a website. As a result, the attacker can get access to user data and carry out actions on the user’s behalf.
Cross-site request forgery (CSRF)
CSRF attacks target authenticated (logged-in) users who are already trusted by the application. The attacker accesses a legitimate user’s account using the information found in session cookies and performs actions on their behalf without their knowledge or involvement. CSRF attacks are also known as session riding or one-click attacks.
Third-party security vulnerabilities
2. Audit dependencies using a package manager
npm audit (see below),
yarn audit, or
pnpm audit commands that let you run code audits at different audit levels:
npm audit [--json] [--production] [--audit-level=(low|moderate|high|critical)]
npm audit fix [--force|--package-lock-only|--dry-run|--production|--only=(dev|prod)]
common options: [--production] [--only=(dev|prod)]
3. Add Subresource Integrity (SRI) checking to external scripts
Subresource Integrity (SRI) checking is a feature built into modern web browsers (see browser support) that uses a cryptographic hash to verify the integrity of an external script.
integrity attribute of the
<link> element. To make the SRI checking work, you also need to add the
crossorigin=anonymous attribute that makes it possible to send a cross-origin request without any credentials.
For example, I used the aforementioned SRI Hash Generator to generate the following secure
<script> tag for the React library hosted on the Cloudflare CDN.
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.0.0-rc.0-next-3b3daf557-20211210/umd/react.production.min.js" integrity="sha256-9pH9+q1ELPzjhXRtae7pItnIlYsGKnDN3ragtQXNpQ0=" crossorigin="anonymous"></script>
onclick), as external .js files.
For better security, we’d also recommend that you establish a content security policy (CSP). This is a security layer in the communication between client and server that allows you to add content security rules to your HTTP response header.
If you don’t have any inline scripts on your page, it’s easier to set up a more effective CSP. You can use the
default-src directives to block all inline scripts, so if any malicious inline script tries to execute on your site, it will automatically fail.
5. Validate user input
Validating user input on both the client- and server-side is essential to avoid malicious code injections.
HTML5 forms come with built-in form validation attributes such as
pattern HTML attribute to validate the value of an input using a Regular Expression.
HTMLButtonElement and provides useful properties and methods for checking input validity against different constraints, reporting validity status, and performing other actions.
6. Escape or encode user input
To avoid XSS attacks, it’s also important to escape or encode incoming or unsafe data. Escaping and encoding are two technologies that convert special characters that can pose a security risk into a safe form.
> string in HTML.
textContent property instead of
innerHTML which is parsed as HTML (therefore the characters are not escaped).
7. Use a CSRF token that’s not stored in cookies
For instance, here’s an example of a CSRF token by the OWASP project that you can add to a form as a hidden input field:
<form action="/transfer.do" method="post">
<input type="hidden" name="CSRFToken" value="OWY4NmQwODE4ODRjN2Q2NTlhMmZlYWEwYzU1YWQwMTVhM2JmNGYxYjJiMGI4MjJjZDE1ZDZMGYwMGEwOA==">
8. Ensure secure cookie transmission
To further improve cookie security, make sure that your cookies are only transmitted via a secure protocol such as HTTPS that encrypts the data sent between the client and server machines. You can enforce the use of a secure protocol by adding the
;secure flag to the
Document.cookie property that gives you access to the cookies of a document.
You can use it together with the
;samesite flag that lets you control cookie transmission in cross-site requests. For example, using this flag with the
lax value allows cookie transmission for every same-site request and all top-level navigation GET requests, which makes user tracking possible but prevents a significant portion of CSRF attacks (this is the default browser setting for the
You can use the
;secure flag in the following way (here,
;samesite is set to
none, which allows cookie transmission for all cross-site and same-site requests):
// Source: https://developer.mozilla.org/en-US/docs/Web/API/Document/cookie#example_2_get_a_sample_cookie_named_test2
document.cookie = "test=Hello; SameSite=None; Secure";
Finally, you can make it harder for hackers to understand the structure and logic of your scripts by minifying and bundling your code using a tool like Webpack that comes with further security features. For example, you can add a nonce to every script it loads.