I'm trying to write a test for my server side form validation but I keep getting a Forbidden error. It seems that this needs to be a 2 step process. Step 1, acquire the CSRF value from the form. Step 2, use the CSRF value to post to the form handler. However no matter how I try to post I get a forbidden error.
--full test: https://github.com/socketwiz/swblog/blob/master/test/contact.js#L57-L100
I've tried changing the following line thusly: https://github.com/socketwiz/swblog/blob/master/test/contact.js#L85
.send({name: 'foo', 'X-CSRF-Token': token})
.set('X-CSRF-Token', token)
.set('Cookie', ['X-CSRF-Token=' + token])
But nothing I try will seem to satisfy the CSRF requirement. The more I try the more complex this gets for what seems like a simple thing. Maybe I'm going about this all wrong. Any ideas?
In order to function properly, the CSRF token must be generated by the server and then rendered on the page where the form is held. Then, all requests from that page will have the input with the csrf_token name included in the request, and all requests which are made cross-site will not have it.
A couple of ways you can test it: Open the developer tools in your browser find the input element for the CSRF token and edit the token value. Trigger a POST submission. This should cause an error, HTTP status 403 typically.
To implement CSRF tokens in Node. js, we can use the csurf module for creating and validating tokens. Lines of code in an integrated development environment. Notice that we added the routing code here, but you can have it in a separate routing class index.
csrfToken() function to make a token which should be added to requests which mutate state, within a hidden form field, query-string etc. This token is validated against the visitor's session or csrf cookie.
Thanks @shawnzhu, you comment on cookies helped me figure out what I needed to do. I had an idea that I was over complicating it. Here is what I came up with:
https://github.com/socketwiz/swblog/blob/master/test/contact.js
it('should not post just a name', function(done) {
request(mock)
.get('/contact')
.end(function(err, res){
var $html = jQuery(res.text);
var csrf = $html.find('input[name=_csrf]').val();
request(mock)
.post('/api/contact.json')
.set('cookie', res.headers['set-cookie'])
.send({
_csrf: csrf,
name: 'Mary Jane'
})
.expect(function(res){
assert.equal(undefined, res.body.name);
assert.equal('You must provide a valid email address', res.body.email);
assert.equal('You must provide a message', res.body.message);
})
.expect(500, done);
});
});
The express csrf middleware saves a secret in session to validate csrf token, while I guess you use cookieSession middleware as session store. So you need to resend the session cookies when POST the data with csrf token, the express can use the secret in session to validate your csrf token.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With