Nodejs 加密算法

加密算法

MD5

  MD5是一种被广泛使用的密码散列函数,不可逆(法从密文推出原文),但是HASH 算法最大的问题是,会发生撞库,也就是说,有可能出现多个原文得到同一个密码。

  一种攻击方法是,攻击者记录了一张巨大的密码库,预先计算了常用密码的 hash 值,这样只需要搜索 hash 值就能寻找到一个合适的密码用于登录。这就是被彩虹表攻击。

  解决彩虹表的问题是加盐,在加密之前,对原文混入其他信息,混入的信息不存放到数据库中。实际寻找到其他原文也无法登录。

用法

导入

let md5 = require('md5');

生成一个MD5密码,这个密码是固定的,所以安全性不如 bcrypt

console.log(md5('123456')) //e10adc3949ba59abbe56e057f20f883e

密码验证

md5('123456') == e10adc3949ba59abbe56e057f20f883e //true
md5('123456789') == e10adc3949ba59abbe56e057f20f883e //false

Bcrypt

Bcrypt 有两个特点

  1.每一次 HASH 出来的值不一样,安全性好

  2.计算非常缓慢

因此使用 Bcrypt 进行加密后,攻击者想要使用算出 M2 成本变得不可接受。但代价是应用自身也会性能受到影响,不过登录行为并不是随时在发生,因此能够忍受。对于攻击者来说,需要不断计算,让攻击变得不太可能。

因此推荐使用 Bcrypt 进行密码加密

用法

导入

let bcrypt = require('bcryptjs')

生成一个hash密码,这个密码每次生成是随机的,所以安全问题比 MD5 更强一些

console.log(bcrypt.genSaltSync(10)); //$2a$10$TQdkC0XkrEEvm27OTQ7jwu

将原来的密码转换为hash密码

const hash = bcrypt.hashSync("123456", 10); //$2a$10$c7ggfPYaSpc..H9IfnXcQeOKt0kcr.CvwS2VSpBmApH2tvZC5u7qC

还有一种写法作为了解

const salt = bcrypt.genSaltSync(10);
const hash = bcrypt.hashSync("123456", salt);

密码验证

bcrypt.compareSync("123456", hash); // true 
bcrypt.compareSync("123456789", hash); // false 

Demo

前端代码

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <script src="./Ajax.js"></script>
    <title>Document</title>
</head>

<body>
    账号:<input type="text" class="user"><br>
    密码:<input type="password" class="password"><br>
    <button>登录</button>

    <p></p>

    <script>
        let user = document.querySelector('.user')
        let password = document.querySelector('.password')
        let p = document.querySelector('p')

        document.querySelector('button').onclick = function () {
            Ajax('POST', url + '/users/login', {
                username: user.value, //账号
                password: password.value //密码
            }).then(function (res) {
                if (res.status !== 200) {
                    alert('登录失败!')
                    p.innerHTML = ''

                    return
                }

                alert('登录成功!')
                p.innerHTML = '欢迎:admin 登录成功!'
            })
        }
    </script>
</body>

</html>

MD5

代码实现

var express = require('express');
var query = require('../db/query');
let md5 = require('md5');
var router = express.Router();

// 用户注册
router.post('/register', async function (req, res) {
  let { username, password, phone } = req.body;

  if (!username || !password || !phone) {
    res.send({
      status: 100,
      message: '注册失败!'
    })

    return;
  }

  // 将用户输入的密码转换为MD5
  password = md5(password);

  let sql = `insert into users(username,password,phone) values('${username}','${password}','${phone}')`;
  let resule = await query(sql);

  if (resule.affectedRows == 1) {
    res.send({
      status: 200,
      message: '注册成功!'
    })
  }
})

// 用户登录
router.post('/login', async function (req, res) {
  let { username, password } = req.body;

  let sql = `select * from users where username='${username}'`;
  let data = await query(sql);

  // 将用户密码转换为MD5跟数据库中加密后的MD5密码进行比较
  let md5BL = md5(password) == data[0].password;


  if (md5BL) {
    res.send({
      status: 200,
      message: '登录成功!'
    })

    return
  }

  res.send({
    status: 100,
    message: '登录失败'
  })
})

module.exports = router;

Bcrypt

代码实现

var express = require('express');
var query = require('../db/query');
let bcrypt = require('bcryptjs')
var router = express.Router();

// 用户注册
router.post('/register', async function (req, res) {
  let { username, password, phone } = req.body;
  // 只要有一个值为空,就返回登陆失败
  if (!username || !password || !phone) {
    res.send({
      status: 400,
      message: '登陆失败!'
    })
  }

  // 生成一个加密后的密码
  password = bcrypt.hashSync(password, 10)

  // 添加数据
  let sql = `insert into users(username,password,phone) values('${username}','${password}','${phone}')`;
  const result = await query(sql);

  if (result.affectedRows == 1) {
    res.send({
      status: 200,
      message: '注册成功!'
    })
  }
})

// 用户登陆
router.post('/login', async function (req, res) {
  let { username, password } = req.body;

  // 查询数据库中有没有对应的信息,会返回一个查到的信息
  // let sql = `select * from users where username='${username}' && password='${password}'`;
  let sql = `select * from users where username='${username}'`;
  let data = await query(sql);

  // 判断加密后的密码是否相等
  const bcryptBL = bcrypt.compareSync(password, data[0].password)

  // 如果没有查到登陆的信息,就登陆失败
  if (!bcryptBL) {
    res.send({
      status: 400,
      message: '登陆失败!'
    })
  } else {
    // 查到信息了就登陆成功
    res.send({
      status: 200,
      message: '登陆成功!'
    })
  }
})

// 查询用户
router.get('/get', async function (req, res) {
  let sql = `select * from users`;
  let data = await query(sql);
  res.send({
    status: 200,
    data
  })
})

module.exports = router;

参考:nodejs中的bcryptjs密码加密 - SegmentFault 思否

评论区
头像