使用RSA加密传输账号密码信息

1 篇文章 0 订阅
1 篇文章 0 订阅

原文地址:https://blog.springcoder.cn/posts/5b7ae417.html

背景

在开发中,通常会偷懒将用户的登录信息(账号密码)直接以明文的方式发送到后端,但我们的项目不是所有都用了https,这在传输过程中存在一定的风险,于是,我们可以通过RSA非对称加密,将用户输入的账号密码进行加密后传输到后端,后端通过私钥解密后得到原始数据,进行后续的逻辑处理。

生成密钥

这里我们可以使用linux自带的openssl来生成密钥,首先生成私钥,通过如下命令生成:

openssl genrsa -out rsa_private_key.pem 1024

参数1024表示生成的密钥长度为1024比特,默认为2048,生成私钥后,我们通过私钥生成公钥:

openssl rsa -in rsa_private_key.pem -pubout -out rsa_public_key.pem

通过上述命令,即可生成公钥和私钥,对应两个文件,rsa_private_key.pemrsa_public_key.pem

PHP加密解密工具

上述生成了密钥,我们就可以直接用来进行加解密操作了,这里介绍php中实现rsa的加解密,密钥文件,我们可以直接使用,也可以将密钥字符复制到php文件中,这里不直接使用密钥文件。项目基于thinkphp5框架,我们在extra文件夹下新增一个文件rsa_key.php,内容如下:

<?php
/**
 * rsa加密公钥私钥
 */
return array(
    // 私钥
    'private_key' => '原样复制私钥文件中的内容',
    // 公钥
    'public_key' => '原样复制公钥文件中的内容',
);

新增一个工具类,用于加密解密:

<?php

namespace app\common\util;

class RSAUtil
{
    public $privateKey;
    public $publicKey;

    /**
     * 构造方法
     * @access public
     */
    public function __construct()
    {
        //这个函数可用来判断私钥是否是可用的,可用返回资源id Resource id
        //如果直接使用密钥文件,可通过函数file_get_contents()进行读取
        $this->privateKey = openssl_pkey_get_private(config('rsa_key.private_key'));
        //这个函数可用来判断公钥是否是可用的
        $this->publicKey = openssl_pkey_get_public(config('rsa_key.public_key'));
    }

    public function __call($method, $args)
    {
        return json(['status' => '01', 'msg' => '方法不存在']);
    }

    public function privateEncrypt($data)
    {
        $crypto = '';
        foreach (str_split($data, 117) as $chunk) {
            openssl_private_encrypt($chunk, $encryptData, $this->privateKey);
            $crypto .= $encryptData;
        }
        //加密后的内容通常含有特殊字符,需要编码转换下,在网络间通过url传输时要注意base64编码是否是url安全的
        $encrypted = $this->urlsafeB64encode($crypto);
        return $encrypted;
    }

    //加密码时把特殊符号替换成URL可以带的内容
    function urlsafeB64encode($string)
    {
        $data = base64_encode($string);
        $data = str_replace(array('+', '/', '='), array('-', '_', ''), $data);
        return $data;
    }

    //解密码时把转换后的符号替换特殊符号
    function urlsafeB64decode($string)
    {
        $data = str_replace(array('-', '_'), array('+', '/'), $string);
        $mod4 = strlen($data) % 4;
        if ($mod4) {
            $data .= substr('====', $mod4);
        }
        return base64_decode($data);
    }

    //私钥加密的内容通过公钥可用解密出来
    public function publicDecrypt($encrypted)
    {
        $crypto = '';
        foreach (str_split($this->urlsafeB64decode($encrypted), 128) as $chunk) {
            openssl_public_decrypt($chunk, $decryptData, $this->publicKey);
            $crypto .= $decryptData;
        }
        return $crypto;
    }

    //公钥加密
    public function publicEncrypt($data)
    {
        $crypto = '';
        foreach (str_split($data, 117) as $chunk) {
            openssl_public_encrypt($chunk, $encryptData, $this->publicKey);
            $crypto .= $encryptData;
        }
        $encrypted = $this->urlsafeB64encode($crypto);
        return $encrypted;
    }

    //私钥解密
    public function privateDecrypt($encrypted)
    {
        $crypto = '';
        foreach (str_split($this->urlsafeB64decode($encrypted), 128) as $chunk) {
            openssl_private_decrypt($chunk, $decryptData, $this->privateKey);
            $crypto .= $decryptData;
        }
        return $crypto;
    }
}

到此,后端的加解密就实现了。

JS前端加密传输

在登录界面,用户输入账号密码信息,点击登录,当参数校验通过,我们就可以对参数进行加密后,提交表单,这里使用jsencrypt实现前端的加密。

function encrypt(data) {
	const publicKey = {$private_key|json_encode};
	let encryptor = new JSEncrypt();
	encryptor.setPublicKey(publicKey)
	return encryptor.encrypt(data)
}

这样,我们可以发现,提交的数据就是被加密过的密文了。

image-20220916152206475

后端接收到参数后,对参数进行解密,即可得到原始数据。

// 登录信息解密
$rsaUtil = new RSAUtil();
$user_name = $rsaUtil->privateDecrypt('user_name');
$password = $rsaUtil->privateDecrypt('password');
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值