使用Hashids來保護你的資料庫主鍵
阿新 • • 發佈:2018-11-18
為什麼要保護資料庫主鍵?
資料庫主鍵一般是有序自增主鍵,極易被爬蟲抓取資料,作為應用開發者,這是不應該的,你辛辛苦苦收集的資料轉眼之間被其他人給抓取了,是不是很大的損失?
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 Hashids\Hashids('this is my salt');
$id = $hashids->encode(1, 2, 3);
$numbers = $hashids->decode($id);
注意
該庫並不是一個加密庫,所以不建議用來加密敏感資料,我們的資料庫主鍵ID並不是業務上的敏感資料,所以這個沒關係。
Yii2的使用
由於該編解碼是獨立與業務之外的,所以需要處理的地方在下面:
- 接收請求資料的自動解碼
- 響應資料的自動編碼(本文只針對JSON響應處理,有需要的可以新增ResponseFormatter自行處理)
這兩個步驟不應該提現在控制器中,控制器拿到的資料是解碼好的,響應的資料是原始資料,然後我們在響應中處理。
程式碼
助手類(HashidsHelper)
class HashidsHelper { public static function encode($id) { $hashids = new \Hashids\Hashids('salt',16); return $hashids->encode($id); } public static function decode($hash) { $hashids = new \Hashids\Hashids('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 \yii\web\JsonParser
{
/**
* @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' => \app\components\Request::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' => \app\components\web\JsonParser::class
]
],
處理響應資料
1.新建JsonResponseFormatter繼承Yii的JsonResponseFormatter,程式碼如下:
class JsonResponseFormatter extends \yii\web\JsonResponseFormatter
{
/**
* @inheritDoc
*/
public function format($response)
{
if ($response->data !== null) {
HashidsHelper::encodeRecursive($response->data);
}
parent::format($response);
}
}
2.配置web.php的components,替換response元件
'response' => [
'class' => \app\components\web\Response::class,
'format' => Response::FORMAT_JSON,
'formatters' => [
'json' => [
'class' => \app\components\web\JsonResponseFormatter::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