背景
在开发中,通常会偷懒将用户的登录信息(账号密码)直接以明文的方式发送到后端,但我们的项目不是所有都用了https
,这在传输过程中存在一定的风险,于是,我们可以通过RSA
非对称加密,将用户输入的账号密码进行加密后传输到后端,后端通过私钥解密后得到原始数据,进行后续的逻辑处理。
生成密钥
这里我们可以使用linux
自带的openssl
来生成密钥,首先生成私钥,通过如下命令生成:
1
| openssl genrsa -out rsa_private_key.pem 1024
|
参数1024表示生成的密钥长度为1024比特,默认为2048,生成私钥后,我们通过私钥生成公钥:
1
| openssl rsa -in rsa_private_key.pem -pubout -out rsa_public_key.pem
|
通过上述命令,即可生成公钥和私钥,对应两个文件,rsa_private_key.pem
和rsa_public_key.pem
。
PHP加密解密工具
上述生成了密钥,我们就可以直接用来进行加解密操作了,这里介绍php中实现rsa
的加解密,密钥文件,我们可以直接使用,也可以将密钥字符复制到php文件中,这里不直接使用密钥文件。项目基于thinkphp5
框架,我们在extra文件夹下新增一个文件rsa_key.php
,内容如下:
1 2 3 4 5 6 7 8 9 10
| <?php
return array( 'private_key' => '原样复制私钥文件中的内容', 'public_key' => '原样复制公钥文件中的内容', );
|
新增一个工具类,用于加密解密:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92
| <?php
namespace app\common\util;
class RSAUtil { public $privateKey; public $publicKey;
public function __construct() { $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; } $encrypted = $this->urlsafeB64encode($crypto); return $encrypted; }
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
实现前端的加密。
1 2 3 4 5 6
| function encrypt(data) { const publicKey = {$private_key|json_encode}; let encryptor = new JSEncrypt(); encryptor.setPublicKey(publicKey) return encryptor.encrypt(data) }
|
这样,我们可以发现,提交的数据就是被加密过的密文了。
后端接收到参数后,对参数进行解密,即可得到原始数据。
1 2 3 4
| $rsaUtil = new RSAUtil(); $user_name = $rsaUtil->privateDecrypt('user_name'); $password = $rsaUtil->privateDecrypt('password');
|