I've tried using the expressjs csurf example from https://github.com/expressjs/csurf When using the first example in the Readme, (using Ejs template language), the token validation works fine. When I try using the 'Ignoring Routes' example, on the 'GET /form' to 'POST /process' execution(just as I did in the first example), I get 'invalid token' on the 'POST /process'. The token is being passed to the form on the GET. Any ideas?
Is 'app.use(csrfProtection)' not working? (used in the non working example, if I remove the 'use(csrfP..' and use the methodology from the working example to use the csrf module, IE, passing 'csrfProtection' to the 'get' and 'post' methods, the second example works)
Works:
var cookieParser = require('cookie-parser')
var csrf = require('csurf')
var bodyParser = require('body-parser')
var express = require('express')
// setup route middlewares
var csrfProtection = csrf({ cookie: true })
var parseForm = bodyParser.urlencoded({ extended: false })
// create express app
var app = express()
app.set('view engine', 'ejs')
// parse cookies
// we need this because "cookie" is true in csrfProtection
app.use(cookieParser())
app.get('/form', csrfProtection, function(req, res) {
// pass the csrfToken to the view
var tkn = req.csrfToken()
console.log(tkn)
res.render('index', { csrfToken: tkn })
})
app.post('/process', parseForm, csrfProtection, function(req, res) {
res.send('data is being processed')
})
var server = app.listen(8081, function () {
var host = server.address().address
var port = server.address().port
console.log("Example app listening at http://%s:%s", host, port)
})
html/ejs:
<!DOCTYPE html>
<html lang="en">
<head>
</head>
<body>
<form action="/process" method="POST">
<input type="hidden" name="_csrf" value="<%= csrfToken %>">
Favorite color: <input type="text" name="favoriteColor">
<button type="submit">Submit</button>
</form>
</body>
</html>
Does not work:
var cookieParser = require('cookie-parser')
var csrf = require('csurf')
var bodyParser = require('body-parser')
var express = require('express')
// setup route middlewares
var csrfProtection = csrf({ cookie: true })
var parseForm = bodyParser.urlencoded({ extended: false })
// create express app
var app = express()
app.set('view engine', 'ejs')
// parse cookies
// we need this because "cookie" is true in csrfProtection
app.use(cookieParser())
// create api router
var api = createApiRouter()
// mount api before csrf is appended to the app stack
app.use('/api', api)
// now add csrf, after the "/api" was mounted
app.use(csrfProtection)
app.get('/form', function(req, res) {
// pass the csrfToken to the view
var tkn = req.csrfToken()
console.log(tkn)
res.render('index', { csrfToken: tkn })
})
app.post('/process', parseForm, function(req, res) {
res.send('csrf was required to get here')
})
function createApiRouter() {
var router = new express.Router()
router.post('/getProfile', function(req, res) {
res.send('no csrf to get here')
})
return router
}
var server = app.listen(8081, function () {
var host = server.address().address
var port = server.address().port
console.log("Example app2 listening at http://%s:%s", host, port)
})
In your second example, you are not passing the csrfProtection middleware to the POST processing chain. It should be
app.post('/process', parseForm, csrfProtection, function(req, res) {
res.send('csrf was required to get here')
})
Related
I'm trying to build a simple to-do list. I keep getting a cannot POST error trying to add a to-do using a form to submit. I'm not sure if I'm linking my files correctly or not while trying to follow MVC. Am I missing a module?
app.js (trimmed down because SO says I have mostly code)
const express = require("express");
const mongoose = require("mongoose");
const dotenv = require("dotenv");
const exphbs = require("express-handlebars");
const MongoStore = require("connect-mongo");
const connectDB = require("./config/db");
// config.env is where all the global variables are stored.
dotenv.config({ path: "./config/config.env" });
// This call connects to mongodb.
connectDB();
// Initialize app
const app = express();
// Body parser
app.use(express.urlencoded({ extended: false }));
app.use(express.json());
// Handlebars
app.engine(".hbs", exphbs({ extname: ".hbs" }));
app.set("view engine", "hbs");
// Sessions
app.use(
session({
secret: "keyboard cat",
resave: false,
saveUninitialized: false,
store: MongoStore.create({ mongoUrl: process.env.MONGO_URI }),
})
);
// Passport middleware
app.use(passport.initialize());
app.use(passport.session());
// Static folder
app.use(express.static(path.join(__dirname, "public")));
const PORT = process.env.PORT || 3000;
// Routes
app.use("/", require("./routes/index"));
app.use("/auth", require("./routes/auth"));
// app.use("/todo", require("./routes/todo"));
app.listen(
PORT,
console.log(`Server running in ${process.env.NODE_ENV} mode on PORT ${PORT}`)
);
todo.js in Route
const express = require("express");
const router = express.Router();
const todosController = require("../controllers/todos");
// const { ensureAuth, EnsureGuest } = require("../middleware/auth");
router.get("/", todosController.getTodos);
router.post("/addTodo", todosController.addTodo);
todo.js in Controller
const Todo = require("../models/todos");
module.exports = {
addTodo: async (req, res) => {
try {
await Todo.create({
todo: req.body.todoItem,
done: false,
googleId: req.user.googleId,
});
console.log("To do has been added!");
res.redirect("/");
} catch (err) {
console.error(err);
}
},
};
handlebars form
<form class="center" action="/addTodo" method="POST">
<input type="text" placeholder="Add a To Do" name="todo" />
<button type="submit" class="submitButton">
<i class="fa fa-plus-square"></i>
</button>
</form>
and lastly my folder structure
I am trying to implement csrf tokens for the first time and i am running into issues. I've been working at it for a few hours and haven't been able to solve it. Below is the error I am getting:
ForbiddenError: invalid csrf token
app.js
const express = require('express')
const app = express()
const router = require('./router')
const cookieParser = require('cookie-parser')
const session = require('express-session')
const flash = require('connect-flash')
const dotenv = require('dotenv')
const csrf = require('csurf')
dotenv.config()
app.use(express.urlencoded({extended: false}))
app.use(express.json())
app.use(express.static('public'))
app.use(cookieParser('secret'))
app.use(session({
secret: 'secret',
cookie: {maxAge: null},
resave: false,
saveUninitialized: false
}))
app.use(flash())
app.set('views', 'views')
app.set('view engine', 'ejs')
app.use(csrf())
app.use(function(req, res, next) {
res.locals.csrfToken = req.csrfToken()
next()
})
app.use('/', router)
app.use(function (req, res, next) {
res.status(404).render('404')
})
app.use(function (err, req, res, next) {
console.error(err.stack)
res.status(500).render('404')
})
app.listen(process.env.PORT)
router.js
const express = require('express')
const multer = require('multer')
const multerConfigOpts = require('./multer.config')
const router = express.Router()
const userController = require('./controllers/userController')
const csrf = require('csurf')
var csrfProtection = csrf({ cookie: true })
// set multer configuration options
const upload = multer(multerConfigOpts)
router.get('/', userController.home)
router.get('/about', userController.about)
router.get('/employer', userController.employer)
router.get('/jobSeeker', userController.jobSeeker)
router.get('/ourProcess', userController.process)
router.get('/contact', userController.contactUs)
// Talent Request Post related routes
router.post('/talentrequest',upload.none() ,userController.requestTalent)
// Job Request Post related routs
router.post('/jobrequest', csrfProtection, upload.single('resume'), userController.requestJob)
module.exports = router
Example of my form:
<form action="/jobrequest" method="POST" enctype="multipart/form-data">
<input type="hidden" name="_csrf" value="<%= csrfToken %>">
<button type="submit" class="btn--form-submit">Submit</button>
</div>
</form>
There are more data fields, I just didn't want to bloat the question with unnecessary code. I've been reading that others are having similar issues when using multipart in the form, but I can't seem to figure it out.
I know that my token is being generated inside the form but I'm not sure if its being passed through properly. Any help or pointers would be appreciated. Thank you
So I was able to find a work around solution by adding the following to my form and removing the input hidden field from my form
form action="/talentrequest/*?_csrf=<%= csrfToken %>*" method="POST" enctype="multipart/form-data">
Everything works as it should. Can anyone explain the potential risks involved with this?
this is my first time when I'm setting up the server and need help. So my goal is to set up server by NodeJS and Expresss. Let's say we have an app with Admin and Users. When Admin clicks a button, it sends some data for the server, then Users can fetch the data.
So this is my server set up:
const express = require('express')
const app = express()
const port = 3000
app.get('/', (req, res) => res.send('Hello World!'))
app.listen(port)
I can add some post method, let's say:
app.post('/', (req, res) => ....);
So I can prepare server reaction for listening the POST method, but I have no idea how to send some data from my app by clicking an button (I mean calling this post method). I've watched a bunch of tutorials and haven't seen any real-world exercises.
To receive the POST parameters, you need the body-parser module, which you can include in your app.js like this,
var bodyParser = require('body-parser');
app.use(bodyParser.json());
And here is how you can receive your form fields which are being sent through the POST method,
app.post('/', function(req, res) {
var someField1 = req.body.some_form_field;
var someField1 = req.body.form_field1;
});
Hope this helps!
On your express server
var bodyParser = require('body-parser');
app.use(bodyParser.json());
app.post("/", (req,res) => {
res.send("Hello");
});
On your webpage/app, You can use axios.
Lets say your express server running with localhost and port 4000.
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<script>
var instance = axios.create({
baseURL: "http://localhost:4000" //use your express server's url(address) and port here
});
function onclick(){
instance.post("/").then( response => {
//response.data will have received data
}
}
</script>
You can use this function and call it on your button click
You can simply use jquery in your HTML page like this to call your api:
$("button").click(function(){
$.post("/", function(data, status){
alert("Data: " + data + "\nStatus: " + status);
});
});
And Send data from your api:
var bodyParser = require('body-parser');
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.post('/', function(req, res) {
var obj = {};
obj.name="hello";
obj.lname="world"
res.json(obj);
});
Example:
HTML:
Your form elements should have name (it is mandatory) to access these in post body request.
<form method="post" action="/">
<input type="text" name="Name" />
<br>
<input type="text" name="Telephone" />
<br>
<input type="submit" />
</form>
app.js
const express = require('express')
const app = express()
const port = 3000
var bodyParser = require('body-parser');
app.use(bodyParser.json());
app.post('/', (req, res) => {
name = req.body.Name;
telephone = req.body.Telephone;
res.render('somefolder/index', {
name: name,
telephone: telephone,
});
// Above code is for reference if you want to load another page after post complete and get posted values in this page too.
res.end();
});
I have a very simple html form, and express server, but I can't make the routing work. I always get "Cannot Post" message. What did I miss?
var express = require('express');
var bodyparser = require('body-parser');
var path = require('path');
var app = express();
app.use(express.static("public"));
app.use(express.bodyParser());
app.get("/", function(req, res){
res.sendFile(path.join(__dirname+"/index.html"));
});
app.post("/sendform", function(req, res){
res.send('You sent the name "' + req.query.user + '".');
});
app.listen(3000, function(){
console.log("Server is running at port: 3000");
});
<form method="post" action="http://localhost:3000/sendform">
<input type="text" name="username" />
<input type="submit" value="küldés" />
</form>
With express 4.15.3, you have to use the body parser a bit differently.
I changed your code to this and I was able to post to it:
var express = require('express');
var bodyParser = require('body-parser');
var path = require('path');
var app = express();
app.use(express.static("public"));
//app.use(express.bodyParser());
app.use(bodyParser.json({
limit: "10mb"
}));
app.use(bodyParser.urlencoded({
limit: "10mb",
extended: true
}));
app.get("/", function (req, res) {
res.sendFile(path.join(__dirname + "/index.html"));
});
app.post("/sendform", function (req, res) {
res.send('You sent the name "' + req.query.user + '".');
});
app.listen(3000, function () {
console.log("Server is running at port: 3000");
});
I am fairly new to nodejs! I have wrote a code to avoid csrf but something is wrong and I always get the error of invalid csrf token. Can anybody help me?
This the code of my nodejs file:
var express = require('express');
var bodyParser = require('body-parser');
var cookieParser = require('cookie-parser')
var csrf = require('csurf')
var csrfProtection = csrf({ cookie: true })
// Create application/x-www-form-urlencoded parser
var urlencodedParser = bodyParser.urlencoded({ extended: false })
var app = express();
app.use(cookieParser())
app.use(express.static('public'));
app.get('/index.html', csrfProtection, function (req, res) {
res.render('send', { csrfToken: req.csrfToken() });
})
app.post('/process_post', urlencodedParser, csrfProtection, function (req, res) {
// Prepare output in JSON format
response = {
first_name:req.body.first_name,
last_name:req.body.last_name
};
console.log(response);
res.end(JSON.stringify(response));
})
var server = app.listen(8081, 'localhost', function () {
var host = server.address().address
var port = server.address().port
console.log("Example app listening at http://%s:%s", host, port)
})
and this is the code of my html file:
<form action = "http://127.0.0.1:8081/process_post" method = "POST">
<input type="hidden" name="_csrf" value="<%=csrfToken%>">
First Name: <input type = "text" name = "first_name"> <br>
Last Name: <input type = "text" name = "last_name">
<input type = "submit" value = "Submit">
</form>
I think there is something regarding setting the token in hidden value because when i try to see the source code of the page in browser the value is still <%=csrfToken%> while it should be set to a random value.