14. nodejs security




/!-- **** home.html *** --> <!DOCTYPE html> <html> <head> <title>home page</title> </head> <body> <div style='margin-left:100px'> <h1 style='margin-left:50px'>tester</h1> <br /> <a href='/public'>route for public</a><br /><br /> <a href='/login'>login</a><br /><br /> <a href='/private'>route for private</a><br /><br /> <a href='/private/detail'>routes under private</a> </div> </body> </html>
                //      *****     app2.js    ***
                const express = require('express')
                const app = express()
                const bodyParser = require('body-parser')
                app.use(bodyParser.urlencoded({ extended: true}))

                app.use(express.static('public'))    // no install needed, it is a build-in middleware
                var path = require('path')           // install needed

                const jsonWebToken = require('jsonwebtoken')   //  npm install required
                const myJWTSecretKey = 'jd-secret-key'         //  This is not passed around web traffic

                app.get('/', (req, res) => {
                    res.sendFile(path.join(__dirname + '/public/html/home.html'))

                        (req, res) => {
                             res.send('hello from public') 

                app.listen(3000, () => {
                        console.log('Server is running at: 3000, 930-622')

Create a token

client-side server-side
home page A user click login button
app2.js login.get route It responds with the login page
login page A user enter username and password, click the login button in this page
app2.js login post route It verifies the user and issue a token, return the token.
login page, ajax callback function It extracts the token and save it in sessionStorage.
<!-- *** login.html **** --> <!DOCTYPE html> <html> <head> <title>sign in</title> <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script> <script> $(document).ready(function(){ $("#login").click(function(){ const d_username = document.getElementById('username').value const d_password = document.getElementById('password').value const jsonUserData = {username: d_username, password: d_password} const strJsonUserData = JSON.stringify(jsonUserData) // for network $.ajax({ url: '/login', type: 'POST', contentType: 'application/json', data:strJsonUserData, success: function(response){ var token = response['token'] $('#msg').append(token + '<br />') // add the token in session storage sessionStorage.setItem('jwt', token) var jwt = sessionStorage.getItem('jwt') alert('jwt from sessionlStorage = ' + jwt) }, error: function(xhr, ajaxOptions, thrownError) { alert(xhr.status) alert(thrownError) } }) $(this).blur() }) }) </script> </head> <body> <h1>log in page</h1> <p>after login, you can ...</p> <button id='login'>login</button> <p id='msg'>the msg is </p> test note: the data in db has only one user username: wiwi password: iwiw <br /> user name:<br /> <input type="text" id="username"><br /> password:<br /> <input type="text" id="password"><br /> </body> </html> // ******* app2.js *********** app.get('/login', (req, res) => { res.sendFile(path.join(__dirname + '/public/html/login.html')) }) app.post('/login', (req, res) => { var msg // 1. get the posting data const p_username = req.body.username const p_password = req.body.password console.log('p_userName = ' + p_username + ' , p_password = ' + p_password) // 2. verify the data in the database, // if not match, return error message // if match, sign it if (p_username !== 'wiwi'){ console.log('not found, please login') msg = 'username_error' res.json({message: msg}) return } if (p_password !== 'iwiw'){ console.log('password not correct, please try again') msg = 'password_error' res.json({message: msg}) return } // 3. sign var token const user = { username: p_username,          id: 1,          name: 'Wiwi Doe'      };      // sign with default (HMAC SHA256)      token = jsonWebToken.sign(user, myJWTSecretKey, {expiresIn: 8 * 60 * 60}) // 4. sign error if (token === undefined){ console.log('token sign error') msg = 'token_error' res.json({message: msg}) return } // 5. return the status and the user data console.log('sign ok') res.json({    token: token }) })

Verify a token

client-side server-side
home.html click the button, requesting get route for private
app2.js app.get('/private')(...){} send private.html to the client
private.html click the button for private data
private.html  It gets the token from sessionStorage.
 It posts the token, makes a ajax web request
app2.js app.post('/private') It gets the token from the request body.
It call a function, using the token as function argument to verify the token
app2.js function verifyToken argument for input: token
jsonWebToken.verify(token, myJWSecretkey) to verify the token
If a valid token, the function return true.
If a invalid token, the function return false.
app2.js app2.js app.post('/private') after the function call If the function returns false, return a error message.
If the function returns true, return the required application data.
private.html     ajax callback $.ajax({...
    success: function(response){...}
get the message from the response
render the message - data or error.
<!-- private.html --> <!DOCTYPE html> <html> <head> <title>private</title> <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script> <script> $(document).ready(function(){ $("#private").click(function(){ //get the token from session storage const jwt = sessionStorage.getItem('jwt') alert('jwt from sessionlStorage = ' + jwt) const token = {token: jwt} // json data const strToken = JSON.stringify(token) // for network $.ajax({ url: '/private', type: 'POST', contentType: 'application/json', data:strToken, success: function(response){ // get and rendering data from private route var message = response['message'] $('#msg').append(message + '<br />') }, error: function(xhr, ajaxOptions, thrownError) { alert(xhr.status) alert(thrownError) } }) $(this).blur() }) }) </script> </head> <body> <h1>private page</h1> <p>auth is needed to access this page</p> <button id='private'>get private data</button> <p id='msg'>data: </p> </body> </html> // app2.js ---------------------------------------- app.get('/private', (req, res) => { res.sendFile(path.join(__dirname + '/public/html/private.html')) } ) app.post('/private', (req, res) => { console.log('enter private') // get the token const token = req.body.token console.log('test 11:40, in private, token = ' + token) // call a function to verify var result = verifyToken(token) var msg if (result === false){ msg = 'no token or invalid token, please login again' } else { msg = 'This is the data from private route' } // return data res.json({    message: msg }) })