I am working on a project which uses React and Node.js. I am using React-router for the redirection of different paths, but I am concerned about the security.
If I have understand things correctly React-router operates on the frontend, so basically it should be pretty easy to edit the frontend code and get access to the paths? Or am I missing something?
I am doing authentication and I have secured the API endpoints so the user cant load any data, but I am concerned that the user could still see the paths without the data. I checked some tutorials and most of them says that the redirections is just for UX purposes, but I need them to also be secure.
Does it make sense and is there any tutorials out there where they show how to redirect in react in a secure way (thats not editable for anyone on the frontend)?
It’s all accessible to a user, they have literally all of the code on their computer if they visit your app. This doesn’t matter if the actual security is all handled backend (if a user needs eg a token they get from the backend, then they need that to authenticate with the backend to get it, they can’t create it using frontend code).
Yes, but how do i create it so that the paths are secure? If i would do it with normal javascript, you could just say ”redirect to login” on the serverside, but on react router you have to get the result from server and then set some state, and based on state it redirects you or not. So basically they should just edit the state and they can then see the protected page (even if they can not do anything).
At least thats how the tutorials I watched explains it.
Do you have any example or tutorial with a more secure method?
You can code split, but that’s not a security feature (if I really want the code, it’s still in the same place, if I’m determined I can get it).
If your app is populated with data from a secured API, then if the user is not signed in they can’t see it. You can “protect” the routes the same way you’d do it in JS – if user is not authorized, don’t show them the stuff. The way RR advises doing it is specific to RR, but it’s the same thing. And you can literally just do
{ userAuthorized && <Route .... /> }
If you want. This is just, at core, a UI nicety, it’s not really security. The reason it doesn’t matter is that if a user is not authorized then they can’t get the data from the backend – the fact they have the code that would render that data isn’t really relevant, because they can’t do anything.
As I say, doesn’t matter as long as you don’t do insecure things like hard-code API keys into the JS or allow direct access to something on a network the app sits in front of. Putting doing something silly security-wide aside, why would they manipulate it directly (not quite a rhetorical question)? An app has a purpose, will normally only work for that purpose, the users can’t “do whatever they please” because there are only a limited amount of things a given program can do. If you’ve built say a calculator, it’s only going to work as a calculator. An average user gains no benefit from directly accessing the internals. By analogy if a have a clock I can take the clock apart, fiddle with the mechanism, but personally I’m not going to do that because I just want a clock.
I just realized this comment isn’t really on topic so just ignore it if you like.
Summary
If a user can run the code, they can inspect it and manipulate it. Sure web code is a lot easier to get at, but even code running natively on the system is susceptible to this.
There is a reason why you can “find” so many pay apps “for free” on the Internet. Someone has taken the time to run the code through a disassembler/debugger and looked at the internals of the code. Maybe found where the app looks for some “key” (or whatnot), and either reversed engineered the process to where they can generate a valid “key”, or just patch parts of the code to do what they want it to do instead.
It is the same way you can find security vulnerabilities in code, you “just” look at it running (and/or do some static analysis).
We are also kind of getting into the domain of open vs closed source code here. If you rely on closed source code for security your basically doing security through obscurity. Not saying closed source doesn’t provide some benefits as it makes it more cumbersome to find what you are looking for, but it’s just a stop-gap (obviously, the real reason for closed source is so no one can “borrow” the code).
No, it doesn’t pose a huge a security issue. This is how JS works in a browser: the user is literally downloading all your code then running it, they can see any of that code.
Right, but how does that affect anything outside their browser? If they change the prices in their browser, that’s all they’re doing.
If, in this example, you have an e-commerce app, the actual thing that does anything useful is not the browser GUI code, that’s just a GUI. It makes no difference if the user alters the code of the GUI. Say they want to buy some products, so they go to the checkout, then they alter the final price and submit. They haven’t actually altered anything except that particular piece of HTML in their own browser. If they submit their basket to the actual e-commerce server, it’s not going to let them have the stuff at the price they chose.
Again by analogy, if you go into a shop, you can if you want just write what you feel the price should be on the price tags of things and take them to the counter – that’s not going to mean that you get those goods at the price you picked
Would the browser submit the state (price) as is? Or it would use the original value? That part wasn’t so clear.
I get you. And thanks for the reply.
Why i am so curious about this is because i am using a payment API that actually allow charges to be made on the frontend and you can confirm the payment on the backend - i would have loved to create charges on the backend.
That’s entirely down to how it’s coded. Maybe it could take the IDs of the products + and discounts + any shipping etc and calculate the price on the server then say whether there’s a mismatch as the user is in the page, before submission. Or it could have loaded all those into memory in the browser and just blindly submit with those user-altered values. But that’s fine because it’ll still do those lookups anyway when it hits the server so there’ll be a mismatch there and there’ll be an error, it shouldn’t be able to enter the impossible state that would be caused by a user altering the input. It’s like the user being charged £20 and then paying £0 – they still owe £20, them saying they’re only paying £0 isn’t going to change that
This is not to say it doesn’t happen, that sometimes things get coded which allow people to freely alter prices then submit (for example), and then they get stuff for free or whatever, but that’s just badly coded stuff (backend)
Right, but you aren’t running payments publicly on the front-end – the front end is a way to get those details to some kind of secure backend, and presumably that backend is some sort of financial system where payments and payees are tracked according to some business logic. Even if the frontend allowed users to do some shenanigans around payments, this isn’t going to benefit them, because the backend is still going to show that they have outstanding monies owed
In my case, and I am probably not alone in this, being able to manipulate state so that you can see the page that should be protected is actually a big deal.
Yes, the user would not be able to actually do anything, but they can still read and watch the layout.
So lets say that your app idea is to sell information about some topic. The user pays for your service and can then log in and read the hardcoded text on your site. Now, by using redirect with react-router anyone with some frontend skills can check your info for free and even copy your info just by changing some state.
In my case, the UI of my app is actually what sets it apart from others, and I would really not want a competitor to look at my UI.
So being able to see the UI and hardcoded text can be a big deal.
So I still wonder if there is any way to redirect on serverside and not based on state?
If the text content needs to have restricted access it would need to be served through some protected backend route. If you just hardcode the content it will be part of the bundle and anyone can just read it (no matter what).
Edit: I guess as was already suggested using code splitting and only (lazily) serving things to authorized users might work as well. I don’t really know much about this approach.
If user has to log in to access the site, then just changing the state on the frontend and making request should result in 401/403 error from the backend. If it’s not, then it’s a poorly coded backend.
Backend should never trust frontend, because users can just use tools like Postman or cUrl and make any request to any endpoint they want.
Yes excactly, and that is my problem woth the turotials for react-router. In React-router you just change the state and the path and its UI and info is being viewed. No request is made before you actually try to do anything. I think its weird that it is not the server that redirects.
A request is sent if user is logged in, but the “protected data” in this case is my UI, and yes, that is already on the frontend.
I tried to use redirect like this using express: res.redirect('/'), but nothing happens. I thought that it was the React-router who was blocking this? but maybe I do something wrong. Should it work? Also, If it works, why don´t people use this instead? It seems much simpler?