Comments (9)
Hi @Jrfidellis ,
It is an interesting question.
Before going further on whether a CSRF token is necessary or not, I’ll dwell a bit on some definitions and concepts of web development.
General Concepts
1. Cookies
Cookies are a just a technology to:
- store small pieces of data on the client host (using a key/value mechanism),
- and send and set this data to and from the server.
For example, if we want to save the value xfe4h8ame56ez
with the name my_key
on the client host, the server can add the header Set-Cookie: my_key=xfe4h8ame56ez; Path=/
in its HTTP response. When receiving it, the user’s web browser creates a cookie called my_key
with the value xfe4h8ame56ez
. Then, on every new request to the server, the browser sends back the value of this cookie by adding the header Cookies: my_key=xfe4h8ame56ez
in the request.
As a result, cookies do not define whether a communication is stateless or not. It’s just a technology to store small pieces of data (user preferences, themes, session id, api key, etc). But they are generally very useful (and largely used) when working with stateful sessions.
2. Stateless communication
In the original thesis that introduces the REST architectural style, Roy Thomas Fielding defines the client-stateless-server style as follows:
Each request from client to server must contain all of the information necessary to understand the request, and cannot take advantage of any stored context on the server. Session state is therefore kept entirely on the client.
In a stateless communication, servers do not have stored contexts.
A word about sessions (to understand the definition): a session describes the fact that we keep a state across several requests. They are usually divided in three categories :
- Client sessions store the state on the client host.
- Server sessions store the state on the server in memory (default behavior of the
express-session
middleware) or in a file.- Database sessions store the state in an database. Django and FoalTS store by default the state in the SQL database. In general, database sessions are stored in a
redis
database.Usually when people talk about sessions they mean server or database sessions.
3. Stateless or stateful?
Using stateless communication is indubitably easier. As we don’t have to manage stored contexts on the servers, the scalability and the deployments are facilitated.
However, in many situations (logging, csrf protections, etc), we cannot get rid of stateless communication. That’s why, as a convention, we usually speak of RESTful APIs when the communication is really stateless.
What about CSRF protections?
Coming soon!
from foal.
Hi @Jrfidellis ,
Sorry for the late reply!
FoalTS aims to eventually be a backend framework for Single Page Applications. The reason why the "get started" tutorial uses Server Side Rendering is for simplicity. The beginner does not have to know a particular frontend framework to learn FoalTS and he/she usually understands what SSR does.
However future releases will focus on how to integrate FoalTS with a frontend application. Especially the createapp
command will support three special flags --angular
, --vue
and --react
to directly use FoalTS with these three common frameworks. Basically here are the steps that the command will follow :
- Install the CLI of the frontend framework if it hasn't been already installed.
- Create the frontend app with this CLI.
- Create the backend app with the FoalTS CLI.
- Create and update files to link both projects and make them work both together in development and production (for example: setting a proxy in development to redirect requests from the Angular port 4200 to port 3000).
I will first focus on the Angular integration and the docs will then have a "Get started with Angular" tutorial.
Regarding the LoginController
, the generated controller indeed uses the SRR pattern with redirections. But you can also avoid these redirections by removing the redirect
property. If you feel like updating the authentication doc, I'll review it ;)
redirect = {
// if `logout` is not defined then the server returns a 204 when requesting GET /logout.
// if `success` is not defined then the server returns a 204 on success.
// if `failure` is not defined then the server returns a 401 on failure.
};
A last word about SSR: even if we eventually use a SPA in the frontend we will need to use SSR when the application loads to send the csrf token.
from foal.
Thank you, that makes sense.
I just have one more question:
A last word about SSR: even if we eventually use a SPA in the frontend we will need to use SSR when the application loads to send the csrf token.
Why a CSRF token is even necessary whit REST? I believe that a REST API should be stateless and should not accept data from either a browser cookie or session (directly). Limiting the request source (to the frontend URL, for example) should be enough to prevent CSRF. (using SSR CSRF seems necessary, no doubt).
I'm using this conversation as a opportunity to learn so don't mind if i say nonsense, if you could help me understand i would be grateful.
When i get some extra time i will submit a PR with the doc changes.
Thanks @LoicPoullain!
from foal.
Hi @Jrfidellis, just a little message to tell you that I have not forgotten your question. I just want to meet someone next week (working in security) to discuss about this, to be sure of my answer;).
from foal.
Thank you very much @LoicPoullain! I'm looking forward to know about your thoughts on CSRF.
There is just one thing that i disagree there.. in my opinion a ideal API shoudn't send a header like Set-cookie
, the API should send back the token (xfe4h8ame56ez
) in the request body and the frontend should decide what to do with him.
I suppose that send a header like Set-cookie
wouldn't work if you are calling the API from a mobile app or desktop application.
"As a result, cookies do not define whether a communication is stateless or not." Agreed, i was wrong about that.
from foal.
There is just one thing that i disagree there.. in my opinion a ideal API shoudn't send a header like Set-cookie, the API should send back the token (xfe4h8ame56ez) in the request body and the frontend should decide what to do with him.
I guess that it depends on the context. I saw some people saving their JWT in a cookie and some other not. One advantage of saving a token in a cookie with the option HttpOnly: true
is that the token cannot be stolen via an XSS attack. However, that's right, it's more common to see the key/token sent back in the request body (or custom header).
I suppose that send a header like Set-cookie wouldn't work if you are calling the API from a mobile app or desktop application.
I think some libraries must exist to parse cookie headers on mobile or desktop apps since they are just strings with keys / values. I didn't do a lot of mobile programming though to confirm it.
What about CSRF tokens ?
Applications using authentication with sessions/cookies are more vulnerable to CSRF attacks. A malicious website A may send a request to B to perform a certain action. And as B's cookies will be (theoretically) sent with it, the B server will receive the authentication token and so allows the action.
One way to prevent that is to ask for a CSRF token. This token is sent in every page of B and required in any incoming request. This way, requests made from A to B won't work, since A does not have the CSRF token.
Drawbacks of using CSRF tokens
Using CSRF tokens can be annoying as it requires SSR, which is not convenient when developing a SPA with Angular/Vue/React, and sessions, making it more difficult to manage scalability and frequent deployments.
I guess this is your point (tell me if I'm wrong). I might have found a solution in the next comment to solve this problem. Let me know what you think.
Note: Even when using authentication with JWT, you will need, at some point, to store a context on the server to support token blacklisting. This context may be stored in a file (server session) or in a database (database session).
Same origin
Over the last years, some new protections have come up to mitigate the risk of CSRF attacks.
Limiting the request source (to the frontend URL, for example) should be enough to prevent CSRF
Recent browsers prevents cross-origin requests. The Same-origin policy checks that both URLs have the same origin (same port, same protocol, same host). This a client-side protection and so depends on whether the user keeps their browser up-to-date.
Note: a lot of tutorials around the web disables this protection by using the
cors
middleware to connect frontend and backend during development.
Limiting the request source can also be done in the server side and it is one of the defense-in-depth mitigation techniques presented by OWASP. However, OWASP still recommends to use a token based mitigation with it as primary defense (see here)
Interesting resources
OWASP: https://www.owasp.org/index.php/Cross-Site_Request_Forgery_(CSRF)
html5rocks: https://www.html5rocks.com/en/tutorials/cors/
from foal.
During the docs examples and getting started we can see that the MVC architectural pattern is used, it's also used in the generated codes (ex: the CLI's
generate controller
, choosingLogin
. The controller handles the redirects and also the rendering of the login page).I would like to know why MVC was chosed as the main architectural pattern (if it was) and if you think it is interesting to create a Web API option (maybe during
foal createapp
).I don't know if the terminology in my question is right, but with MVC i mean Server Side Rendering of the Pages.
When reading your first post and some other comments I've received since, I feel that most people want to create a REST API with a front end (SPA) and handle authentication with JWT and localStorage. Was it / is it your case?
If so, I was thinking about disabling the CSRF protection by default in every new project and replace the SSR example with a simple ApiController
. This would remove some "noise" and make the "getting started" easier.
Currently
config/settings.json
{
"csrf": true
}
Directory structure:
src/
app/
controllers/
view.controller.ts
app.controller.ts
app.controller.ts
import { controller } from '@foal/core';
import { ViewController } from './controllers';
export class AppController {
subControllers = [
controller('/', ViewController),
];
}
controllers/view.controller.ts
import { Config, Get, render } from '@foal/core';
export class ViewController {
@Get('/')
index(ctx) {
return render('./templates/index.html', {
appName: Config.get('app', 'name'),
csrfToken: ctx.request.csrfToken(),
}, __dirname);
}
}
After
config/settings.json
{
"csrf": false
}
Directory structure:
src/
app/
controllers/
api.controller.ts
app.controller.ts
app.controller.ts
import { controller } from '@foal/core';
import { ApiController } from './controllers';
export class AppController {
subControllers = [
controller('/api', ApiController),
];
}
controllers/api.controller.ts
import { Config, Get, HttpResponseOK } from '@foal/core';
export class ApiController {
@Get('/')
index(ctx) {
return new HttpResponseOK('Hello world!');
}
}
What do you think? Would it be better that way?
from foal.
Hi Loïc,
I feel that most people want to create a REST API with a front end (SPA) and handle authentication with JWT and localStorage. Was it / is it your case?
Yes, it is my case.
What do you think? Would it be better that way?
It would be better that way because it is the way that (i think) most part of the developers will be interested in using Foal.
from foal.
The PR has been merged #315 . Closing this issue
from foal.
Related Issues (20)
- Compatibility issues between mongo store and node 19.1.0 (alpine) HOT 2
- AJV @ValidateBody schema regression in FoalTS 3.0 HOT 1
- @foal/password HOT 3
- Error with FOAL CONNECT for angular>13 (project) : foal connect angular frontend_dir HOT 2
- Multiple mysql "active" connections HOT 2
- Question: body size limits HOT 1
- Receiving xml in request body HOT 3
- How to get the response time and log it using winston logger in foalts HOT 1
- JWT support for SocketIO HOT 1
- Allow ajv strict option HOT 2
- TypeError: Class constructor SocialPost cannot be invoked without 'new' HOT 2
- Task Scheduling In App HOT 2
- SSR with built-in templates not working HOT 2
- Possibility to set option to static serving (via express.static) HOT 3
- Version 4 HOT 1
- a yarn on ubuntu 23 HOT 3
- Question : static access to Context outside a controller HOT 1
- foal: not found HOT 2
- It seems when setting FOAL_ENV=production, cookies setings in production.json of config folder not applied HOT 2
- [Proposal] Give full control of express response object for user
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from foal.