当前位置: 首页 > 后端技术 > PHP

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

时间:2023-03-30 05:04:26 PHP

为什么要保护数据库主键?数据库主键一般是有序的自增主键,非常容易被爬虫爬取。作为应用程序开发人员,不应这样做。你辛辛苦苦收集的数据,转眼就被别人抓走了。这是一个很大的损失吗?Hashidsgenerateshortuniqueidsfromintegers的引入可以理解为数字编码库,支持市面上几乎所有的语言。可用于JavaScript、Ruby、Python、Java、Scala、PHP、Perl、Perl6、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和forPHP使用$hashids=newHashids\Hashids('这是我的盐');$id=$hashids->编码(1,2,3);$numbers=$hashids->解码($id);注意这个库不是加密库,所以不建议加密敏感数据,我们数据库的主键ID在业务中不是敏感数据,所以无所谓。Yii2的使用与业务无关因为编解码与业务无关,所以需要处理的地方如下:接收到的请求数据自动解码响应数据自动编码(本文只针对JSONresponse的处理,如果有需要,可以自己添加ResponseFormatter来处理)这两个步骤在controller中应该不会提到。controller得到的数据经过解码,response数据就是原始数据,然后我们在response中进行处理。代码助手类(HashidsHelper)classHashidsHelper{publicstaticfunctionencode($id){$hashids=new\Hashids\Hashids('salt',16);返回$hashids->encode($id);}publicstaticfunctiondecode($hash){$hashids=new\Hashids\Hashids('salt',16);$data=$hashids->decode($hash);返回空($data)?null:$data;}publicstaticfunctiondecodeArray(array$hashes){returnarray_map([HashidsHelper::class,'decode'],$hashes);}/***递归编码*@paramarray$data*/publicstaticfunctionencodeRecursive(array&$data){foreach($dataas$key=>&$value){if(is_array($value)){self::编码递归($值);继续;}if(strpos($key,'id')!==false&&is_numeric($value)){$data[$key]=static::encode($value);}}}/***发送归解码*@param数组$data*/publicstaticfunctiondecodeRecursive(array&$data){foreach($dataas$key=>&$value){if(is_array($value)){self::decodeRecursive($value);继续;}if(strpos($key,'id')!==false){if(is_string($value)){$id=static::decode($value);$data[$key]=$id??$值;}elseif(is_array($value)){$data[$key]=static::decodeArray($value);}}}}}处理请求数据($_POST,$_PUT,$_GET)提交的Data1.新建JsonParser继承Yii自带的JsonParser,代码如下classJsonParserextends\yii\web\JsonParser{/***@inheritDoc*/publicfunctionparse($rawBody,$contentType){$data=parent::parse($rawBody,$contentType);如果($data!==null){HashidsHelper::decodeRecursive($data);}返回$数据;}}2。新建一个Request整合Yii自带的Request,重写getQueryParams,代码如下:publicfunctiongetQueryParams(){$data=parent::getQueryParams();如果($data!==null){HashidsHelper::decodeRecursive($data);}返回$数据;}3。配置web.php的组件,改成我们自定义的processor'request'=>['class'=>\app\components\Request::class,//!!!在下面插入一个密钥(如果它是空的)——这是cookie验证所必需的'cookieValidationKey'=>'123456','enableCsrfValidation'=>false,'parsers'=>['application/json'=>\app\components\web\JsonParser::class]],处理响应数据1.新建JsonResponseFormatter继承Yii的JsonResponseFormatter,代码如下:classJsonResponseFormatterextends\yii\web\JsonResponseFormatter{/***@inheritDoc*/publicfunction格式($response){如果($response->data!==null){HashidsHelper::encodeRecursive($response->data);}父母::格式($响应);}}2。配置web.php的组件,替换响应组件'response'=>['class'=>\app\components\web\Response::class,'format'=>Response::FORMAT_JSON,'formatters'=>['json'=>['class'=>\app\components\web\JsonResponseFormatter::class,'prettyPrint'=>YII_DEBUG]]],测试1.SiteController添加方法publicfunctionactionA($corporation_id){$data=Yii::$app->request->post();var_dump($data,$corporation_id);}publicfunctionactionB(){return['app_id'=>1,'app'=>['app_id'=>2]];}2.请求测试,这个加密的hashreader可能无法解决,因为我们使用的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/b5.响应内容如下{"app_id":"XaYeAV2q80pkB4KL","app":{"app_id":"LOnMp3QR5lryDgRK"}}最后不知道这是不是AOP编程业务层对外部输入和自己的输出是透明的(理解为业务层本身并不知道加密和解密),本文的核心在于两种递归的方法,和其他语言类似,比如nodejs,可以由中间件处理。