#121 Added CSRF protection

master
Keith Irwin 2018-03-04 20:15:43 +00:00
parent 3af3d9aa96
commit 50061c370c
No known key found for this signature in database
GPG Key ID: 378933C743E2BBC0
9 changed files with 93 additions and 18 deletions

61
package-lock.json generated
View File

@ -1228,6 +1228,16 @@
"integrity": "sha1-ojD2T1aDEOFJgAmUB5DsmVRbyn4=",
"dev": true
},
"csrf": {
"version": "3.0.6",
"resolved": "https://registry.npmjs.org/csrf/-/csrf-3.0.6.tgz",
"integrity": "sha1-thEg3c7q/JHnbtUxO7XAsmZ7cQo=",
"requires": {
"rndm": "1.2.0",
"tsscmp": "1.0.5",
"uid-safe": "2.1.4"
}
},
"css-color-names": {
"version": "0.0.4",
"resolved": "https://registry.npmjs.org/css-color-names/-/css-color-names-0.0.4.tgz",
@ -1327,6 +1337,34 @@
"source-map": "0.5.7"
}
},
"csurf": {
"version": "1.9.0",
"resolved": "https://registry.npmjs.org/csurf/-/csurf-1.9.0.tgz",
"integrity": "sha1-SdLGkl/87Ht95VlZfBU/pTM2QTM=",
"requires": {
"cookie": "0.3.1",
"cookie-signature": "1.0.6",
"csrf": "3.0.6",
"http-errors": "1.5.1"
},
"dependencies": {
"http-errors": {
"version": "1.5.1",
"resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.5.1.tgz",
"integrity": "sha1-eIwNLB3iyBuebowBhDtrl+uSB1A=",
"requires": {
"inherits": "2.0.3",
"setprototypeof": "1.0.2",
"statuses": "1.4.0"
}
},
"setprototypeof": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.0.2.tgz",
"integrity": "sha1-gaVSFB7BBLiOic44MQOtXGZWTQg="
}
}
},
"d": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/d/-/d-1.0.0.tgz",
@ -6046,6 +6084,11 @@
"resolved": "https://registry.npmjs.org/querystring-es3/-/querystring-es3-0.2.1.tgz",
"integrity": "sha1-nsYfeQSYdXB9aUFFlv2Qek1xHnM="
},
"random-bytes": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/random-bytes/-/random-bytes-1.0.0.tgz",
"integrity": "sha1-T2ih3Arli9P7lYSMMDJNt11kNgs="
},
"randomatic": {
"version": "1.1.7",
"resolved": "https://registry.npmjs.org/randomatic/-/randomatic-1.1.7.tgz",
@ -6425,6 +6468,11 @@
"inherits": "2.0.3"
}
},
"rndm": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/rndm/-/rndm-1.2.0.tgz",
"integrity": "sha1-8z/pz7Urv9UgqhgyO8ZdsRCht2w="
},
"run-async": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/run-async/-/run-async-0.1.0.tgz",
@ -7123,6 +7171,11 @@
"punycode": "1.4.1"
}
},
"tsscmp": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/tsscmp/-/tsscmp-1.0.5.tgz",
"integrity": "sha1-fcSjOvcVgatDN9qR2FylQn69mpc="
},
"tty-browserify": {
"version": "0.0.0",
"resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.0.tgz",
@ -7203,6 +7256,14 @@
"resolved": "https://registry.npmjs.org/uid-number/-/uid-number-0.0.6.tgz",
"integrity": "sha1-DqEOgDXo61uOREnwbaHHMGY7qoE="
},
"uid-safe": {
"version": "2.1.4",
"resolved": "https://registry.npmjs.org/uid-safe/-/uid-safe-2.1.4.tgz",
"integrity": "sha1-Otbzg2jG1MjHXsF2I/t5qh0HHYE=",
"requires": {
"random-bytes": "1.0.0"
}
},
"uid2": {
"version": "0.0.3",
"resolved": "https://registry.npmjs.org/uid2/-/uid2-0.0.3.tgz",

View File

@ -10,6 +10,7 @@
"cookie-parser": "^1.4.3",
"cookie-session": "^2.0.0-beta.2",
"css-loader": "^0.28.7",
"csurf": "^1.9.0",
"debug": "^2.6.9",
"express": "^4.15.5",
"express-request-limit": "^1.0.2",

View File

@ -7,6 +7,7 @@ const rateLimit = require('express-request-limit')
const bodyParser = require('body-parser')
const cookieParser = require('cookie-parser')
const cookieSession = require('cookie-session')
const csurf = require('csurf')
const mongoose = require('mongoose')
const nunjucks = require('nunjucks')
const passport = require('passport')
@ -49,7 +50,7 @@ let ready_promise_list = []
/* Templates */ {
nunjucks.configure(__dirname + '/views', {
autoescape: true,
express: app
express: app,
})
app.set('view engine', 'html')
}
@ -66,11 +67,11 @@ let ready_promise_list = []
},
secret: env.session,
saveUninitialized: true,
resave: true
resave: true,
}))
app.use(bodyParser.json())
app.use(bodyParser.urlencoded({
extended: true
extended: true,
}))
app.use(flash())
}
@ -149,7 +150,7 @@ let ready_promise_list = []
res.status(err.status || 500)
res.render('error', {
code: err.status || 500,
message: (err.status <= 499) ? err.message : 'Server error'
message: (err.status < 500) ? err.message : 'Server error'
})
})
@ -168,6 +169,11 @@ let ready_promise_list = []
}
}
// CSRF Protection
app.use(csurf({
cookie: true,
}))
/* Sockets */ {
sockets.init(io)
}

View File

@ -19,6 +19,7 @@
<h1>Contact</h1>
<form id='contact-form' role="form" method="POST">
<input type="hidden" name="_csrf" value="{{csrfToken}}">
<input id='subject-input' name="subject" id='subject' type="text" maxlength="160" placeholder="Subject">
<p id='message-help' class='red help'>You need to enter a message. </p>

View File

@ -13,6 +13,7 @@
<p>Enter your email below to recieve a link to reset your password. </p>
<form method="post" role="form">
<input type="hidden" name="_csrf" value="{{csrfToken}}">
<div class='form-group'>
<label for="email">Email:</label>

View File

@ -24,6 +24,7 @@
<h3>Login</h3>
<form method="post">
<input type="hidden" name="_csrf" value="{{csrfToken}}">
<div id='social-login' class='flex form-group'>
@ -64,6 +65,7 @@
<h3>Create account</h3>
<p>Welcome aboard! </p>
<form action="/signup" method="post">
<input type="hidden" name="_csrf" value="{{csrfToken}}">
<input type="email" name="email" placeholder="Your email" required>
<p>You will be sent an email confrimation with a link to create a password. </p>
<p>By signing up, you agree to our <a href="/terms">terms of service</a> and <a href="/privacy">privacy policy</a>. </p>

View File

@ -18,20 +18,21 @@
<h1>Set Password</h1>
<form id='password-form' role="form" method="post">
<style>
#password-form .password {
flex-grow: 1;
min-width: 0;
margin: 2%;
}
#password-help {
display: none;
}
.form-group > span {
display: flex;
flex-wrap: wrap;
}
</style>
<input type="hidden" name="_csrf" value="{{csrfToken}}">
<style>
#password-form .password {
flex-grow: 1;
min-width: 0;
margin: 2%;
}
#password-help {
display: none;
}
.form-group > span {
display: flex;
flex-wrap: wrap;
}
</style>
<p>Your password must be at least 8 characters long. You can use any letter, number, symbol, emoji, or spaces. Your password will be checked using <a href="https://github.com/dropbox/zxcvbn">zxcvbn</a>. All passwords are stored on the server as salted hashes. </p>

View File

@ -28,6 +28,7 @@
<a href="https://www.keithirwin.us/">Keith Irwin</a></p>
<form class='flex' action="#" method="POST">
<input type="hidden" name="_csrf" value="{{csrfToken}}">
{% if user.isPro %}
<div id='already-pro' class='inline-block alert alert-success'>
<i class="fa fa-check-circle"></i>

View File

@ -19,6 +19,7 @@
<h1>Settings</h1>
<form id='settings-form' role="form" method="post">
<input type="hidden" name="_csrf" value="{{csrfToken}}">
<h2>Account settings</h2>