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 相关文章推荐
javascript学习网址备忘
May 29 Javascript
node.js中的fs.chownSync方法使用说明
Dec 16 Javascript
JS中处理时间之setUTCMinutes()方法的使用
Jun 12 Javascript
jquery注册文本框获取焦点清空,失去焦点赋值的简单实例
Sep 08 Javascript
详解照片瀑布流效果(js,jquery分别实现与知识点总结)
Jan 01 Javascript
DOM事件探秘篇
Feb 15 Javascript
JS拉起或下载app的实现代码
Feb 22 Javascript
Express之get,pos请求参数的获取
May 02 Javascript
Vue中v-for的数据分组实例
Mar 07 Javascript
图片文字识别(OCR)插件Ocrad.js教程
Nov 26 Javascript
JavaScript模板引擎应用场景及实现原理详解
Dec 14 Javascript
jQuery简单实现根据日期计算星期几的方法
Jan 09 jQuery
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/05/05 PHP
浅谈laravel框架与thinkPHP框架的区别
2019/10/23 PHP
js 数据类型转换总结笔记
2011/01/17 Javascript
Javascript验证用户输入URL地址是否为空及格式是否正确
2014/10/09 Javascript
JS获取网页图片name属性的方法
2015/04/01 Javascript
异步JS框架的作用以及实现方法
2015/10/29 Javascript
五种js判断是否为整数类型方式
2015/12/03 Javascript
jQuery实现放大镜效果实例代码
2016/03/17 Javascript
全面解析JS字符串和正则表达式中的match、replace、exec等函数
2016/07/01 Javascript
jquery获取table指定行和列的数据方法(当前选中行、列)
2016/11/07 Javascript
一道面试题引发的对javascript类型转换的思考
2017/03/06 Javascript
js使用原型对象(prototype)需要注意的地方
2017/08/28 Javascript
JS二级菜单不同实现方法分析【4种方法】
2018/12/21 Javascript
jQuery Ajax async=&gt;false异步改为同步时,解决导致浏览器假死的问题
2019/07/22 jQuery
Vue源码分析之Vue实例初始化详解
2019/08/25 Javascript
js判断复选框是否选中的方法示例【基于jQuery】
2019/10/10 jQuery
解决vue-cli项目开发运行时内存暴涨卡死电脑问题
2019/10/29 Javascript
react quill中图片上传由默认转成base64改成上传到服务器的方法
2019/10/30 Javascript
JS定时器如何实现提交成功提示功能
2020/06/12 Javascript
Vue中keep-alive的两种应用方式
2020/07/15 Javascript
Python中的rjust()方法使用详解
2015/05/19 Python
ubuntu17.4下为python和python3装上pip的方法
2018/06/12 Python
解决Python pip 自动更新升级失败的问题
2020/02/21 Python
python实现测试工具(一)——命令行发送get请求
2020/10/19 Python
英文版区域经理求职信
2013/10/23 职场文书
《小猫刮胡子》教学反思
2014/02/21 职场文书
抽样调查项目计划书
2014/04/24 职场文书
信用卡逾期证明示例
2014/09/13 职场文书
受资助学生感谢信
2015/01/21 职场文书
骨干教师个人总结
2015/02/11 职场文书
2015大学生自我评价范文
2015/03/03 职场文书
道歉短信大全
2015/05/12 职场文书
宿舍卫生管理制度
2015/08/05 职场文书
幼儿园班级管理心得体会
2016/01/07 职场文书
工作计划范文之财务管理
2019/08/09 职场文书
Go 语言结构实例分析
2021/07/04 Golang