• 使用Hashids来保护你的数据库主键


    为什么要保护数据库主键?

    数据库主键一般是有序自增主键,极易被爬虫抓取数据,作为应用开发者,这是不应该的,你辛辛苦苦收集的数据转眼之间被其他人给抓取了,是不是很大的损失?

    Hashids的介绍

    generate short unique ids from integers

    理解为数字编码库即可,几乎支持市面上所有语言。

    available in JavaScript, Ruby, Python, Java, Scala, PHP, Perl, Perl 6, Swift, Clojure, Objective-C, C, C++11, D, F#, Go, Erlang, Lua, Haskell, OCaml, Elixir, Rust, Smalltalk, ColdFusion, Groovy, Kotlin, Nim, VBA, Haxe, Crystal, Elm, ActionScript, CoffeeScript, Bash, R, TSQL, PostgreSQL and for

    PHP使用

    $hashids = new HashidsHashids('this is my salt');
    $id = $hashids->encode(1, 2, 3);
    $numbers = $hashids->decode($id);
    

    注意

    该库并不是一个加密库,所以不建议用来加密敏感数据,我们的数据库主键ID并不是业务上的敏感数据,所以这个没关系。

    Yii2的使用

    由于该编解码是独立与业务之外的,所以需要处理的地方在下面:

    1. 接收请求数据的自动解码
    2. 响应数据的自动编码(本文只针对JSON响应处理,有需要的可以添加ResponseFormatter自行处理)

    这两个步骤不应该提现在控制器中,控制器拿到的数据是解码好的,响应的数据是原始数据,然后我们在响应中处理。

    代码

    助手类(HashidsHelper)

    
    class HashidsHelper {
        public static function encode($id)
        {
            $hashids = new HashidsHashids('salt',16);
            return $hashids->encode($id);
        }
    
        public static function decode($hash)
        {
            $hashids = new HashidsHashids('salt',16);
            $data= $hashids->decode($hash);
            return empty($data)?null:$data;
        }
    
        public static function decodeArray(array $hashes)
        {
            return array_map([HashidsHelper::class, 'decode'], $hashes);
        }
    /**
         * 递归编码
         * @param array $data
         */
        public static function encodeRecursive(array &$data)
        {
            foreach ($data as $key => &$value) {
                if (is_array($value)) {
                    self::encodeRecursive($value);
                    continue;
                }
                if (strpos($key, 'id') !== false && is_numeric($value)) {
                    $data[$key] = static::encode($value);
                }
            }
        }
    
        /**
         * 递归解码
         * @param array $data
         */
        public static function decodeRecursive(array &$data)
        {
            foreach ($data as $key => &$value) {
                if (is_array($value)) {
                    self::decodeRecursive($value);
                    continue;
                }
                if (strpos($key, 'id') !== false) {
                    if (is_string($value)) {
                        $id = static::decode($value);
                        $data[$key] = $id ?? $value;
                    } elseif (is_array($value)) {
                        $data[$key] = static::decodeArray($value);
                    }
                }
            }
        }
    }
    

    处理请求数据($_POST,$_PUT,$_GET)提交过来的数据

    1.新建JsonParser继承Yii自带的JsonParser,代码如下

    
    class JsonParser extends yiiwebJsonParser
    {
        /**
         * @inheritDoc
         */
        public function parse($rawBody, $contentType)
        {
            $data = parent::parse($rawBody, $contentType);
            if ($data !== null) {
                HashidsHelper::decodeRecursive($data);
            }
            return $data;
        }
    }
    

    2.新建Request集成Yii自带的Request,重写getQueryParams,代码如下:

        public function getQueryParams()
        {
            $data = parent::getQueryParams();
            if ($data !== null) {
                HashidsHelper::decodeRecursive($data);
            }
            return $data;
        }
    

    3.配置web.php的components,更改为我们自定义的处理器

            'request' => [
                'class' => appcomponentsRequest::class,
                // !!! insert a secret key in the following (if it is empty) - this is required by cookie validation
                'cookieValidationKey' => '123456',
                'enableCsrfValidation' => false,
                'parsers' => [
                    'application/json' => appcomponentswebJsonParser::class
                ]
            ],
    

    处理响应数据

    1.新建JsonResponseFormatter继承Yii的JsonResponseFormatter,代码如下:

    class JsonResponseFormatter extends yiiwebJsonResponseFormatter
    {
        /**
         * @inheritDoc
         */
        public function format($response)
        {
            if ($response->data !== null) {
                HashidsHelper::encodeRecursive($response->data);
            }
            parent::format($response);
        }
    }
    

    2.配置web.php的components,替换response组件

            'response' => [
                'class' => appcomponentswebResponse::class,
                'format' => Response::FORMAT_JSON,
                'formatters' => [
                    'json' => [
                        'class' => appcomponentswebJsonResponseFormatter::class,
                        'prettyPrint' => YII_DEBUG
                    ]
                ]
            ],
    

    测试

    1.SiteController添加方法

        public function actionA($corporation_id)
        {
            $data = Yii::$app->request->post();
            var_dump($data, $corporation_id);
        }
    
        public function actionB()
        {
            return [
                'app_id' => 1,
                'app' => [
                    'app_id' => 2
                ]
            ];
        }
    

    2.请求测试,这个加密过的hash读者可能解不开,因为我们用的salt不一样,替换为你自己的即可

    
    POST /site/a?corporation_id=XaYeAV2q80pkB4KL
    
    {
      "corporation_id": "XaYeAV2q80pkB4KL",
      "applet":{
        "id":"XaYeAV2q80pkB4KL",
        "appid":"xxxxxx"
      }
    }
    

    3.响应的内容如下:

    
    array(2) {
      ["corporation_id"]=>
      int(1)
      ["applet"]=>
      array(2) {
        ["id"]=>
        int(1)
        ["appid"]=>
        string(6) "xxxxxx"
      }
    }
    int(1)
    

    4.响应测试

    
    GET /site/b
    

    5.响应内容如下

    
    
    {
        "app_id": "XaYeAV2q80pkB4KL",
        "app": {
            "app_id": "LOnMp3QR5lryDgRK"
        }
    }
    

    写在最后

    不知道这个算不算AOP编程?个人觉得算,在业务逻辑之外处理,业务层对外部输入和自身输出是透明的(理解为业务层自己不知道加解密)。

    本文核心在于两个递归方法,其他语言类似,像nodejs可以使用中间件来处理。

    原文地址:https://segmentfault.com/a/1190000015704969

  • 相关阅读:
    超详细的FreeRTOS移植全教程——基于srm32
    继续学习freertos消息队列
    FreeRTOS优化与错误排查方法
    从单片机到操作系统⑦——深入了解FreeRTOS的延时机制
    Android Pie 私人 DNS 使用教程
    「运维之美」技术周刊 ( 第 1 期 )
    「运维之美」技术周刊 ( 第 3 期 )
    用 Python 快速实现 HTTP 和 FTP 服务器
    关于ubuntu软件图标的问题
    You're currently running Fcitx with GUI 错误解决 Fcitx
  • 原文地址:https://www.cnblogs.com/lalalagq/p/9979798.html
Copyright © 2020-2023  润新知