J'ai les éléments suivants dans mon côté serveur app.js
après bodyParser
let dotEnv = require("dotenv");
dotEnv.load();
let express = require("express");
let app = express();
if (process.env.NODE_ENV === 'production') {
app = require('./public/web/server').app;
}
let passport = require("passport");
let server = require("http").Server(app);
let io = require("socket.io").listen(server);
// load intial configuration
require("./startup/initial-configuration")(app, io);
require("./server/config/socket")(io);
require("./server/config/database")(app, process.env.NODE_ENV);
require("./server/authentication/passport.local")(passport);
require("./server/authentication/passport.impersonate");
require("./startup/initial-routes")(app);
if (process.env.NODE_ENV === 'production') {
app.get('*.*', express.static('./public/web/browser', {
maxAge: '1y'
}));
app.get('*', (req, res) => {
res.render('index', {
req,
res
}, (err, html) => {
if (html) {
res.send(html);
} else {
// console.error(err);
res.send(err);
}
});
});
}
require("./server/middleware/custom-middleware")(app);
module.exports = { app: app, server: server };
Comme vous pouvez le constater, un fichier initial-configuration
est inséré dans app.js
, le contenu de ce fichier est le suivant:
const path = require("path");
const bodyParser = require("body-parser");
const cookieParser = require("cookie-parser");
const csurf = require("csurf");
const helmet = require("helmet");
const compression = require("compression");
const useragent = require("express-useragent");
const cors = require("cors");
const passport = require("passport");
const express = require("express");
const cookieMiddleware = require("../server/middleware/cookie-middleware");
const checkCSRFMiddleware = require("../server/middleware/checkCSRF-middleware");
const notificationModel = require("../server/model/notification/notification.model");
const logger = require("./logger");
const morgan = require("morgan");
module.exports = (app, io) => {
app.set("case sensetive routing", true);
if (process.env.NODE_ENV === "production") {
app.enable("trust proxy");
}
app.use((req, res, next) => {
res.io = io;
res.header(
"Access-Control-Allow-Headers",
"X-CSRF-Token, Content-Type"
);
notificationModel.setIO(io);
next();
});
let corsOption = {
Origin: true,
methods: "GET,HEAD,PUT,PATCH,POST,DELETE",
credentials: true,
exposedHeaders: ["x-auth-token"]
};
app.use(cors(corsOption));
// app.use(logger('dev'));
app.use(helmet());
app.use(useragent.express());
app.use(compression());
app.use(bodyParser.json());
app.use(
bodyParser.urlencoded({
extended: false
})
);
app.use(cookieParser());
app.use(cookieMiddleware);
app.use(passport.initialize());
app.use(require('csurf')({cookie: true}))
// error handler
app.use(function (err, req, res, next) {
if (err.code !== 'EBADCSRFTOKEN') return next(err)
// handle CSRF token errors here
res.status(403)
res.send('session has expired or form tampered with')
})
app.use(function (req, res, next) {
res.cookie('XSRF-TOKEN', req.csrfToken())
next()
})
// app.use(express.static(path.join(__dirname, "../public/web/browser")));
app.use(
morgan("combined", {
stream: logger.stream
})
);
};
Et dans Angular, je n'ai importé que les lignes suivantes dans app.module
HttpClientXsrfModule.withOptions({
cookieName: "XSRF-TOKEN",
headerName: "X-CSRF-TOKEN"
}),
Et tout mon en-tête de demandes a Cookie:_csrf=TmghRq3eWC-PxQfp6pvuHw07; XSRF-TOKEN=vMPrZZtA--BgtY1YVqDRXmi5A6RSbMNb61JA
Mais toutes mes demandes de publication ont échoué et portent la mention code: "EBADCSRFTOKEN"
.
Devrais-je faire quelque chose du côté angulaire? Devrais-je annexer cela aux données du formulaire?
Pour toute aide merci.
Dans votre code, vous utilisez beaucoup de modules. Pour isoler le problème, je suggère de réduire votre code à une version minimale en supprimant tout ce qui n'est pas obligatoire pour activer csrf.
Ceci n'est qu'une suggestion, cependant, dans mon application Angular 7, j'ai ajouté ceci (il n'est pas nécessaire de changer le nom de cookie et le jeton, car ils ont des valeurs par défaut dans le code source d'Angular):
HttpClientModule,
HttpClientXsrfModule.withOptions()
puis dans mon serveur (fichier principal app.js) avec Express 4, j'ai ajouté ce code (dans cet ordre exact):
const csrf = require('csurf');
app.use(bodyParser.urlencoded({
extended: false
}));
// then add cookie parser and csrf config
app.use(cookieParser());
app.use(csrf({
cookie: {
// here you can configure your cookie. Default values are ok, but I decided to be more explicit
// http://expressjs.com/en/4x/api.html#req.cookies
key: '_csrf',
path: '/',
httpOnly: false, // if you want you can use true here
secure: false, // if you are using HTTPS I suggest true here
signed: false, // I don't know if csurf supports signed cookies, so I used false
// not mandatory, but if you want you can use sameSite: 'strict'
// sameSite: 'strict', // https://www.owaspsafar.org/index.php/SameSite
maxAge: 24 * 60 * 60 * 1000 // 24 hours
}
}));
app.use((req, res, next) => {
const csrfTokenToSendToFrontEnd = req.csrfToken();
console.log('csrfTokenToSendToFrontEnd: ', csrfTokenToSendToFrontEnd);
// this cookie must be XSRF-TOKEN, because already defined as default in Angular.
res.cookie('XSRF-TOKEN', csrfTokenToSendToFrontEnd);
next();
});
// here requires the api file with all your rest apis (not static paths)
const routesApi = require('./src/routes/index')(express, passport);
app.use('/api', routesApi);
Et enfin, avant la fin du fichier (avant le middleware 500), j'ai ajouté ceci pour gérer les erreurs:
// error handler
app.use((err, req, res, next) => {
if (err.code !== 'EBADCSRFTOKEN') {
return next(err);
}
res.status(403).json({
message: 'error'
});
});
J'ai copié que le code pertinent. Si vous avez des problèmes, n'hésitez pas à demander, je vérifierai à nouveau dans mon code si j'ai oublié quelque chose.
Plusieurs modules vous aident à implémenter des jetons CSRF dans votre application. L'un d'eux est csurf. Installez ce module avec les dépendances cookie-parser en lançant:
npm install cookie-parser csurf --save
Ces deux modules sont des intergiciels pouvant modifier le comportement d'une requête dans Express. Nous utilisons déjà body-parser pour analyser notre corps POST afin de récupérer le message. De plus, nous allons l’utiliser pour rechercher le jeton _csrf. Le middleware de l'analyseur de cookies vérifie que le jeton est disponible dans les cookies et csurf protégera automatiquement toutes les opérations POST, PUT, PATCH ou DELETE en vérifiant que le jeton _csrf est présent dans les cookies et dans le corps de la demande et que ils correspondent.
Ajoutez le code suivant à votre fichier index.js pour configurer le middleware:
const express = require('express');
const bodyParser = require('body-parser');
const csurf = require('csurf');
const cookieParser = require('cookie-parser');
const PORT = process.env.PORT || 3000;
const app = express();
const csrfMiddleware = csurf({
cookie: true
});
app.use(bodyParser.urlencoded({
extended: true
}));
app.use(cookieParser());
app.use(csrfMiddleware);
app.get('/', (req, res) => {
res.send(`
<h1>Hello World</h1>
<form action="/entry" method="POST">
<div>
<label for="message">Enter a message</label>
<input id="message" name="message" type="text" />
</div>
<input type="submit" value="Submit" />
<input type="hidden" name="_csrf" value="${req.csrfToken()}" />
</form>
`);
});
app.post('/entry', (req, res) => {
console.log(`Message received: ${req.body.message}`);
res.send(`CSRF token used: ${req.body._csrf}, Message received: ${req.body.message}`);
});
app.listen(PORT, () => {
console.log(`Listening on http://localhost:${PORT}`);
});
Redémarrez votre serveur et accédez à http: // localhost: 3000 . Entrez du texte dans la zone de saisie et cliquez sur Soumettre. Le message devrait apparaître dans la console et être salué dans le navigateur par un message similaire à celui ci-dessous: