Notes on Cross-Site Scripting (XSS) and Cross-Site Request Forgery (CSRF) attacks and prevention in React apps
Last updated on 30 Dec 2024
Summary points on XSS and JWT in context of React apps, based on my understanding:
1) XSS seems to be mainly a JavaScript injection technique. XSS attacks can be Reflected (malicious script comes in the HTTP request), Stored (malicious script comes from database) and DOM-based (e.g. malicious script comes from input field).
2) React has some XSS protection. It automatically escapes string variables that are displayed in views. But a React app can still be vulnerable to XSS attack if it uses some features. For example, using dangerouslySetInnerHTML, using anchor elements whose href is set to user-supplied data, and passing user supplied data as props to React components.
3) Checking that a React app. is not vulnerable to XSS does not seem to be an easy task.
4) Production React apps should have React Dev Tools and Redux Dev Tools disabled as otherwise, it seems, the state variables data of React and Redux will be available via browser tools for debugging (Inspect in Chrome).
5) As per my understanding, JWT token approach can be of two main types: Single JWT auth token or a JWT access token and a JWT refresh token.
6) JWT token being stored in Local Storage is not recommended as XSS attacker that manages to get into the app can easily pick up the JWT token from Local Storage.
7) JWT token being stored in memory or state seems to be OK. But that also may not be perfect security. I do not have a clear understanding of how XSS attacker could pick up JWT token from memory or state (of app running on some other device (computer/mobile)). Note that if JWT token is stored in memory/state, for a React app, typically the user will have to re-login on browser display refresh of app page.
8) JWT token being stored in an httponly, secure, same-site cookie seems to be a secure approach but disadvantage is that client JavaScript code cannot access it. So additional backend API call(s) would be needed to get user info. like username, role, email id etc.
9) In case of JWT access token and JWT refresh token (both provided by backend), the access token has very short expiry time, while the refresh token has a significantly longer expiry time. Access token is needed for every API call. When access token expires, a new access token can be obtained using a specific API (refresh) endpoint which is sent the refresh token. But if the refresh token too has expired, the (refresh) API endpoint does not send an access token, and so the user has to login again.
10) One of the videos listed in this post whose source code repo is: https://github.com/gitdagray/react_jwt_auth , IIRC, stores Refresh token in httpOnly cookie and Access Token in memory/state. Has Axios code to detect access token expiry related failure and so automatically get new access token using refresh API endpoint and refresh token. Browser display refresh of app page in this version of app causes user to re login. A modified version is covered in another video mentioned in this post, that adds feature of persisting user login and so user does not have to re-login on browser display refresh of app page. It implements the feature without saving access token (or refresh token) in local storage. Related source code repo: https://github.com/gitdagray/react_persist_login .
=======================================
Note: Notes on Node.js related authentication and JSON Web Token (JWT), https://raviswdev.blogspot.com/2024/03/notes-on-nodejs-related-authentication.html , is a short post of mine having some links on JWT. One article from it is particularly relevent here: Where to store JWT in browser? How to protect against CSRF?, https://stackoverflow.com/questions/27067251/where-to-store-jwt-in-browser-how-to-protect-against-csrf .
What is cross-site scripting (XSS)?, https://portswigger.net/web-security/cross-site-scripting - Seems to have good explanation.
The wiki page on XSS, https://en.wikipedia.org/wiki/Cross-site_scripting , is a little hard to understand.
3 Ways to Fix the CORS Error — and How the Access-Control-Allow-Origin Header Works, https://medium.com/@dtkatz/3-ways-to-fix-the-cors-error-and-how-access-control-allow-origin-works-d97d55946d9 : Gives an example of "cross-site request forgery attack". May not be related directly to XSS.
Mentions Moesif Origin/CORS Changer & API Logger Chrome extension, "Allow cross-domain requests by override Origin and CORS headers.", as a quick fix for local development.
==========
Great IBM video: Cross-Site Scripting: A 25-Year Threat That Is Still Going Strong, https://www.youtube.com/watch?v=z4LhLJnmoZ0 , 9 min. 32 secs, by IBM Technology, Nov. 2024.
The video recommends: Cross Site Scripting Prevention Cheat Sheet, https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html .
At least one example of XSS is Java Script Injection, covered in a simple way (Reflected XSS: input is reflected back in response) in: Cross-Site Scripting (XSS) Explained, https://www.youtube.com/watch?v=EoaDgUgS6QA , 11 min. 26 secs, Mar. 2020.
Stored XSS: JS is stored on server side and then served out later (to possibly many users, and so more dangerous than reflected XSS).
Above YT video refers to https://xss.pwnfunction.com/ where some XSS 'games' are provided (site not maintained now but at least the first game 'Ma Spaghet' works.
In 'Ma Spaghet' I tried the below url which did not work (no alert was shown):
https://sandbox.pwnfunction.com/warmups/ma-spaghet.html?somebody=%3Cscript%3Ealert(1)%3C/script%3E
The provided solution in above site, works (alert is shown):
https://sandbox.pwnfunction.com/warmups/ma-spaghet.html?somebody=<svg%20onload=alert(1337)>
---------
JWT: Where to store JWT in the browser frontend?, https://www.youtube.com/watch?v=occfnVaZOXI , around 3 mins, Nov. 2021.
What does it mean when they say React is XSS protected?, https://stackoverflow.com/questions/33644499/what-does-it-mean-when-they-say-react-is-xss-protected
[Seems to be good article:] Exploiting script injection flaws in ReactJS apps, https://medium.com/dailyjs/exploiting-script-injection-flaws-in-reactjs-883fb1fe36c1 , Aug. 2017
=============================
Best Practices for React Data Security, Logins, Passwords, JWTs, https://www.youtube.com/watch?v=3QaFEu-KkR8 , 21 mins, Dave Gray, May 2022
Frontend GH: Seems to list only starter project code
Backend (Node.js) GH: Seems to list only starter project code
From video references:
disable-react-devtools, https://www.npmjs.com/package/@fvilers/disable-react-devtools : "A simple method to disable the React Developer Tools addon to access your application"
"Disable Redux dev tools" is the last video segment (labelled).
React Login Authentication with JWT Access, Refresh Tokens, Cookies and Axios, https://www.youtube.com/watch?v=nI8PYZNFtac, 41 mins, Dave Gray, Jan. 2022
Completed source code: https://github.com/gitdagray/react_jwt_auth
IIRC, stores Refresh token in httpOnly cookie and Access Token in memory/state. Has Axios code to detect access token expiry related failure and so automatically get new access token using refresh API endpoint and refresh token. Browser display refresh of app page in this version of app causes user to re login.
Handling JWT Access and Refresh Token using Axios in React App, https://blog.theashishmaurya.me/handling-jwt-access-and-refresh-token-using-axios-in-react-app , Jun. 2023
Access Tokens, Refresh Tokens, And User Data, https://stackoverflow.com/questions/74450944/access-tokens-refresh-tokens-and-user-data, Nov. 2022
Token Storage on Client Side, https://cheatsheetseries.owasp.org/cheatsheets/JSON_Web_Token_for_Java_Cheat_Sheet.html#token-storage-on-client-side
Where to store JWT token in react / client side in secure way?, https://stackoverflow.com/questions/69294536/where-to-store-jwt-token-in-react-client-side-in-secure-way , Sept. 2021
SPA using Token Handler, https://curity.io/resources/learn/token-handler-spa-example/
Slightly confusing article but is simple and so mostly easy to understand: How to Secure JWT in a Single-Page Application, https://javascript.plainenglish.io/how-to-secure-jwt-in-a-single-page-application-6a46e69fc393
Best way to store Access token and Refresh token using React?, https://www.reddit.com/r/reactjs/comments/10s9ume/best_way_to_store_access_token_and_refresh_token/
React Persistent User Login Authentication with JWT Tokens, https://www.youtube.com/watch?v=27KeYk-5vJw , 37 mins, Dave Gray, Feb. 2022.
Completed source code: https://github.com/gitdagray/react_persist_login . Shows a way to have persistant login but without storing the access token in local storage.
Modifies code of previously mentioned video: React Login Authentication with JWT Access, Refresh Tokens, Cookies and Axios, with its completed code at: https://github.com/gitdagray/react_jwt_auth. Adds feature of persisting user login and so user does not have to re-login on browser display refresh of app page but implements the feature without saving access token (or refresh token) in local storage.
===============
===============
What is an attack vector?, https://www.cloudflare.com/learning/security/glossary/attack-vector/ :
"An attack vector, or threat vector, is a way for attackers to enter a network or system."
Same-origin policy, https://developer.mozilla.org/en-US/docs/Web/Security/Same-origin_policy : "The same-origin policy is a critical security mechanism that restricts how a document or script loaded by one origin can interact with a resource from another origin." "It helps isolate potentially malicious documents, reducing possible attack vectors." The article is not so easy to understand.
Same-origin policy, https://web.dev/articles/same-origin-policy - this is easier to read but, as expected, not as informative as above MDN page. The article covers clickjacking and ways to prevent it using content security policy or X-Frame-Options to the HTTP headers. I have not got a clear understanding of how to do this in a React frontend app but React apps too seem to be vulnerable to this clickjacking.
Handling Web Application Security, https://engineering.vayana.com/blog/Engineering/web_application_security/ covers React and clickjacking besides XSS and CORS. But I could not understand it well in my quick-read. Perhaps I need to visit it again and study the article carefully.
How to Make Your React App Safer, https://www.youtube.com/watch?v=T3pr4WjSAOQ , 13 min. 28 secs., Nov. 2022
------
I have the impression that in clickjacking the browser address bar will show the fake url/address but I could not clearly confirm that through videos/articles on clickjacking. If my impression is right then clickjacking seems to be just a quick way of fooling a user visiting a fake site to think he/she is visiting a genuine site. Even without clickjacking, a malicious hacker could recreate the UI of a genuine site. The key to identifying that is checking that the browser address url is showing the genuine site's address (and not a fake site address).
I also read in some article/post that Netlify hosted site's HTTP headers to combat clickjacking like X-Frame-Options have to be set manually as they are not set by default. So my React and other apps hosted on Netlify can be easily clickjacked but then my apps do not hold any sensitive info. and so clickjacking my apps would be a waste of time for the clickjacker.
==================
Comments
Post a Comment