Avoiding CSRF with Remix

Rate this content

Remix 'Data Writes' go back to the basics of the web when it comes to form submissions. But therein lies a trap if you're not careful - Cross site request forgery (CSRF) can rear its head. In this session we'll explore what CSRF is. How it can be exploited and what you can do to make sure your Remix application isn't vulnerable.

7 min
10 Jun, 2022

Video Summary and Transcription

Welcome to my session on avoiding CSRF with Remix. Remix helps protect against CSRF by thinking about actions in terms of HTML form elements. To avoid CSRF with Remix, set the same site attribute on cookies and consider using a token in addition to the attribute. The token-based approach involves generating a unique token per session and form, transmitting it with the form, sending it back when the user submits the form, and securely validating it on the server side.

Available in Español

1. Introduction to CSRF and Remix

Short description:

Welcome to my session on avoiding CSRF with Remix. CSRF stands for Cross-Site Request Forgery, where the attacker tricks the user into accessing a URL to perform an action using their existing session. Even if using post, an exploit can be achieved with an iframe and a separate URL. Remix helps protect against CSRF by thinking about actions in terms of HTML form elements. To avoid CSRF with Remix, set the same site attribute on cookies and consider using a token in addition to the attribute.

Hi and welcome to my session on avoiding CSRF with Remix. This is a lightning talk, so we're going to go through this in a pretty whirlwind fashion. So let's start up by talking about what CSRF is. Like most security exploits, it's got an acronym and it stands for Cross-Site Request Forgery. And in this scenario, basically the attacker tricks the user into accessing the URL and then this URL will perform an action using their existing session.

So a simple example, or perhaps the worst example, is an image with a URL and that URL performs an action. So before you say, no, I want to write code like this, I've seen this in apps that I've audited, and obviously the first thing the user is doing wrong here is they're using get to perform some sort of action. But equally, this kind of exploit can be achieved even if it's using post. And we do that by having an iframe with a hidden height and width, and that embeds a separate URL. And in that URL we have the form, the post to that endpoint, and we have an onload function that submits it the second the form is loaded.

So let's talk about Remix a bit. Remix gets you thinking about actions in terms of the building blocks of the web, which is the HTML form element. And if you've been building apps with JavaScript, you've probably been using things like Fetch or Axios, and in these scenarios, of course, it protects you. Unless, of course, you're using access, allow origin, you know, star, and you're allowing credentials to come through. And in that case, you're in the same boat. So because we're submitting forms again via straight up, you know, multi-part form data, we need to think about Cross-Site Request Forgery.

So let's have a look at a simple Remix form example. We've got a primitive form here with a text field and a Submit button. We've got some sort of loader to check the user has got authenticated session because Cross-Site Request Forgery does require these to be logged in. You know, you're performing an action using their existing session that they didn't intend to do. And so we're not going to go into the details here, but yeah, the loader is making sure the user's got a session. We've then got an action in our component that does some sort of write to the database or similar. Something that performs some sort of action that, you know, can't be reversed. So how do you avoid Cross-Site Request Forgery with Remix in this scenario? Well, the first thing you should do is set the same site attribute on your cookies. So you can set that to lax, which will mean the browser will only send the cookies if it's a get request coming from another domain. Or you can set it to strict, which means it won't send any cookies for any requests that originate from another domain. So you might need to check whether you're using some sort of authentication flow that redirects to other sites as to which is the most appropriate for your site. But unfortunately, according to OWASP, this isn't enough and we shouldn't replace having a token. And the main reason for that is that only 93% of browsers support the same site attribute at this stage. We're almost there.

2. CSRF Token Generation and Validation

Short description:

The token-based approach involves a four-step process: generating a unique token per session and form, transmitting it with the form, sending it back when the user submits the form, and securely validating it on the server side. To generate the token, secure random keys are generated, including a hash salt and a private key. The token is transmitted with the loader and returned in the loader data, which can be accessed in the form. Validation is done by regenerating the token and comparing it to the submitted version. If they don't match, an error is thrown.

Your app might have higher depending on your user's browser mix. So the token-based approach is commonly called synchronize the token pattern and it's basically a four step process.

The first thing is you have to generate a unique token per session, per form. You have to transmit that with the form. You have to send it back when the user submits the form and then you have to securely validate it on the server side.

So we start by generating some secure random keys. We generate a hash salt and this is something that you shouldn't store in your database. It should be on disk or environment variables so that if your database is compromised even then the hash salt is not leaked. You should also have a private key and both of these you can generate using the random bytes package from the crypto.

So the first step is to generate a unique random seed per session and so we do this by checking if the seed already exists in the session. If it does we use that. If it doesn't, we generate a new seed using again the random bytes function and we store that in the session. Then we need to generate a unique token for per session and identifier and in this scenario the identifier would be something unique for that form or operation and this prevents the same token being valid for two different operations and prevents token reuse.

So to do this we would take that hash, so we take our private key, we also take the seed and we combine the three together and we create a HMAC digest of that, which is basically a hash. It gives us a nice unique token. We have to transmit that token with the loader. The first thing we do is we generate the token and we return it in our loader data and that means we can then get that back in our form by using the route data. So we get our CRSF token from there and we transmit that in the form in our hidden field.

We then need to validate the code, so if we write a nice little utility function for validating it will regenerate the token based on the unique identifier and session and then it will compare the two using timing safe equals against the version that was submitted with the form. We use timing safe equals here to avoid timing attacks.

So how do we use this utility function? In our action, we can just call validate CRSF token using the value from the submitted form and if the two don't match then we throw an error.

That's a whirlwind tour of CSRF validation for Remix. If you've got any questions, please contact me via the GitHub Discord server for this conference or you can message me on Twitter.

Check out more articles and videos

We constantly think of articles and videos that might spark Git people interest / skill us up or help building a stellar career

React Summit Remote Edition 2021React Summit Remote Edition 2021
33 min
Building Better Websites with Remix
Top Content
Remix is a new web framework from the creators of React Router that helps you build better, faster websites through a solid understanding of web fundamentals. Remix takes care of the heavy lifting like server rendering, code splitting, prefetching, and navigation and leaves you with the fun part: building something awesome!
React Advanced Conference 2021React Advanced Conference 2021
39 min
Don't Solve Problems, Eliminate Them
Top Content
Humans are natural problem solvers and we're good enough at it that we've survived over the centuries and become the dominant species of the planet. Because we're so good at it, we sometimes become problem seekers too–looking for problems we can solve. Those who most successfully accomplish their goals are the problem eliminators. Let's talk about the distinction between solving and eliminating problems with examples from inside and outside the coding world.
Remix Conf Europe 2022Remix Conf Europe 2022
23 min
Scaling Up with Remix and Micro Frontends
Top Content
Do you have a large product built by many teams? Are you struggling to release often? Did your frontend turn into a massive unmaintainable monolith? If, like me, you’ve answered yes to any of those questions, this talk is for you! I’ll show you exactly how you can build a micro frontend architecture with Remix to solve those challenges.
Remix Conf Europe 2022Remix Conf Europe 2022
37 min
Full Stack Components
Top Content
Remix is a web framework that gives you the simple mental model of a Multi-Page App (MPA) but the power and capabilities of a Single-Page App (SPA). One of the big challenges of SPAs is network management resulting in a great deal of indirection and buggy code. This is especially noticeable in application state which Remix completely eliminates, but it's also an issue in individual components that communicate with a single-purpose backend endpoint (like a combobox search for example).
In this talk, Kent will demonstrate how Remix enables you to build complex UI components that are connected to a backend in the simplest and most powerful way you've ever seen. Leaving you time to chill with your family or whatever else you do for fun.
Node Congress 2022Node Congress 2022
26 min
It's a Jungle Out There: What's Really Going on Inside Your Node_Modules Folder
Top Content
Do you know what’s really going on in your node_modules folder? Software supply chain attacks have exploded over the past 12 months and they’re only accelerating in 2022 and beyond. We’ll dive into examples of recent supply chain attacks and what concrete steps you can take to protect your team from this emerging threat.
You can check the slides for Feross' talk here.

Workshops on related topic

React Summit 2022React Summit 2022
136 min
Remix Fundamentals
Top Content
Featured WorkshopFree
Building modern web applications is riddled with complexity And that's only if you bother to deal with the problems
Tired of wiring up onSubmit to backend APIs and making sure your client-side cache stays up-to-date? Wouldn't it be cool to be able to use the global nature of CSS to your benefit, rather than find tools or conventions to avoid or work around it? And how would you like nested layouts with intelligent and performance optimized data management that just works™?
Remix solves some of these problems, and completely eliminates the rest. You don't even have to think about server cache management or global CSS namespace clashes. It's not that Remix has APIs to avoid these problems, they simply don't exist when you're using Remix. Oh, and you don't need that huge complex graphql client when you're using Remix. They've got you covered. Ready to build faster apps faster?
At the end of this workshop, you'll know how to:- Create Remix Routes- Style Remix applications- Load data in Remix loaders- Mutate data with forms and actions
React Summit 2023React Summit 2023
106 min
Back to the Roots With Remix
Featured Workshop
The modern web would be different without rich client-side applications supported by powerful frameworks: React, Angular, Vue, Lit, and many others. These frameworks rely on client-side JavaScript, which is their core. However, there are other approaches to rendering. One of them (quite old, by the way) is server-side rendering entirely without JavaScript. Let's find out if this is a good idea and how Remix can help us with it?
Prerequisites- Good understanding of JavaScript or TypeScript- It would help to have experience with React, Redux, Node.js and writing FrontEnd and BackEnd applications- Preinstall Node.js, npm- We prefer to use VSCode, but also cloud IDEs such as codesandbox (other IDEs are also ok)
Remix Conf Europe 2022Remix Conf Europe 2022
195 min
How to Solve Real-World Problems with Remix
Featured Workshop
- Errors? How to render and log your server and client errorsa - When to return errors vs throwb - Setup logging service like Sentry, LogRocket, and Bugsnag- Forms? How to validate and handle multi-page formsa - Use zod to validate form data in your actionb - Step through multi-page forms without losing data- Stuck? How to patch bugs or missing features in Remix so you can move ona - Use patch-package to quickly fix your Remix installb - Show tool for managing multiple patches and cherry-pick open PRs- Users? How to handle multi-tenant apps with Prismaa - Determine tenant by host or by userb - Multiple database or single database/multiple schemasc - Ensures tenant data always separate from others
Remix Conf Europe 2022Remix Conf Europe 2022
156 min
Build and Launch a personal blog using Remix and Vercel
Featured Workshop
In this workshop we will learn how to build a personal blog from scratch using Remix, TailwindCSS. The blog will be hosted on Vercel and all the content will be dynamically served from a separate GitHub repository. We will be using HTTP Caching for the blog posts.
What we want to achieve at the end of the workshop is to have a list of our blog posts displayed on the deployed version of the website, the ability to filter them and to read them individually.
Table of contents: - Setup a Remix Project with a predefined stack- Install additional dependencies- Read content from GiHub- Display Content from GitHub- Parse the content and load it within our app using mdx-bundler- Create separate blog post page to have them displayed standalone- Add filters on the initial list of blog posts
React Summit 2023React Summit 2023
56 min
0 to Auth in an hour with ReactJS
Passwordless authentication may seem complex, but it is simple to add it to any app using the right tool. There are multiple alternatives that are much better than passwords to identify and authenticate your users - including SSO, SAML, OAuth, Magic Links, One-Time Passwords, and Authenticator Apps.
While addressing security aspects and avoiding common pitfalls, we will enhance a full-stack JS application (Node.js backend + React frontend) to authenticate users with OAuth (social login) and One Time Passwords (email), including:- User authentication - Managing user interactions, returning session / refresh JWTs- Session management and validation - Storing the session securely for subsequent client requests, validating / refreshing sessions- Basic Authorization - extracting and validating claims from the session token JWT and handling authorization in backend flows
At the end of the workshop, we will also touch other approaches of authentication implementation with Descope - using frontend or backend SDKs.
React Advanced Conference 2023React Advanced Conference 2023
104 min
Building High-Performance Online Stores with Shopify Hydrogen and Remix
I. Introduction- Overview of Shopify Hydrogen and Remix- Importance of headless e-commerce and its impact on the industry
II. Setting up Shopify Hydrogen- Installing and setting up Hydrogen with Remix- Setting up the project structure and components
III. Creating Collections and Products- Creating collections and products using Hydrogen’s React components- Implementing a Shopping Cart- Building a shopping cart using Hydrogen’s built-in components
VI. Building the home page with Storyblok- Cloning the space and explaining how it works- Implementing Storyblok in the repo- Creating the Blok components- Creating the Shopify components- Implementing personalisation