node/expressで、 CSRF対応の例 #node #javascript


■ 概要:

node / Express で、CSRFセキュリティ対応の例となります。

■ 環境

node
express

■ 参考

先人様の記事を、参考にしました。

https://qiita.com/kmatae/items/0ce25ac6bde0b301402a

■ 参考の設定

■ npm 追加

npm install csrf --save

npm install express-session --save

■ 実装など

・express-session 読込


var session = require('express-session');

・login ルーティング 読込み


var loginRouter = require('./routes/login');

・express-session 設定

// CSRF
app.use(session({
 secret: 'secret key',
 resave: false,
 saveUninitialized: false,
 cookie: {
   //生存期間は3日
   maxAge: 3 * 24 * 60 * 1000,
   //httpsを使用しない
   secure: false
 }
}));

・login ルーティング

app.use('/login', loginRouter);


・app..js

var createError = require('http-errors');
var express = require('express');
var path = require('path');
var cookieParser = require('cookie-parser');
var logger = require('morgan');
var session = require('express-session');
//
var indexRouter = require('./routes/index');
var loginRouter = require('./routes/login');


var app = express();
const expressLayouts = require('express-ejs-layouts');
app.use(expressLayouts);

// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'ejs');

app.use(logger('dev'));
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));

app.use(function(req,res,next){
 next();
});
// CSRF
app.use(session({
 secret: 'secret key',
 resave: false,
 saveUninitialized: false,
 cookie: {
   //生存期間は3日
   maxAge: 3 * 24 * 60 * 1000,
   //httpsを使用しない
   secure: false
 }
}));

// route
app.use('/', indexRouter);
//app.use('/tasks', tasksRouter );
app.use('/login', loginRouter);

// api
//app.use('/api', apiRouter );

// catch 404 and forward to error handler
app.use(function(req, res, next) {
 next(createError(404));
});

// error handler
app.use(function(err, req, res, next) {
 // set locals, only providing error in development
 res.locals.message = err.message;
 res.locals.error = req.app.get('env') === 'development' ? err : {};
 // render the error page
 res.status(err.status || 500);
 res.render('error');
});

module.exports = app;

・login.js , Get:画面表示, POST:CSRF 処理

・APIで、CSRFトークン判定
 失敗:例外処理で、NGコードのレスポンス返す
 OK: OKコードのレスポンス返す


var express = require('express');
var router = express.Router();

var csrf = require('csrf');
var tokens = new csrf();

/******************************** 
* 
*********************************/
router.get('/', function(req, res) {
 try{
   var secret = tokens.secretSync();
   var token = tokens.create(secret);

   req.session._csrf = secret;
   res.cookie('_csrf', token);
   res.render('login');
 } catch (e) {
     console.log(e);
 }
});

/******************************** 
* 
*********************************/
router.post('/', function(req, res){
   var ret_arr = {ret:0, msg:""}
   try{
       var data = req.body
       console.log(data )    
       	
       var secret = req.session._csrf;
       var token = req.cookies._csrf;
       if(tokens.verify(secret, token) === false)
       {
           throw new Error('Invalid Token');
       }else{
           console.log("Success, Token");
       }
       delete req.session._csrf;
       res.clearCookie('_csrf');
       ret_arr.ret = 1
       res.json( ret_arr )
   } catch (e) {
       console.log(e);
       res.json(ret_arr);        
   }

});

module.exports = router;

■ 参考の画面ejs
views/login.ejs

<div id="app">
   <h1>Login</h1>
   <hr />
   <div class="form-group">
           <label for="TopicTitle">mail :</label>
           <input type="text" class="form-control" v-model="mail">
       </div>
       <div class="form-group">
           <label for="TopicContent">password :</label>
           <input type="password" class="form-control" v-model="password">
       </div>
       <button v-on:click="send_post">ログイン</button>

</div>

■ テスト
・ curlで、ブラウザ以外で不正アクセス/テストする場合

curl  -X POST http://localhost:3000/login -d "mail=hoge" -d "password=1111"

実行すると、サーバーログに、Invalid Token 等出力されます

Error: Invalid Token
   at /home/naka/work/node/express/app9_auth/routes/login.js:43:19
   at Layer.handle [as handle_request] (/home/naka/work/node/express/app9_auth/node_modules/express/lib/router/layer.js:95:5)
   at next (/home/naka/work/node/express/app9_auth/node_modules/express/lib/router/route.js:137:13)
   at Route.dispatch (/home/naka/work/node/express/app9_auth/node_modules/express/lib/router/route.js:112:3)
   at Layer.handle [as handle_request] (/home/naka/work/node/express/app9_auth/node_modules/express/lib/router/layer.js:95:5)
   at /home/naka/work/node/express/app9_auth/node_modules/express/lib/router/index.js:281:22
   at Function.process_params (/home/naka/work/node/express/app9_auth/node_modules/express/lib/router/index.js:335:12)
   at next (/home/naka/work/node/express/app9_auth/node_modules/express/lib/router/index.js:275:10)
   at Function.handle (/home/naka/work/node/express/app9_auth/node_modules/express/lib/router/index.js:174:3)
   at router (/home/naka/work/node/express/app9_auth/node_modules/express/lib/router/index.js:47:12)



この記事が気に入ったら、サポートをしてみませんか?
気軽にクリエイターの支援と、記事のオススメができます!
3
はじめまして knaka0209 です。knaka Tech-Blogを書いています。 フリーのエンジニアで。普段はIT系の作業 空き時間に、IoTやAIによるデータ分析予測とか勉強しています。 https://kuc-arc-f.com