Node.js Article 14: JWT-based interface security verification

Security authentication methods for interfaces

Traditional Interface Security Authentication Methods

Internet services cannot be separated from user authentication.The general process is as follows.

  1. Users send user names and passwords to the server.

  2. After validating the server, relevant data, such as user roles, logon times, and so on, are saved in the current session.

  3. Server returns session_to userId, session information is written to the user's Cookie.

  4. Each subsequent request of the user will take session_out of the cookieThe ID is passed to the server.

  5. Server receives session_id and verify the user's identity by comparing the previously saved data.

The biggest problem with this pattern is that it does not have a distributed architecture to support horizontal scaling.If you use a server, this mode is completely OK.However, if it is a server cluster or a service-oriented cross-domain architecture, a unified session database library is needed to hold session data for sharing so that each server under load balancing can properly authenticate users.

List one of the common requirements for Single Sign-on in practice: Site A and Site B provide services related to the same company.Users are now required to log in to only one site, and then it will automatically log in to another site.How do you do it?

One solution is to listen to persistent session data, write to a database or file persistence layer, and so on.Upon receipt of the request, the validation service requests data from the persistence layer.The advantage of this solution is that the architecture is clear, but the disadvantage is that it takes a lot of effort to modify the architecture, rewrite the validation logic layer of the entire service, and the workload is relatively large.Also, depending on the persistence layer database or the problematic system, there is a single risk that if the persistence layer fails, the entire authentication system will be suspended.

JWT Interface Security Authentication Method

Another way is to save data through the client, while the server does not save session data at all, and each request is sent back to the server.JWT represents this solution.

JSON Web Token (JWT) is the most popular cross-domain authentication solution at present.

The principle of JWT is that after server authentication, a JSON object is generated and sent back to the user, and then when the user communicates with the server, the client sends back the JSON object in the request.The server only relies on this JSON object to identify the user.To prevent users from tampering with data, the server adds a signature when the object is generated.

The server does not hold any session data, that is, the server becomes stateless, making it easier to expand.

Code

Get ready

  • Install third-party modules: npm install jsonwebtoken
  • Import jsonwebtoken module into backend program
  • Common methods for this module
    • Jwt.signGenerate token (data, signature key, other configurations)
    • jwt.verify(token, signature key) Verify the signature

File: https://www.npmjs.com/package/jsonwebtoken

Backend API Program

const koa = require('koa')
const router = require('koa-router')()
const cors = require('koa2-cors')
const bodyparser = require('koa-bodyparser')
// [Import jsonwebtoken module - process token]
const jwt = require('jsonwebtoken')

const app = new koa()

// Configuring the middleware for cors 
app.use(
  cors({
    origin: function (ctx) { //Set allow requests from specified domain names
      return 'http://localhost:8080'; //Allow onlyHttp://localhost: 8080 Request for this domain name
    },
    maxAge: 5, //Specify the validity period of this pre-check request in seconds.
    credentials: true, //Is Cookie s Allowed to Send
    allowMethods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'], //Set allowed HTTP request methods
    allowHeaders: ['Content-Type', 'Authorization', 'Accept'], //Set all header information fields supported by the server
    exposeHeaders: ['WWW-Authenticate', 'Server-Authorization'] //Set Get Other Custom Fields
  })
)

// [Configure jwt authentication middleware]
app.use(async (ctx, next) => {
  // If it is not a login page
  if (ctx.url != '/login') {
    // Get token in request header
    const token = ctx.request.header.authorization;
    // Verify token
    try {
      // [Verify token]
      const obj = jwt.verify(token, 'login jwt')
      await next()
    } catch (ex) {
      ctx.body = 'Token error, no permission at this time'
    }
    // console.log(obj)
    // { username: 'admin', iat: 1590073058, exp: 1590159458 }
    // iat signature timestamp unit is s
    // exp expiration timestamp units are s


  } else {
    await next()
  }

})

// [Login Interface]
router.post('/login', async (ctx) => {
  const params = ctx.request.body;
  if (params.username == 'admin' && params.pwd == '123456') {
    // jwt signature
    // Sign (data to be signed, private key, other configurations), return signature
    const token = jwt.sign({ username: params.username }, 'login jwt', {
      expiresIn: 60 * 60 * 24   // Expiration Time
    })
    // Respond, return login status and token to client
    ctx.body = {
      loginstatus: true,
      token: token
    }
  } else {
    ctx.body = {
      loginstatus: false
    }
  }

})

// Data List Interface
router.get('/list', async (ctx) => {
  ctx.body = ['Zhang San', 'Li Si', 'King Five'];
})

app.use(bodyparser())
app.use(router.routes())
app.use(router.allowedMethods());

app.listen(80)

Front End Program

Service Deployment Code

const koa = require('koa')
const path = require('path')
// Import Static Resource Processing Module
const static = require('koa-static')

const app = new koa()
// Configure Static Resource Path
app.use(static(path.join(__dirname,'./public')))
app.listen(8080)

Front End Program Code

  <div class="box">
    <p>User name:<input type="text" name="username" id="username"></p>
    <p>Password:<input type="password" name="pwd" id="pwd"></p>
    <button id="btn">Sign in</button>
  </div>
  <hr>
  <button id="btn3">Sign out</button>
  <button id="btn2">Get a set of data-Yes jwt Verification-Must be logged in to get</button>
  <script src="./jquery.js"></script>
  <script>
    // Sign in
    $('#btn').click(function () {
      $.post('http://localhost/login', {
        username: $('#username').val(),
        pwd: $('#pwd').val()
      }, function (data) {
        if (data.loginstatus) {
          alert('Login Successful');
          // Store the token client
          sessionStorage.token = data.token;
        }
      })
    })
    // Sign out
    $('#btn3').click(function () {
      sessionStorage.token = null;
    })
    
    // Get a set of data
    $('#btn2').click(function () {
      $.ajax({
        url: 'http://localhost/list',
        success:function(data){
          console.log(data)
        },
        error:function(err) {
          console.log(err)
        },
        headers: {
          "Authorization":sessionStorage.getItem("token")//Place the requested user token here
          // "Authorization":sessionStorage.getItem("token") + 222//tamper with token
        }
      })
    })
  </script>

Some questions about JWT

(1) JWT is not encrypted by default, but it can also be encrypted.Once the original Token has been generated, it can be encrypted again with the key.

(2) Secret data cannot be written to JWT without encryption.

(3) JWT can be used not only for authentication, but also for exchanging information (for example, between different pages).Effective use of JWT can reduce the number of times the server queries the database.

(4) The biggest disadvantage of JWT is that because the server does not save session state, it is not possible to invalidate a token or change its permissions during use.That is, once a JWT is signed, it will always be valid until it expires unless the server deploys additional logic.

(5) The JWT itself contains authentication information, and once it is disclosed, anyone can obtain all the rights of the token.To reduce theft, the validity period of the JWT should be set relatively short.For some of the more important privileges, the user should be authenticated again when used.

(6) In order to reduce theft, JWT should not use HTTP protocol for plain code transmission, but use HTTPS protocol for transmission.

Tags: Programming Session Database JSON npm

Posted on Thu, 21 May 2020 14:08:47 -0400 by JimiLives