Node js csrf Защита токенов не работает - PullRequest
0 голосов
/ 10 декабря 2018

У меня на стороне файлового сервера app.js есть следующее после 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 };

Как видите, у меня есть файл initial-configuration, загруженный внутри app.js, содержимое которогофайл:

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
 })
);
};

А в Angular я импортировал только следующие строки в app.module

HttpClientXsrfModule.withOptions({
  cookieName: "XSRF-TOKEN",
  headerName: "X-CSRF-TOKEN"
}),

И заголовок всех моих запросов имеет Cookie:_csrf=TmghRq3eWC-PxQfp6pvuHw07; XSRF-TOKEN=vMPrZZtA--BgtY1YVqDRXmi5A6RSbMNb61JA

Но все мои почтовые запросы провалились и говорят code: "EBADCSRFTOKEN".

Должен ли я что-то делать с угловой стороны?Должен ли я добавить это с данными формы?

За любую помощь, спасибо.

Вот мои данные запроса request details

my login request

Ответы [ 2 ]

0 голосов
/ 19 декабря 2018

Существует несколько модулей, которые помогут вам реализовать токены CSRF в вашем приложении.Одним из них является Csurf.Установите этот модуль вместе с зависимостями парсера cookie, выполнив:

npm install cookie-parser csurf --save

Оба эти модуля являются промежуточным программным обеспечением, которое может изменять поведение запроса в Express.Мы уже используем body-parser для анализа нашего тела POST для получения сообщения.Кроме того, мы будем использовать его для проверки токена _csrf.Промежуточное программное обеспечение парсера cookie проверяет, доступен ли токен в файлах cookie, и csurf будет автоматически защищать любые операции POST, PUT, PATCH или DELETE, проверяя, присутствует ли токен _csrf как в файлах cookie, так и в теле запроса, и чтоони совпадают.

Добавьте следующий код в файл index.js для настройки промежуточного программного обеспечения:

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}`);
});

Перезапустите сервер и перейдите к http://localhost:3000. Введите некоторый текст ввведите поле и нажмите Отправить.Вы должны увидеть сообщение, появившееся в консоли, и приветствие в браузере с сообщением, подобным приведенному ниже:

0 голосов
/ 15 декабря 2018

В вашем коде вы используете много модулей.Чтобы изолировать проблему, я предлагаю сократить ваш код до минимальной версии, удалив все, что не является обязательным для включения csrf.

Это только предложение, однако в моем приложении Angular 7 я добавил это (не нужно менять имя_прибораи токен, потому что они имеют значения по умолчанию в исходном коде Angular):

HttpClientModule,
HttpClientXsrfModule.withOptions()

, затем на моем сервере (основной файл app.js) с Express 4 я добавил этот код (в точном порядке):

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);

И, наконец, перед концом файла (до промежуточного программного обеспечения 500) я добавил это для обработки ошибок:

// error handler
app.use((err, req, res, next) => {
  if (err.code !== 'EBADCSRFTOKEN') {
    return next(err);
  }
  res.status(403).json({
    message: 'error'
  });
});

Я скопировал только соответствующий код.Если у вас есть вопросы, не стесняйтесь спрашивать, я проверю еще раз в своем коде, если я что-то забыл.

...