RSA加密算法在WEB中的应用

加密算法有很多,如不可逆的摘要算法MD5、SHA(安全哈希算法),可逆的Base64编码,对称加密算法DES、AES,还有非对称加密算法DH、RSA等。那是不是说明我们可以使用任何一种加密算法就能保证网站的安全性,答案是否。举个例子,我们在登录web页面时,发送用户名和密码给服务器,这时请求被拦截了:

(1) 密码采用不可逆加密。因为不可逆加密算法就几种,不管怎样变换,攻击者都可以模拟登录;

(2) 密码采用可逆加密算法。因为加密是在前端进行加密,所以可能通过js代码看到加密方式,这样也就很容易破解了。

所以针对浏览器-服务器这种模式,最好采用非对称加密算法,即使攻击者知道了加密算法和公钥,他也没法解密,因为用公钥加密的数据只能用私钥才能解密,而且私钥始终保存在服务器,攻击者无法获取。

今天总结一下项目中使用非对称加密算法RSA实现登录验证的过程。

一、RSA非对称加密算法介绍

RSA加密算法是一种非对称加密算法,在甲乙方的通信过程中,首先甲方(通常是服务端)会生成一对秘钥对,称作公钥(Public Key)和私钥(Private Key),然后他把生成的公钥或私钥发送给乙方(客户端),乙方获取到公钥或私钥之后,用它将原始数据加密后发送给甲方,此时甲方用私钥或公钥对乙方发送过来的加密数据进行解密,在整个通信过程中,即使请求被拦截,攻击者获取到了暴露的秘钥和加密数据也无法解密,因为只能使用甲方手中的私钥才能解密,而在整个通信过程中私钥始终保存在甲方手中,没有在通信过程中传递,所以攻击者也就很难获取到,除非是甲方有意暴露。如下图所示:

上图的过程描述为:

1、  web服务器生成密钥对

2、  客户端(浏览器)从服务器获取公钥

3、  客户端用获取的公钥对原始数据加密后发送给web服务器

4、  Web服务器接受加密后的数据并获取到私钥

5、  Web服务器用私钥对数据进行解密

在上图中,采用的是公钥加密,私钥解密,还可以使用私钥加密,公钥解密的方式,关键是服务器只暴露其中的一个秘钥给客户端进行加密,另一个自己保存用来解密。

二、用PHP实现RSA加解密过程

第一步:生成密钥文件(公钥和私钥)

注:在生成秘钥对之前,需要在linux系统中安装openssl。

1、生成私钥文件

2、利用私钥生成公钥文件

3、秘钥文件生成结果

第二步:生成密钥对(公钥和私钥)

1、根据私钥文件生成私钥

function get_private_key() {
    return @file_get_contents(DATA_PATH . 'Cert/rsa_private_key.pem');
}

2、根据公钥文件生成公钥

function get_public_key() {
    return @file_get_contents(DATA_PATH . 'Cert/rsa_public_key.pem');
}

第三步:封装加密解密方法

1、公钥加密

/**
 * 公钥加密
 */
function rsa_encrypt($string) {
    $publicKey = get_public_key();
    $resource = openssl_pkey_get_public($publicKey);

    if (!is_resource($resource)) {
        return '';
    }

    $encrypted = "";
    openssl_public_encrypt($string, $encrypted, $resource);

    return $encrypted;
}

2、私钥解密

/**
 * 私钥解密
 */
function rsa_decrypt($string) {
    $privateKey = get_private_key();
    $resource = openssl_pkey_get_private($privateKey);

    if (!is_resource($resource)) {
        return '';
    }

    $decrypted = '';

    try {
        openssl_private_decrypt($string, $decrypted, $resource);

        return $decrypted;
    } catch (Exception $e) {
        return '';
    }
}

第四步:测试结果

简单写一个方法进行测试

    /**
     * 测试RSA加密解密
     */
    public function testEncode(){
        $data = 'hello world!';
        var_dump('加密前的数据:'.$data);
        $encodeData = rsa_encrypt($data);
        var_dump('公钥加密后的数据:'.$encodeData);
        $decodeData = rsa_decrypt($encodeData);
        var_dump('私钥解密后的数据:'.$decodeData);
    }

 测试结果如下:

从上面结果可以看到原始数据【hello world!】解密后也是【hello world!】,说明使用RSA加解密成功,但是加密后的结果中有乱码,这一问题的解决方式就是在加密和解密过程中使用base64编码。

第五步:解决加密乱码问题

1、公钥加密(加密结果进行base64编码)

 1 /**
 2  * 公钥加密
 3  */
 4 function rsa_encrypt($string) {
 5     $publicKey = get_public_key();
 6     $resource = openssl_pkey_get_public($publicKey);
 7 
 8     if (!is_resource($resource)) {
 9         return '';
10     }
11 
12     $encrypted = "";
13     openssl_public_encrypt($string, $encrypted, $resource);
14 
15     return base64_encode($encrypted);
16 }

 注:上面的第15行中对加密结果进行base64编码。

2、私钥解密(解密之前对加密数据进行base64解码)

 1 /**
 2  * 私钥解密
 3  */
 4 function rsa_decrypt($string) {
 5     $privateKey = get_private_key();
 6     $resource = openssl_pkey_get_private($privateKey);
 7 
 8     if (!is_resource($resource)) {
 9         return '';
10     }
11 
12     $decrypted = '';
13 
14     try {
15         openssl_private_decrypt(base64_decode($string), $decrypted, $resource);
16 
17         return $decrypted;
18     } catch (Exception $e) {
19         return '';
20     }
21 }

注:上面的第15行中,在解密之前对加密数据进行base64解码 

3、查看优化后的结果

以上就是用PHP实现的服务端加解密全部过程,需要注意以下几点:

1、  在linux中生成密钥文件之前需要安装openssl库

2、  为解决加密数据出现的乱码问题,需要对加密后的数据进行base64编码

三、B/S模式下的rsa加密

1、前端加密库

PHP端的加解密,可用在第三方跟平台之前的传输数据,但是如果是前端传到后端呢?我们知道前端是采用JavaScript处理业务逻辑,所以当用户密码等数据传到后台服务器之前需要用JavaScript进行加密,假设后台语言是PHP,那么这就涉及加解密一致性的问题,相当于两种语言结合实现rsa非对称加解密过程。而JavaScript已经有了一个加密库jsencrypt.js。

2、jsencrypt.js库的使用

一般来说,前端加密所用到的密钥(公钥或私钥)都是服务器传过来的,前端只需要负责将原始数据加密后传给后台就可以。这里为了介绍jsencrypt.js库的使用,假设前端已经获取到了公钥和私钥,并使用公钥加密,私钥解密。一般只会获取其中的一个进行前端加密,如果是公钥加密,服务端使用私钥解密;如果是私钥加密,服务端使用公钥解密,这里是为了验证jsencrypt.js的加解密效果获取到公钥和私钥的,不要误解。

①公钥加密

  /* 公钥加密 */
    function rsaEncrypt(valueData) {
        var PublicKey = $("#txt_rsa_public_key").val();
        var encrypt = new JSEncrypt();
        encrypt.setPublicKey(PublicKey);
        
        var encrypted = encrypt.encrypt(valueData);
        
        return encrypted;
    }

②私钥解密

  /* 私钥解密 */
    function rsaDecrypt(valueData) {
        var PrivateKey = $("#txt_rsa_private_key").val();
        var decrypt = new JSEncrypt();
        decrypt.setPrivateKey(PrivateKey);
        
        var decrypted = decrypt.decrypt(valueData);
        
        return decrypted;
    }

③测试方法

  /* 测试加解密 */
    function testRsa(){
        var data = "hello world!";
        console.info("加密前的数据:"+data);
        var encodeData = rsaEncrypt(data);
        console.info("使用公钥加密后的数据:"+encodeData);
        var decodeData = rsaDecrypt(encodeData);
        console.info("使用私钥解密后的数据:"+decodeData);
    }

④测试结果

 

根据上面的示例,可以总结用JS实现ras加解密的过程为:

1、  获取JSEncrypt对象。(加密解密都使用同一个实例)

2、  给JSEncrypt对象设置私钥/公钥

3、  调用对象的加密解密方法

由此可以看出,前端加密不需要设置base64编码解码的过程。

四、web登录过程中RSA的运用

通过以上介绍,知道了前后端怎么使用非对称加密算法RSA进行加密解密的过程,可以利用这两部分内容实现web登录过程中对密码的加密,具体的实现过程这里不再赘述,这里只介绍一下流程:

1、在你所用的web服务器(Apache、Tomcat等)指定目录下生成私钥文件;

2、在相同目录下利用私钥文件生成公钥文件;

3、在服务端(代码中)生成公钥和私钥;

4、客户端(WEB前端)从服务端获取公钥;

5、将密码等敏感信息使用公钥加密后传给后台(ajax方式);

6、服务端获取到加密数据后使用自己的私钥进行解密;

以上就是加解密的完整过程,至于其他的密码是否正确之类的验证,就是其他的业务逻辑了。

本次服务端使用PHP,下次介绍服务端Java的方式。

原文地址:https://www.cnblogs.com/hellowhy/p/9377928.html