I have been reading around CSRF for the past few days and feel like I have a good grasp on what it is and how to prevent it. I am building a small Express/React application that will have a secure admin area for updating the app content and I want it to be protected from CSRF.
I understand that it is common for the server to generate the CSRF token and then send it to the client along with the view (page) that has been requested (the token can then be hidden in a HTML form input tag). However, my Express API does not serve HTML, it is a REST API that only returns JSON data. The UI is built with React, running on a different port from the server.
My question is; Where do I securely store a token generated on the server?
For example, if I log in as admin by hitting '/api/login', generate a token, and send it back to the client in the API response, what should I do with it now?
The original plan was to use Redux to store the token but from reading this post Is Redux secure?, this does not sound ideal.
I considered using React env variables but have also read that these are exposed in the build.
Obviously localStorage is also a bad idea...
I am really struggling to find a solution to this problem using the tools I am implementing i.e. Express/React
Any help, links, advice, criticisms would be appreciate, I want to learn to build apps with security in mind
I understand that it is common for the server to generate the CSRF token
The server needs to generate two CSRF tokens
and then send it to the client along with the view (page) that has been requested (the token can then be hidden in a HTML form input tag).
One token is commonly sent as a cookie, another can be sent as HTTP header. It doesn't need to be sent inside HTML body as a HTML form input tag (or any other part of the body) though it can be sent this way.
My question is; Where do I securely store a token generated on the server?
You don't have to store a token on the server. You can but you don't need to.
The original plan was to use Redux to store the token
The Redux store is on the client, in browser's memory. In theory one React component (that extracts the second CSRF token from server response) can temporarily store the token in the store so that another React component can get it from there and put into the next request before it's sent to the server.
Obviously localStorage is also a bad idea...
Yes
Any help, links, advice, criticisms would be appreciate, I want to learn to build apps with security in mind
Links
With Express is very common to use this middleware. The steps can be found here.
Criticisms
This is strictly speaking off topic in the context of CSRF related Q/A, but ...
The UI is built with React, running on a different port from the server.
That hints to the possibility of using react-scripts which start webpack-dev-server. It's fine for development, not good for deployment in production. However this is a separate topic, serving React app's build artifacts (.html file, script bundles) to webclients has nothing to do with CSRF attack and its mitigation.
I want to learn to build apps with security in mind
Then you might consider using one webserver instead of two (frontend to serve React app and backend to serve API responses). Using one server results in production deployment which is not only less complex and costly, but also more secure because two servers have larger attack surface and with one server you don't need to weaken security by using CORS.
Related
Let's imagine a client opens your nuxt.js website on the index page. From there, they authenticate (you used #nuxtjs/auth-next for that purpose). Then they move to a secure page that only authenticated users can see. This secure page is a .vue file in your "pages" folder with middleware: ["auth"].
Now, how is this page really secure ?
I mean, couldn't a malicious user temper with the page and access it without being authenticated anyway ? Because the "security" in this scenario is only implemented on the client side right ? [Edit]
Your application being an SPA at the end, if you want to bypass a middleware with it's security checkup, you could disable the JS on the page. But then, since no content is generated directly, you won't see anything because it's not here (as a static file).
If your app is isomorphic (basically has a ssr: true), the auth module will still disable the access to those pages (you can double check).
At the end, the critical info is received when:
you do have a valid JWT token (after some login)
you submit an HTTP query to the backend
the backend acknowledges it and the token is valid
the backend gives you the sensitive info via an HTTP response
At the end, your client side code doesn't need to be secure. If somebody somehow hacks your client side state and reaches the sensitive page, he will still not have a valid JWT token since the verification still happens on the backend.
The one that can be generated only when sending the proper credentials to the backend and having the backend validating those.
Now, how is this page really secure ?
The protected content is served from a request if a valid access token has been provided by the client.
The protected content is provided at runtime.
Because the "security" in this scenario is only implemented on the client side right ?
The security is not only implemented on the client side.
The premise is: The access token has been obtained securely through an authentication flow with an auth-server.
I recommend to read more about auth flows if this sounds unclear.
Auth0 has some good documentation on different flows.
https://auth0.com/docs/authorization/flows
Then, what is the best way to show a complex page to authenticated users only ?
The content is provided at run-time. Server-side or client-side.
There are some setup guides here for Nuxt.
Here is the first (Auth0) I found from the list.
https://auth.nuxtjs.org/providers/auth0
I don't know how updated those guides are, but the auth service providers tend to have updated guides themselves.
I started a Django app and i created the whole authentication layer using Django-Allauth, it already has quite some features such as email confirmation, password reset and two factor authentication. Now i realized that, since my app will be heavily interactive and with a lot of real time features, i'm going to need a Vue SPA to use with Django, so i'm thinking of creating the Vue SPA on the same server and domain and have Django as a Rest API.
Here is my problem: since i already made the whole authentication part using Django templates and Django urls, if i separate the rest of the frontend from the backend, will i have to rewrite everything? Is it possible to have a Vue app and a Django backend app separated on the same domain where authentication is handled by Django templates and all the rest is a Vue app with vue routes and all the other interactions are handled by Django Rest Framework endpoints?
So maybe something like this:
urlpatterns = [
path('accounts/signup/', SignUpView.as_view(), name='signup'), #Django template
path('accounts/login/', LoginView.as_view(), name='login'), #Django template
...
]
And these are the only Django-handled urls where the page is rendered by Django views. Once the user is logged in, they will be redirected to the VueJS app.
My personal opinion, it's not worth it to keep a bunch of server side pages just for sign-up, login, ... Managing both server-side pages and front-end pages in long run is a headache. But if you like that way, here are my suggestions.
For authentication, use Django auth. No matter if it's a server side HTML page or it's an API end-point. Django auth is simple and secure. Don't roll your own auth, don't store tokens in localstorage or so.
Fully separate these 3:
Front-end URLs (i.e. routes stored in Vue)
Back-end page URLs (i.e. HTML pages severd by Django)
Back-end API end-points URLs (i.e. the ones user never see, only Vue uses them under the hood)
They can be on separated domains but it can be just by a path prefix as well. As you yourself suggested in a comment.
Now when user visits some page in BE, it will use server side rendering and every user click is a browser refresh. Until you hit a FE URLs, then your front proxy should redirect user to FE or you'll serve JS files directly from Django. After that every user click is handled inside Vue without a refresh. If user hits a URL prefix that's for BE, then FE needs to do something like document.location = "/server-side/some-page.
BTW few days ago I answered another question that was similar to this, maybe you find the answer or comments there useful.
So in order to log in from the SPA i need to send a csrf token, and in order to get the token i can create a Django view that returns a CSRF token to the user so that it can be used to login. Wouldn't it provide attackers a way to attack my server (stackoverflow.com/questions/43567052/…)
My suggestion is to turn CSRF protection off and instead make session cookie samesite=Lax (I think that's default in newer versions of Django). All major browsers support this and it prevents CSRF.
Otherwise you can read token from another API or from cookie like here
So on production i will use Nginx to have the Vue app and the Django backend app on the same server and domain, but on development how can i do that? If i run the two apps on different terminals, won't django consider the Vue app to be in a different server?
It can't understand what server it is. The only thing you should care is the domain of the cookie. It should be set on your BE domain. When running on local both FE and BE are running on domain "localhost" so there should be no issue.
I have a problem trying to figure it out for few days, still didn't get any rigid solution.
I have an angular app which will be publicly available so no login or credential is needed to open the website, and user can have an Id as query param. lets' say www.mysite.com/123
to retrieve data for 123, I have a backend, that needs authentication with clientId and clientSecret, to get access_token and then call the api with access_token to get information.
If I put clientId and clientSecret in the code a hacker can steal it and will be using it.
There were some suggestion to enable CORS on backend to make sure only requests from my site will be handled. which I already did, but with knowing the clientId and clientSecret even if CORS is enable a hacker can send requests from postaman by adding origin and referrer as header.
I tried Angular Universal for server side rendering hoping the api call will be run on serve side and will be hidden from user, but api call still happing in front end.
Really stuck in this problem any kind of help is appreciated.
Since the application is small and it's only hosting a web component developed by stencilJs, if other languages such as react or vue can support my scenario I can switch
You can go extensive ways of obfuscating statically inserted token in the frontend client build, yet it is still going to be there and the only thing it will add — extra steps for an attacker to reverse it, at least to my knowledge.
So to explore the solution to your problem, i guess you want to define it in the more narrow way, i.e what are you trying to protect:
resource requiring privilege (admin panel)
then your answer will be dynamic auth.
protect your api from external usage/ddos
CORS, ratelimiting, dynamic token issuing(take notice that strategy still will be available inside frontend client code)
also i think owasp guidelines will be a good read on the topic:
https://cheatsheetseries.owasp.org/cheatsheets/REST_Security_Cheat_Sheet.html
I think i should clarify that in my opinion the solution that you are going to implement in the end in the case of the "protection of the api" is going to be building fences to jump over, rather than sealing api completely from the 3rd party usage.
I'm working with auth in Nextjs, I'm wondering what is the best strategy to handle authentication in NextJS ?
Here my services structure :
If I understand well I have to handle the server side rendering in NextJS, so I understand I have to put cookies from my external server to my NextJS client, then handle the server side rendering checkings. To do that I assume I have to create connection between the NextJS server and the other services. Before dive more deeper in the subject I would discuss with you about the possibilities available to me. It seems the NextJS auth is a subject in plain development.
Any hint would be great,
Thanks
I've recently added an example with cookie auth which explains what you are trying to do on the frontend.
For the backend, optimally you'll have your API in an external server, apart from the server you use for rendering your Next.js app. This API will handle the database and the token creation business. Then the basics of the authentication are like this:
The client POST a request with username and password to the server.
The server gets the request and generate a token based on the data received.
If everything went okay validating the data, the server responds with the token, e.g., { token: "secrettoken" }.
The client receives the token and saves it in a cookie. Optionally you redirect the user to the /dashboard or /profile if everything is okay.
The client, on restricted pages, will check if the cookie exists and optionally validate that against the server, you do this last part in getInitialProps. If the cookie validation fails you redirect the user away.
I've created a small library to abstract this logic.
So in the end, your Next.js app shouldn't know what's happening in the server, it only should receive the token, save it, validate it, and redirect the user if something is wrong.
How you want to handle the token creation, on the external server, is up to you.
Check out this thread. There are several examples of how to do Authentication with JWT, OAuth etc throughout the thread. You'll see that the examples are utilizing getInitialProps and there are several examples utilizing cookies throughout to extract the Authentication tokens.
You'll have to write a custom server.js file using express.js to serve the tokens through your route requests. I'm assuming by "external server" you mean some third party Authenticator using OAuth or OpenId protocols to retrieve tokens. If so, you're right to say that you'll need to request the tokens (or Authentication mechanism) from those external services and then decide how you're going to utilize them in your own client. You'll probably be using getInitialProps to do what you need to do with your Authentication tokens in the client once you are rendering to the browser.
More examples of Authentication here -- one for firebase and another for Apollo.
Just to add to the answers if you want to use Auth0 specifically. In the interview on http://www.fullstackradio.com/112 around the 1:06 min mark Guillermo Rauch mentioned that if he were to implement authentication all over again he would use Auth0, so I created a minimal repo using Auth0 and Nextjs with Serverless functions.
Like #jolvera suggested there is an API in an external server, apart from the server used for rendering the Next.js app. This API is located in ./auth/auth.js. It handles the token creation business, and could be extended to handle the database.
The HOC component in ./utils/withAuth.js calls the auth.js lambda for the user information, and is only able to retrieve it if the client side is authorized. Otherwise the user information is undefined. Additionally there is an event listener similar to the one in with-cookie-auth which syncs logouts across tabs.
Also one other note, don't get confused with the Nextjs example on Auth0's blog. That example is extending the Nextjs server, and isn't the solution you want if you are deploying Next to serverless. It doesn't have the separation of concerns with page routing and authentication.
This is a design question for AngularJS websites that access a REST API. Since all the AngularJS code can be viewed from the client side (assuming obfuscation is not completely secure) how do you hide the API access credentials (the API key and password or even a JWT)?
This can be extended to a broader question about how other application logic can be hidden in an AngularJS website?
My research led me to some insights, one of which was
http://billpatrianakos.me/blog/2016/02/15/securing-api-keys-in-a-javascript-single-page-app/
But this has me more confused now, since the post suggests an SPA connecting to a REST API is not a good architecture. I thought it was and now can't figure what the right approach is.
The closest I can come to an answer is this resource:
https://developers.facebook.com/docs/facebook-login/security#appsecret
Facebook, is pretty good with their security and say:
Never include your App Secret in client-side or decompilable code.
Use unique short-term tokens on clients.
In short, do not keep API secrets on the client side
Answering the discussion in comments for sake of not being brief:
And then my question would be "what then is the correct architecture for SPAs and server side code (or database access)?".
There's no one correct architecture, it depends on the size and scope of your project. It will also depend on what frontend and backend frameworks you choose. Those choices also will depend on how many other APIs you are calling, or what other developers or you are most familiar with.
Speaking more specifically about security though, ideally you'd like to set up a session for the user which consists of a token that the user uses to identify himself. This is usually generated for each user by the server when they login. Generally this is provided by the framework you are working in, but even if it isn't, it's fairly simple to build. You will want to prevent cross origin requests (making sure the user is actually on YOUR frontend) and have secure connections (setting up SSL and https, though this can get complicated). You will generally want to run your JS code through something like Uglify to prevent it from being too easy to look through, but this does NOT guarantee that people cannot take that code and un-uglify it.
As the other answers have suggested, you should never keep API keys or any secrets in the client source code. There is no way to hide anything on the client, and obfuscation != security.
If you are looking to architect secure authentication/authorization into your app, you will want to return a JWT to the AngularJS application. You can then pass this JWT as a Bearer token to your API which will verify the validity of the token and allow the API to authorize access to the AngularJS application.
As for where to store the JWT token, you can store it in either Local Storage or in a cookie. There are serious considerations between choosing whether to store the token in either of these locations.
If security is your concern, I would look into the OAuth 2.0 Implicit Flow.
Don't put API keys in your client side source code. Keep them on your server, and have your client make a request to YOUR server, which then calls out to external APIs for data.