使用非对称加密(RSA) 实现前端加密后端解密

数据加密方式有:

单向加密、对称加密、非对称加密、加密盐、散列函数、数字签名。

1、单向加密

单向加密通过对数据进行摘要计算生成密文,密文不可逆推还原。只能加密,不能解密,常用于提取数据的指纹信息以此来验证数据的完整性。但是会引发雪崩效应(雪崩效应就是一种不稳定的平衡状态也是加密算法的一种特征,它指明文或密钥的少量变化会引起密文的很大变化,就像雪崩前,山上看上去很平静,但是只要有一点问题,就会造成一片大崩溃。 可以用在很多场合对于Hash码,雪崩效应是指少量消息位的变化会引起信息摘要的许多位变化。)

算法代表:Base64,MD5,SHA

2、对称加密

对称加密的加密和解密是使用同一个密钥;加密和解密的速度比较快,效率比较高;但是密钥传输过程不安全,容易破解,而且密钥管理也比较麻烦。

算法代表:DES,3DES,AES,IDEA,RC4,RC5

对称加密可以分为两类:序列密码和分组密码

2.1、序列密码
从概念上讲,序列密码(stream cipher)的操作过程与我们想象中加密的过程一致。将1字节的明文输入加密算法,就得到1字节的密文输出。在对端则进行相反的过程。整个过程持续重复,直到所有数据处理完成。因为这种思路比较简单,序列密码绝不能第二次使用相同的密钥。这是因为在实际使用中,攻击者知道或者可以预测特定区域的明文(请思考加密HTTP请求的情景;许多请求的请求方法、协议版本、请求头名称都是一样的)当你知道明文,又观察到密文时,就可以解析一部分密钥序列。如果使用了相同的密钥,那么就可以解密后续的部分密文。为了解这个问题,序列密码都与从长期密钥中提取出来的一次性密钥一同使用。

2.2、分组密码

分组密码(block cipher)每次加密一整块数据,并且现代的分组密码倾向于使用128位(16字节)大小的块。一种分组密码就是一个变换函数:接受输入并生成看似杂乱无章的输出。只要使用相同的密钥,每一个可能的输入组合都有唯一的输出。

我们可以理解为更高级的对称加密算法。这种加密算法也是非常常见,例如AES加密,有128位、192位和256位的加密强度。在现在的系统对接时,AES加密非常常见。

3、非对称加密

相对对称加密而言,无需拥有同一组密钥,非对称加密是一种“信息公开的密钥交换协议”。非对称加密需要公开密钥和私有密钥两组密钥,公开密钥和私有密钥是配对起来的,也就是说使用公开密钥进行数据加密,只有对应的私有密钥才能解密。这两个密钥是数学相关,用某用户密钥加密后的密文,只能使用该用户的加密密钥才能解密。如果知道了其中一个,并不能计算出另外一个。因此如果公开了一对密钥中的一个,并不会危害到另外一个密钥性质。这里把公开的密钥为公钥,不公开的密钥为私钥。

算法代表:RSA,DSA

4、加密盐

加密盐也是比较常听到的一个概念,盐就是一个随机字符串用来和我们的加密串拼接后进行加密。加盐主要是为了提供加密字符串的安全性。假如有一个加盐后的加密串,黑客通过一定手段这个加密串,他拿到的明文,并不是我们加密前的字符串,而是加密前的字符串和盐组合的字符串,这样相对来说又增加了字符串的安全性。

5、散列函数

散列函数在密码学中也是不可缺少的一部分。散列函数(hash function)是将任意长度的输入转化为定长输出的算法。谈到散列函数,肯定会想到MD5加密,这种就是一种最为常见的散列函数。散列函数的特点:

抗原像性(单向性)给定一个散列,计算上无法找到或者构造出生成它的消息。即不能还原,MD5即是一种单项加密,因此,经常用于密码加密,实现即使管理员也无法知道用户的密码的功能。
抗第二原像性(弱抗碰撞性)给定一条消息和它的散列,计算上无法找到一条不同的消息具有相同的散列。
强抗碰撞性 计算上无法找到两条散列相同的消息。

6、数字签名

在通过散列函数来验证消息完整性的时候,仅仅在信息和数据的散列分开传输的时候才可以,否则中间人可以修改数据的同时修改散列,从而避开检测。数字签名主要是验证数据的真伪。微信通过对称加密生成的签名,支付宝通过非对称加密生成签名。效果差别不大。只要足够证明自己的身份即可。

这里着重介绍下RSA,RSA是首个适用以签名作为加密的算法。被用于银行网上支付、电商交易。
RSA是Rivest、Shamir、Adleman三位数学家的缩写。其数学原理是大整数因数分解极其苦难的原因设计的一种算法。

RSA算法优点

不需要进行密钥传递,提高了安全性
可以进行数字签名认证

RSA算法缺点

加密解密效率不高,一般只适用于处理小量数据(如:密钥)
容易遭受小指数攻击

非加密算法实现流程图:
在这里插入图片描述
在此可以看到,非对称加密是通过两个密钥(公钥-私钥)来实现对数据的加密和解密的。公钥用于加密,私钥用于解密。

下面做一个简单的登录功能来测试示例

前端:这里用的是 jsencrypt.js

代码:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>测试</title>
</head>
<body>
<div>打开控制台查看</div>
</body>
<!--jquery cdn-->
<script src="https://apps.bdimg.com/libs/jquery/2.1.4/jquery.min.js"></script>
<!--引入jsencrypt.js  cdn-->
<script src="https://cdn.bootcss.com/jsencrypt/3.0.0-beta.1/jsencrypt.js"></script>
<script type="text/javascript">
    var publicKey = '公钥串';
    console.log(encrypt(publicKey, 'HelloWord'))

    // RSA前端加密
    function encrypt(key, oldPwd) {
      let encrypt = new JSEncrypt();
      encrypt.setPublicKey(key);
      let encrypted = encrypt.encrypt(oldPwd);
      return encrypted;
    }
</script>
</html>

获取表单值并请求接口:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<form id="doLogin">
    <!--用户名-->
    <input type="text"  name="username" required="" autofocus="">
    <!--密码-->
    <input type="password" name="password" required="">
    <button type="button" id="bt">登录</button>
    <a th:href="@{/AddPage}">注册</a>
</form>
</body>
<!--jquery cdn-->
<script src="https://apps.bdimg.com/libs/jquery/2.1.4/jquery.min.js"></script>
<!--引入jsencrypt.js  cdn-->
<script src="https://cdn.bootcss.com/jsencrypt/3.0.0-beta.1/jsencrypt.js"></script>
<script type="text/javascript">
    var publicKey = '公钥串';
    
    // RSA前端加密
    function encrypt(key, oldPwd) {
      let encrypt = new JSEncrypt();
      encrypt.setPublicKey(key);
      let encrypted = encrypt.encrypt(oldPwd);
      return encrypted;
    }

    $("#bt").click(function () {
      let data = $("#doLogin").serializeArray();
      console.log(data)
      
      var obj = {}
      data.forEach((item) => {
        obj[item.name] = item.value
      })
      console.log(obj)

      $.ajax({
        url: '/app/v1/checkSign',
        type: 'get',
        data: getSign(obj),
        dataType: 'json',
        success: function (res) {
          console.log(res)
        }
      })
    })

    function getSign(params) {
      var signParam = "";
      var bandParam = publicKey;
      params["signTime"] = (new Date().getTime() / 1000).toFixed(0);
      var sign = '';
      var newData = Object.keys(params).sort();
      for (var i = 0; i < newData.length; i++) {
        if (
          Object.prototype.toString.call(params[newData[i]]) !==
          "[object Array]" &&
          Object.prototype.toString.call(params[newData[i]]) !== "[object Object]"
        ) {
          if (newData[i] !== "sign") {
            sign += newData[i] + params[newData[i]];
          }
        }
      }
      signParam = encrypt(publicKey, sign);
      params["sign"] = signParam;
      return params;
    }
</script>
</html>

也可以在页面放一个隐藏域,用于存放公钥:

<!--也可以页面放置一个隐藏域标签,用于存放公钥-->
<input type="hidden" th:value="${session.publicKey}" id="publicKey">
  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值