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 相关文章推荐
jQueryUI如何自定义组件实现代码
Nov 14 Javascript
使用JS或jQuery模拟鼠标点击a标签事件代码
Mar 10 Javascript
判断复选框是否被选中的两种方法
Jun 04 Javascript
深入理解JavaScript系列(48):对象创建模式(下篇)
Mar 04 Javascript
JS实现仿苹果底部任务栏菜单效果代码
Aug 28 Javascript
JS+CSS实现自适应选项卡宽度的圆角滑动门效果
Sep 15 Javascript
jquery 仿锚点跳转到页面指定位置的实例
Feb 14 Javascript
vue2+el-menu实现路由跳转及当前项的设置方法实例
Nov 07 Javascript
区别JavaScript函数声明与变量声明
Sep 12 Javascript
JS基于对象的链表实现与使用方法示例
Jan 31 Javascript
微信小程序实现Session功能及无法获取session问题的解决方法
May 07 Javascript
js中的this的指向问题详解
Aug 29 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
通过html表格发电子邮件
2006/10/09 PHP
PHP网上调查系统
2006/10/09 PHP
php heredoc和phpwind的模板技术使用方法小结
2008/03/28 PHP
thinkphp在php7环境下提示Cannot use ‘String’ as class name as it is reserved的解决方法
2016/09/30 PHP
iOS+PHP注册登录系统 PHP部分(上)
2016/12/26 PHP
php解决约瑟夫环算法实例分析
2019/09/30 PHP
javascript 拖放效果实现代码
2010/01/22 Javascript
用javascript关闭本窗口技巧小结
2014/09/05 Javascript
JavaScript中常见的字符串操作函数及用法汇总
2015/05/04 Javascript
jQuery CSS3相结合实现时钟插件
2016/01/08 Javascript
详解javascript立即执行函数表达式IIFE
2017/02/13 Javascript
详解axios在vue中的简单配置与使用
2017/05/10 Javascript
详解vue-cli快速构建项目以及引入bootstrap、jq
2017/05/26 Javascript
jQuery实现获取当前鼠标位置并输出功能示例
2019/01/05 jQuery
微信小程序地图导航功能实现完整源代码附效果图(推荐)
2019/04/28 Javascript
react koa rematch 如何打造一套服务端渲染架子
2019/06/26 Javascript
elementui之el-tebs浏览器卡死的问题和使用报错未注册问题
2019/07/06 Javascript
layui复选框的全选与取消实现方法
2019/09/02 Javascript
在vue-cli中引入lodash.js并使用详解
2019/11/13 Javascript
在vue项目中 实现定义全局变量 全局函数操作
2020/10/26 Javascript
Python获取服务器信息的最简单实现方法
2015/03/05 Python
在Python中使用M2Crypto模块实现AES加密的教程
2015/04/08 Python
在Python中使用itertools模块中的组合函数的教程
2015/04/13 Python
python爬虫之百度API调用方法
2017/06/11 Python
win7下python3.6安装配置方法图文教程
2018/07/31 Python
Pytorch卷积层手动初始化权值的实例
2019/08/17 Python
PyTorch中反卷积的用法详解
2019/12/30 Python
Python3监控windows,linux系统的CPU、硬盘、内存使用率和各个端口的开启情况详细代码实例
2020/03/18 Python
pycharm通过anaconda安装pyqt5的教程
2020/03/24 Python
SOA的常见陷阱或者误解是什么
2014/10/05 面试题
车队司机个人自我鉴定
2014/04/17 职场文书
实习评语大全
2014/04/26 职场文书
2014教师研修学习体会
2014/07/08 职场文书
四风问题个人自查剖析材料思想汇报
2014/09/21 职场文书
2014年乡镇工会工作总结
2014/12/02 职场文书
windows10 家庭版下FTP服务器搭建教程
2022/08/05 Servers