node中的密码安全(加密)


Posted in Javascript onSeptember 17, 2018

本文将讲解对于前后端分离的项目,前端注册或登录时如何保证用户密码安全传输到server端,最终存入数据库

为什么需要加密

加密真的有必要吗?

我们先来看一看前端发起的ajax请求中,如果不对密码进行加密,会发生什么。

f12打开chrome开发者工具,找到请求,查看请求参数如下:

node中的密码安全(加密)

如果你的协议是http,那么前端传给后端的密码差不多是裸奔状态,因为http传输的是明文,很可能在传输过程中被窃听,伪装或篡改。

那么,弄个https不就好了吗?

https的确能够极大增加网站的安全性,但是用https得先买证书(也有免费的),对于个人站点或者不想弄证书的情况下,那最起码也得对用户密码进行一下加密吧。

流程图

先看一下大体流程图,首先,我们用工具生成公钥和私钥,将其放入server端,前端发起请求获取公钥,拿到公钥后对密码进行加密,然后将加密后的密码发送到server端,server端将用密钥解密,最后再用sha1加密密码,存入数据库。

node中的密码安全(加密)

生成RSA公钥和密钥

既然选择RSA加密,那么首先得有工具啊,常见的有openssl,但这里不介绍,感兴趣的请自行查阅,对于node而言,我介绍一个不错的库Node-RSA,我们将用它来生成RSA公钥和密钥。

RSA是一种非对称加密算法,即由一个密钥和一个公钥构成的密钥对,通过密钥加密,公钥解密,或者通过公钥加密,密钥解密。其中,公钥可以公开,密钥必须保密

用Node-RSA生成的公钥和密钥代码如下:

const NodeRSA = require('node-rsa')
const fs = require('fs')

// Generate new 512bit-length key
var key = new NodeRSA({b: 512})
key.setOptions({encryptionScheme: 'pkcs1'})

var privatePem = key.exportKey('pkcs1-private-pem')
var publicDer = key.exportKey('pkcs8-public-der')
var publicDerStr = publicDer.toString('base64')

// 保存返回到前端的公钥
fs.writeFile('./pem/public.pem', publicDerStr, (err) => {
 if (err) throw err
 console.log('公钥已保存!')
})
// 保存私钥
fs.writeFile('./pem/private.pem', privatePem, (err) => {
 if (err) throw err
 console.log('私钥已保存!')
})

执行完成后,我们将在根目录下得到公钥和私钥文件:

node中的密码安全(加密)

注意:server端的公钥和密钥应该隔一段时间换一次,比如每次服务器重启时。

前端加密

核心代码如下:

<script src="https://cdn.bootcss.com/jsencrypt/2.3.1/jsencrypt.min.js"></script>
 <script src="https://cdn.bootcss.com/axios/0.18.0/axios.min.js"></script>
 <script>
  function reg() {
   axios({
    method: 'post',
    url: 'http://127.0.0.1:3000/getPublicKey'
   })
    .then(res => {
     let result = res.data

     // 从后端获取的公钥 String
     var publicPem = result
     // 用JSEncrypt对密码进行加密
     var encrypt = new JSEncrypt()
     encrypt.setPublicKey(publicPem)
     var password = 'abc123'
     password = encrypt.encrypt(password)

     axios({
      method: 'post',
      url: 'http://127.0.0.1:3000/reg',
      data: {
       password: password
      }
     })
      .then(res => {
       let result = res.data
       console.log(result)
      })
      .catch(error => {
       console.log(error)
      })
    })
  }
 </script>

前端将用到jsencrypt对其进行加密,详细用法请参考github。

后端解密

后端核心代码:

const express = require('express');
const crypto = require('crypto');
const fs = require('fs');

var privatePem = fs.readFileSync('./pem/private.pem');

var app = express();
app.use(express.json());

// CORS 注意:要放在处理路由前
function crossDomain(req, res, next) {
 res.header('Access-Control-Allow-Origin', '*');
 res.header('Access-Control-Allow-Headers', 'Content-Type');

 next();
}
app.use(crossDomain)

app.use(function (req, res, next) {
 // 不加会报错
 if (req.method === 'OPTIONS') {
  res.end('ok')
  return
 }

 switch (req.url) {
  case '/getPublicKey':
   let publicPem = fs.readFileSync('./pem/public.pem', 'utf-8')
   res.json(publicPem)
   break
  case '/reg':
   // 解密
   var privateKey = fs.readFileSync('./pem/private.pem', 'utf8')
   var password = req.body.password
   var buffer2 = Buffer.from(password, 'base64')
   var decrypted = crypto.privateDecrypt(
    {
     key: privateKey,
     padding: crypto.constants.RSA_PKCS1_PADDING // 注意这里的常量值要设置为RSA_PKCS1_PADDING
    },
    buffer2
   )
   console.log(decrypted.toString('utf8'))

   // sha1加密
   var sha1 = crypto.createHash('sha1');
   var password = sha1.update(decrypted).digest('hex');
   console.log('输入到数据库中的密码是: ', password)
   // 存入数据库中
   // store to db...
   res.end('reg ok')
   break
 }
})

app.listen(3000, '127.0.0.1')

这里,我是用node自带模块crpto进行解密,当然,你也可以用Node-RSA的方法进行解密。

最后

我们再来看一看前端请求的密码信息:

node中的密码安全(加密)

这样一串字符,即便被他人获取,如果没有密钥,在一定程度上,他是无法知道你的密码的。

当然,关于网络安全是一个大话题,本篇只是对其中的一小部分进行介绍,欢迎留言讨论,希望对您有帮助。,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
FireFox JavaScript全局Event对象
Jun 14 Javascript
一些主流JS框架中DOMReady事件的实现小结
Feb 12 Javascript
multiSteps 基于Jquery的多步骤滑动切换插件
Jul 22 Javascript
基于jQuery的弹出框插件
Mar 18 Javascript
20款非常优秀的 jQuery 工具提示插件 推荐
Jul 15 Javascript
javascript用户注册提示效果的简单实例
Aug 17 Javascript
几种经典排序算法的JS实现方法
Mar 25 Javascript
JavaScript事件学习小结(三)js事件对象
Jun 09 Javascript
深入理解jQuery 事件处理
Jun 14 Javascript
浅谈Vue的基本应用
Dec 27 Javascript
Vue.js项目实战之多语种网站的功能实现(租车)
Aug 07 Javascript
Ajax常用封装库——Axios的使用
May 08 Javascript
Vue CLI3搭建的项目中路径相关问题的解决
Sep 17 #Javascript
浅谈webpack SplitChunksPlugin实用指南
Sep 17 #Javascript
vue的过滤器filter实例详解
Sep 17 #Javascript
一步一步的了解webpack4的splitChunk插件(小结)
Sep 17 #Javascript
React Router V4使用指南(精讲)
Sep 17 #Javascript
关于vue编译版本引入的问题的解决
Sep 17 #Javascript
理顺8个版本vue的区别(小结)
Sep 17 #Javascript
You might like
php 静态属性和静态方法区别详解
2017/04/09 PHP
详解PHP函数 strip_tags 处理字符串缺陷bug
2017/06/11 PHP
比较简单的一个符合web标准的JS调用flash方法
2007/11/29 Javascript
Javascript load Page,load css,load js实现代码
2010/03/31 Javascript
javascript管中窥豹 形参与实参浅析
2011/12/17 Javascript
jquery插件珍藏(图片局部放大/信息提示框)
2013/01/08 Javascript
javaScript如何处理从java后台返回的list
2014/04/24 Javascript
用jquery实现的一个超级简单的下拉菜单
2014/05/18 Javascript
js解决select下拉选不中问题
2014/10/14 Javascript
jQuery实现图片渐入渐出切换展示效果
2015/08/15 Javascript
跟我学习javascript的call(),apply(),bind()与回调
2015/11/16 Javascript
基于jQuery实现淡入淡出效果轮播图
2020/07/31 Javascript
浅谈js的异步执行
2016/10/18 Javascript
angular2中Http请求原理与用法详解
2018/01/11 Javascript
使用vue2实现购物车和地址选配功能
2018/03/29 Javascript
详解Vue开发微信H5微信分享签名失败问题解决方案
2018/08/09 Javascript
原生JS实现轮播图效果
2018/10/12 Javascript
vue+VeeValidate 校验范围实例详解(部分校验,全部校验)
2018/10/19 Javascript
vue通过过滤器实现数据格式化
2020/07/20 Javascript
Java 生成随机字符的示例代码
2021/01/13 Javascript
Python中的取模运算方法
2018/11/10 Python
python计算二维矩形IOU实例
2020/01/18 Python
python中使用paramiko模块并实现远程连接服务器执行上传下载功能
2020/02/29 Python
Python使用requests xpath 并开启多线程爬取西刺代理ip实例
2020/03/06 Python
python GUI库图形界面开发之PyQt5信号与槽事件处理机制详细介绍与实例解析
2020/03/08 Python
纯HTML5+CSS3制作生日蛋糕(代码易懂)
2016/11/16 HTML / CSS
英国领先的酒杯和水晶玻璃器皿制造商:Dartington Crystal
2019/06/23 全球购物
Monica Vinader官网:英国轻奢珠宝品牌
2020/02/05 全球购物
饮料业务员岗位职责
2013/12/15 职场文书
老公保证书
2015/01/17 职场文书
2015年关爱留守儿童工作总结
2015/05/22 职场文书
刑事上诉状范文
2015/05/22 职场文书
React-vscode使用jsx语法的问题及解决方法
2021/06/21 Javascript
Spring Cloud Gateway去掉url前缀
2021/07/15 Java/Android
MySQL8.0升级的踩坑历险记
2021/11/01 MySQL
一次Mysql update sql不当引起的生产故障记录
2022/04/01 MySQL