• cookie加密解密和保证数据完整性(不被篡改)


    cookie加密解密和保证数据完整性

    AES-128-CBC`加密算法

    AES-128-CBC是一种分组对称加密算法,即用同一组key进行明文和密文的转换,以128bit为一组,128bit==16Byte,意思就是明文的16字节为一组对应加密后的16字节的密文。
    若最后剩余的明文不够16字节,需要进行填充,通常采用PKCS7进行填充。比如最后缺3个字节,则填充3个字节的0x03;若最后缺10个字节,则填充10个字节的0x0a;
    若明文正好是16个字节的整数倍,最后要再加入一个16字节0x10的组再进行加密

    CBC加密原理:
    明文跟向量异或,再用KEY进行加密,结果作为下个BLOCK的初始化向量。

    解密原理:
    使用密钥先对密文解密,解密后再同初始向量异或得到明文。

    加密时需要的参数:
    1、传入要加密的明文
    2、传入一个16字节的key
    3、传入一个16字节的初始偏移向量IV

    解密时需要的参数:

    1、带解密的密文
    2、加密解密的key一致
    3、跟加密时传递IV参数一致

    正文:

    laravel初始化会加载 \App\Http\Middleware\EncryptCookies::class中间件用来加密解密cookie
    代码:

    
    use Illuminate\Cookie\Middleware\EncryptCookies as Middleware;
    
    class EncryptCookies extends Middleware
    {
        /**
         * The names of the cookies that should not be encrypted.
         *
         * @var array
         */
        protected $except = [
            //
        ];
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    EncryptCookies 继承了 EncryptCookies,处理逻辑都在EncryptCookies这个类中

    关键代码:

        /**
         * Handle an incoming request.
         *
         * @param  \Illuminate\Http\Request  $request
         * @param  \Closure  $next
         * @return \Symfony\Component\HttpFoundation\Response
         */
        public function handle($request, Closure $next)
        {
            return $this->encrypt($next($this->decrypt($request))); //加密解密
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    加密代码:

        /**
         * Encrypt the given value.
         *
         * @param  mixed  $value
         * @param  bool  $serialize
         * @return string
         *
         * @throws \Illuminate\Contracts\Encryption\EncryptException
         */
        public function encrypt($value, $serialize = true)
        {
            $iv = random_bytes(openssl_cipher_iv_length($this->cipher));//偏移向量IV
    
    
            // First we will encrypt the value using OpenSSL. After this is encrypted we
            // will proceed to calculating a MAC for the encrypted value so that this
            // value can be verified later as not having been changed by the users.
            $value = \openssl_encrypt(
                $serialize ? serialize($value) : $value,
                $this->cipher, $this->key, 0, $iv
            );//key在.env中配置
    
            if ($value === false) {
                throw new EncryptException('Could not encrypt the data.');
            }
    
            // Once we get the encrypted value we'll go ahead and base64_encode the input
            // vector and create the MAC for the encrypted value so we can then verify
            // its authenticity. Then, we'll JSON the data into the "payload" array.
            $mac = $this->hash($iv = base64_encode($iv), $value); //签名,base64加密之后再计算,双重加密
    
            $json = json_encode(compact('iv', 'value', 'mac'));
      
    
            if (json_last_error() !== JSON_ERROR_NONE) {
                throw new EncryptException('Could not encrypt the data.');
            }
    
            return base64_encode($json);//再次加密
        }
    
    • 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

    这里的$this->encrypter对应是vendor/laravel/framework/src/Illuminate/Encryption/Encrypter.php类

      /**
         * Encrypt the given value.
         *
         * @param  mixed  $value
         * @param  bool  $serialize
         * @return string
         *
         * @throws \Illuminate\Contracts\Encryption\EncryptException
         */
        public function encrypt($value, $serialize = true)
        {
            $iv = random_bytes(openssl_cipher_iv_length($this->cipher));
    
            // First we will encrypt the value using OpenSSL. After this is encrypted we
            // will proceed to calculating a MAC for the encrypted value so that this
            // value can be verified later as not having been changed by the users.
            $value = \openssl_encrypt(
                $serialize ? serialize($value) : $value,
                $this->cipher, $this->key, 0, $iv
            );
    
            if ($value === false) {
                throw new EncryptException('Could not encrypt the data.');
            }
    
            // Once we get the encrypted value we'll go ahead and base64_encode the input
            // vector and create the MAC for the encrypted value so we can then verify
            // its authenticity. Then, we'll JSON the data into the "payload" array.
            $mac = $this->hash($iv = base64_encode($iv), $value);
    
            $json = json_encode(compact('iv', 'value', 'mac'));
    
            if (json_last_error() !== JSON_ERROR_NONE) {
                throw new EncryptException('Could not encrypt the data.');
            }
    
            return base64_encode($json);
        }
    
    • 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

    Laravel 的加密机制使用的是 OpenSSL 所提供的 AES-256 和 AES-128 加密,所有 Laravel 加密之后的结果都会使用消息认证码 (MAC) 签名,使其底层值不能在加密后再次修改
    采用的是AES-128-CBC加密算法

    解密代码:

      /**
         * Decrypt the given value.
         *
         * @param  string  $payload
         * @param  bool  $unserialize
         * @return mixed
         *
         * @throws \Illuminate\Contracts\Encryption\DecryptException
         */
        public function decrypt($payload, $unserialize = true)
        {
            $payload = $this->getJsonPayload($payload);
    
            $iv = base64_decode($payload['iv']);
    
            // Here we will decrypt the value. If we are able to successfully decrypt it
            // we will then unserialize it and return it out to the caller. If we are
            // unable to decrypt this value we will throw out an exception message.
            $decrypted = \openssl_decrypt(
                $payload['value'], $this->cipher, $this->key, 0, $iv
            );
    
            if ($decrypted === false) {
                throw new DecryptException('Could not decrypt the data.');
            }
    
            return $unserialize ? unserialize($decrypted) : $decrypted;
        }
    
    • 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
       /**
         * Get the JSON array from the given payload.
         *
         * @param  string  $payload
         * @return array
         *
         * @throws \Illuminate\Contracts\Encryption\DecryptException
         */
        protected function getJsonPayload($payload)
        {
            $payload = json_decode(base64_decode($payload), true); //之前加密这里对应解密
            var_dump($payload);
    
            // If the payload is not valid JSON or does not have the proper keys set we will
            // assume it is invalid and bail out of the routine since we will not be able
            // to decrypt the given value. We'll also check the MAC for this encryption.
            if (! $this->validPayload($payload)) {
                throw new DecryptException('The payload is invalid.');
            }
    
            if (! $this->validMac($payload)) {
                throw new DecryptException('The MAC is invalid.');
            }
    
            return $payload;
        }
    
    • 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
    array(3) {
      ["iv"]=>
      string(24) "YlBI1gpkduvfhdVbKtVI0g=="
      ["value"]=>
      string(64) "kdL5N3LkUNoCtsHFcQAWmBx4+3+pCH6814uV0l4Y3A4qMhxr2/ZsT9W/VGXU21yB"
      ["mac"]=>
      string(64) "4d47c1452cf3b8772e6528dae7247a51a9b95e36636b9228ab4f081522a55b8e"
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    关键代码:
    t h i s − > v a l i d M a c ( this->validMac( this>validMac(payload)方法验证数据完整性

        /**
         * Determine if the MAC for the given payload is valid.
         *
         * @param  array  $payload
         * @return bool
         */
        protected function validMac(array $payload)
        {
            $calculated = $this->calculateMac($payload, $bytes = random_bytes(16));同样算法算出签名
    
            return hash_equals( 
                hash_hmac('sha256', $payload['mac'], $bytes, true), $calculated
            );//和之前存储的签名作比较
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
        /**
         * Calculate the hash of the given payload.
         *
         * @param  array  $payload
         * @param  string  $bytes
         * @return string
         */
        protected function calculateMac($payload, $bytes)
        {
            return hash_hmac(
                'sha256', $this->hash($payload['iv'], $payload['value']), $bytes, true
            );
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    扩展

    数字签名:
    在这里插入图片描述
    验签:

    在这里插入图片描述

  • 相关阅读:
    elasticsearch 中text与keyword的区别
    GeoServer改造Springboot源码一(公共部分)
    opencv识别一张图片的多个红框,并截取红框的内容
    Qt在线安装教程(详细图文)
    uniapp微信小程序蓝牙连接与设备数据对接
    2023年全国大学生电子信息竞赛E题——自动追踪系统(stm32和openmv+普通舵机)完美解决第四问
    数学知识—不同数据范围求组合数,例题、思路、代码实现
    移动应用数据安全管理要求(一)
    LabVIEW避免在使用functional global时内存中有多个大数组的拷贝
    2023年【北京市安全员-A证】考试报名及北京市安全员-A证考试资料
  • 原文地址:https://blog.csdn.net/qq_39586877/article/details/128187747