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 相关文章推荐
脚本吧 - 幻宇工作室用到js,超强推荐base.js
Dec 23 Javascript
js模拟滚动条(横向竖向)
Feb 22 Javascript
jQuery选择器源码解读(五):tokenize的解析过程
Mar 31 Javascript
jquery简单实现图片切换效果的方法
May 12 Javascript
一张Web前端的思维导图分享
Jul 03 Javascript
javascirpt实现2个iframe之间传值的方法
Jun 30 Javascript
jquery自动补齐功能插件flexselect用法示例
Aug 06 Javascript
快速解决js开发下拉框中blur与click冲突
Oct 10 Javascript
vue快捷键与基础指令详解
Jun 01 Javascript
vue给组件传递不同的值方法
Sep 29 Javascript
JQuery animate动画应用示例
May 14 jQuery
react中useState使用:如何实现在当前表格直接更改数据
Aug 05 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 时间转换Unix时间戳代码
2010/01/22 PHP
关于Sphinx创建全文检索的索引介绍
2013/06/25 PHP
利用PHP fsockopen 模拟POST/GET传送数据的方法
2015/09/22 PHP
基于php数组中的索引数组和关联数组详解
2018/03/12 PHP
学习jquery之一
2007/04/27 Javascript
js中获取事件对象的方法小结
2011/03/13 Javascript
浅析webapp框架AngularUI的demo
2014/12/21 Javascript
详解Vue爬坑之vuex初识
2017/06/14 Javascript
Bootstrap 模态框(Modal)带参数传值实例
2017/08/20 Javascript
微信小程序使用map组件实现检索(定位位置)周边的POI功能示例
2019/01/23 Javascript
Vue动态路由缓存不相互影响的解决办法
2019/02/19 Javascript
微信小程序:报错(in promise) MiniProgramError
2020/10/30 Javascript
python实现从网络下载文件并获得文件大小及类型的方法
2015/04/28 Python
详解python3中socket套接字的编码问题解决
2017/07/01 Python
Python模拟脉冲星伪信号频率实例代码
2018/01/03 Python
python十进制和二进制的转换方法(含浮点数)
2018/07/07 Python
python批量下载网站马拉松照片的完整步骤
2018/12/05 Python
Python3利用print输出带颜色的彩色字体示例代码
2019/04/08 Python
Python当中的array数组对象实例详解
2019/06/12 Python
python将字母转化为数字实例方法
2019/10/04 Python
Python使用tkinter实现摇骰子小游戏功能的代码
2020/07/02 Python
巴西电子、家电、智能手机购物网站:Girafa
2019/06/04 全球购物
ECOSUSI官网:女式皮革背包
2019/09/27 全球购物
New Balance比利时官方网站:购买鞋子和服装
2021/01/15 全球购物
德国亚马逊官方网站:Amazon.de
2020/11/15 全球购物
一份比较全的PHP面试题
2016/07/29 面试题
实习医生自我评价
2013/09/22 职场文书
机电专业毕业生求职信
2013/10/27 职场文书
有多年工作经验的自我评价
2014/03/02 职场文书
物业管理专业自荐信
2014/07/01 职场文书
领导欢迎词致辞
2015/01/23 职场文书
销售会议开幕词
2015/01/28 职场文书
劳动仲裁撤诉申请书
2015/05/18 职场文书
解决 Redis 秒杀超卖场景的高并发
2022/04/12 Redis
Java中的Kotlin 内部类原理
2022/06/16 Java/Android
css清除浮动clearfix:after的用法详解(附完整代码)
2023/05/21 HTML / CSS