美文网首页
RSA前端加密后端解密(密钥动态生成)

RSA前端加密后端解密(密钥动态生成)

作者: 周老一员 | 来源:发表于2019-12-11 17:42 被阅读0次

    RSA 是什么

    RSA 是一种非对称加密算法,简单概括,就是加密和解密时使用不同的密钥进行。

    问题

    一般在进行WEB开发过程中,少不了用户登录功能的开发,用户在登录时需要输入用户名(或邮箱等其它唯一标识信息)和密码进行系统登录。如果密码通过明文的方式进行http传输并登录时,密码将能被人查看到。此时多数人会想到MD5编码,通过将密码进行MD5编码成无法解密的密文,则他人就算获取到该密文,也无法解密获取其原始密码。但后台需要获取该原始密码进行校验登录的操作,那么MD5编码不可取。搜索相关如何保证账号密码安全的文章,了解到RSA这种非对称加密算法。

    方案确定

    网上的许多Jsencrypt库进行前端加密,java后台解密的代码,但只适用于公钥和私钥确定的情况。本文为提高安全性,目标是后台动态生成公钥私钥对。
    整体方案:后台动态生成RSA的密钥,将公钥发送给前端,并将私钥通过session保存在服务器,让前端进行加密操作后才将密文传给后端,后端使用对应私钥进行解密操作。
    前端:TypeScript
    后端:Java

    前端(JavaScript/TypeScript)加密实践

    前端进行RSA加密的第三方库采用 node-forge 库,其他如 Jsencrypt 库等暂时没有调试成功。

    前端代码:

    import * as forge from 'node-forge';
    
          // publicKey需要先通过http从后台获取,后台可以写一些geKey接口供前端调用
    
          const pki = forge.pki;
    
          // 规定格式:publicKey之前需要加'-----BEGIN PUBLIC KEY-----\n',之后需要加'\n-----END PUBLIC KEY-----'
          const publicK = pki.publicKeyFromPem('-----BEGIN PUBLIC KEY-----\n' + publicKey + '\n-----END PUBLIC KEY-----');
    
          // forge通过公钥加密后一般会是乱码格式,可进行base64编码操作再进行传输,相应的,后台获取到密文的密码后需要先进行base64解码操作再进行解密
          const passwordCrypto =  forge.util.encode64(publicK.encrypt(password));
          
          // ... 后面就是进行常规的发送登录请求,不同的是,也需要将publicKey作为一个参数传输到后台,后台需要以此找到对应的私钥
    

    后端(Java)解密实践

    网上后端解密的代码很多,但质量无法确保,正好我使用的 Hutool 这个Java的工具库,其中包含了非对称加密的工具,可以直接使用。

    Java代码:

    /**
      * 获取秘钥-RSA
      * @return
      */
    @RequestMapping(value = "/getKey",method = RequestMethod.POST)
    @ResponseBody
    public Result<String> getKeyOfRSA() {
        Result<String> result = new Result<>();
    
        RSA rsa = new RSA();
        String privateKeyBase64 = rsa.getPrivateKeyBase64();
        String publicKeyBase64 = rsa.getPublicKeyBase64();
    
        // 使用当前用户的session进行保存公钥私钥对
        Subject currentUser = SecurityUtils.getSubject();
        Session session = currentUser.getSession();
        session.setAttribute(publicKeyBase64, privateKeyBase64);
        return result.successWithData(publicKeyBase64);
    }
    
    
    /**
         * 解密password
         * @param password
         * @param publicKey
         * @return
         * @throws Exception
         */
        private String checkPassword(String password, String publicKey, String algorithm) throws Exception {
            Subject currentUser = SecurityUtils.getSubject();
            Session session = currentUser.getSession();
    
            // publicKey需要前端返回
            String privateKey = (String) session.getAttribute(publicKey);
            if(privateKey ==null){
                log.error("session中私钥失效.publickey={},password={}",publicKey,password);
                return null;
            }
            // 获取到私钥之后,需要将session中的该公钥私钥对信息移除
            session.removeAttribute(publicKey);
            // 构建,当只用私钥进行构造对象时,只允许使用该私钥进行加密和解密操作,本文只需要进行私钥解密,故只使用私钥构造对象
            RSA rsa = new RSA(privateKey, null);
            // 密码的密文先进行base64解码,之后再进行解密
            byte[] decrypt = rsa.decrypt(Base64.decode(password), KeyType.PrivateKey);
            String decryptStr = StrUtil.str(decrypt, CharsetUtil.CHARSET_UTF_8);
            
            return decryptStr;
        }
    

    相关文章

      网友评论

          本文标题:RSA前端加密后端解密(密钥动态生成)

          本文链接:https://www.haomeiwen.com/subject/dykagctx.html