paulodiff / rainbow-table-index
Laravel 数据库数据加密与全文搜索
Requires
- php: ^7.4|^8.0
- illuminate/support: ^8.0
Requires (Dev)
- orchestra/testbench: ^6.0
- phpunit/phpunit: ^9.0
This package is auto-updated.
Last update: 2024-09-18 23:26:37 UTC
README
🚨 不要在生产环境中使用! 🚨
免责声明
- 此库是一个概念验证。
待办事项
- 前缀表
- 配置默认加密
- 安全定制
- 测试关系
- 统计
简介
数据库数据加密是必不可少的,使用 Laravel Eloquent ORM 转换在数据库中加密数据非常简单。
<?php namespace App\Models; use Illuminate\Database\Eloquent\Model; class Post extends Model { protected $casts = [ 'title' => 'encrypted', ]; }
有了加密数据字段,您只能通过精确的字段名值进行搜索。
$p = Post::where('title','Beautiful Post'); // OK
但是不能使用 LIKE 操作符
$p = Post::where('title','LIKE','%Bea%'); // WRONG!
因为真实数据以加密形式存储在数据库表中
"id";"title" "1";"7OioIr/njEtH0fFHDoVopndh2z/yfQ4r8i40QlZjaITQ7Mh5QwnhH/Gjug=="
Laravel 包含 Eloquent,一个对象关系映射器 (ORM)。通过扩展 Eloquent 类并使用 Laravel Traits,可以构建一个库,允许您使用“彩虹表索引”对加密文本进行全文搜索。
想法...
目标:在加密数据中使用 LIKE 操作符进行搜索。通过库构建一个替代索引(彩虹表索引),可以索引加密值并查询这些值。
这是一个工作示例,有一个包含字段 "id" 和 "title" 的 Post 模型。我们创建一个 Post 项目
Post::create(['id'=> 88, 'title' => 'Beauty']);
生成的 RainbowTableIndex(最小标记大小为 3)
Rainbow Table Index data post:title BEA 88 post:title EAU 88 post:title AUT 88 post:title UTY 88 post:title BEAU 88 post:title EAUT 88 post:title AUTY 88 post:title BEAUTY 88
对加密字段进行 LIKE 搜索
$p = Post::where('title','LIKE','%BEA%');
首先自动转换为对彩虹表索引的搜索,然后是标记 'BEA' 的 id,查询变为
$p = Post::whereIn('id', [88]);
彩虹表索引 - 详情
“彩虹表索引”是一个由 RainbowTableService 构建的索引。Eloquent 模型是一个与数据库交互的对象。这是一个示例
<?php namespace App\Models; use Illuminate\Database\Eloquent\Model; use Paulodiff\RainbowTableIndex\RainbowTableIndexTrait; class Author extends Model { use RainbowTableIndexTrait; protected $fillable = [ 'name' ]; // Rainbow table configuration public static $rainbowTableIndexConfig = [ 'table' => [ 'primaryKey' => 'id', 'tableName' => 'authors', ], 'fields' => [ [ 'fName' => 'name', 'fType' => 'ENCRYPTED_FULL_TEXT', 'fSafeChars' => " 'àèéìòùqwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM.", 'fTransform' => 'UPPER_CASE', 'fMinTokenLen' => 3, ] ] ]; }
此模型定义了一个具有一个加密字段 'name' 的 Author。彩虹表索引配置
- primaryKey:表的键
- tableName:数据库表名
对于每个要加密和用彩虹表索引索引的字段,您定义以下内容
- fName:字段名
- fType:ENCRYTPED_FULL_TEXT(其他类型即将推出)
- fSafeChars:用于清理字段值的字符数组
- fTransform:UPPER_CASE|LOWER_CASE|NONE 应用字段转换
- fMinTokenLen:在标记生成中使用的最小标记大小。如果 = 0,则标记器返回完整数据。
当创建 Eloquent 模型时,会在数据库表中插入一行,并加密配置的所有字段。然后创建所有条目在 RainbowTableIndex。
Author::create(['id'=> 1, 'name' => 'Billy White']);
显示数据库作者数据
id;name; 1ZXlKcGRpSTZJa1JEUTB4cWNuTmxTRzFOSzFZMVowNUxiazVITjFFOVBTSXNJblpoYkhWbElqb2lUMFp2V1hwRVlsSkVWSFZ3TDBGNldURklXRzVuVEZnMk16QXhVQ3RpY1dWUVowMTJha1V5WkdOeFNUMGlMQ0p0WVdNaU9pSm1NbUpqWTJSaE5HSTNORFUxTlRjME16ZGlOalEyWVRjd05tRXdORFF4T1RCbU9EZGtaREl6TlRsallqa3laR0UwTTJJelkyVTFaV1kyWWpFd00yUXpJaXdpZEdGbklqb2lJbjA9;
显示与字段 'name' 相关的彩虹表索引数据。
table name: rt_6f48819d50e9b840e0c9a5e4a1375145 table data: rt_key;rt_value 7327b0fa163b48eb9dca10700a55d717406e25f24da3223d78257bb55cbd5e77;1 3da30095b68d8df0348b86660aa9f8c33617b2f9bbecae4ef342bd708fcbf1fc;1 89aa7c63a9087d2f4da32e49d5949024d9c9a41cde32bb0c80ea3edc28c9384b;1 979d88c360ae25de60c5afdf97e48760e1dbff047c595431272d3c69c0056484;1 91024262f3055431a4aca784cca25fde500a3e6a498e12717d498667c322fec3;1 bf64a77aef0838485fff59fde2c889bea48c451ad7c157f005d5b93bf686ddb1;1 3d5834be7f15366d5a5d9c823d3e39713f932b6378f210cf3e842417bd20f81f;1 334dea03de177f5f22bfd8a571f4f1c696be6d08fa135a161680a3b0dfa1302c;1 4b0cdc4e3d3c57e606bdd14b4c69b4eb0d6535947290429fa135231b150b1173;1 0f91f40beba2d9e7400653124342097b17a05d62ddbc4fe8b4205d0a256344e2;1 b5da40127d66e01bc324557fa056c3ed89b7c44b832399c2373df3dc7ea60b29;1 fad5fc5354ddbd9adaccd041f96e7aa4c8a460d4acd94c0eb099ef637c6fb6df;1 f0647065844b606d53db1adef3d540404cc00e9ab040d14c422f6f4b9f5e4979;1 a5fd15ffb7150fb7dec15b758f3a118d724b11c67a4483ac2ec6d8b631d0320b;1 ...
当需要在 RainbowTableIndex 中插入数据时,会应用转换
- 仅“安全字符”有效 - fSafeChars
- 可选:CASE 转换 - fTransform
- 标记大小生成 - fMinTokenLen
示例
地址数据:"77712 O'Conner Plain Apt. 996 nw"
- 安全字符过滤器:"O'Conner Plain Apt. nw"
- 大小写转换:"O'CONNER PLAIN APT. NW"
- 标记化"[O'C]['CO]ONNER PLAIN APT. NW".... TODO (NW 跳过!)
如果模型被更新或删除,彩虹表索引也会更新。
RainbowTableIndex 特性
- 当创建/更新 Eloquent 模型(数据库项)时,自动创建/更新彩虹表索引
- 所有值都是哈希数据
- 索引表名是加密的
- 每个 Eloquent 模型数据库表都包含所有彩虹表索引数据
用例
该库可用于需要保证敏感数据隐私,并需要执行LIKE等搜索的场景。
- 姓名或姓氏
- 地址
- 信用卡号码
安装
要求
- Laravel 8
- Mysql
- Redis(即将推出)
设置
创建Laravel应用程序
composer create-project laravel/laravel rainbow-table-index-app cd rainbow-table-index-app composer require paulodiff/rainbow-table-index php artisan vendor:publish --provider="Paulodiff\RainbowTableIndex\RainbowTableIndexServiceProvider" --tag="config"
检查.env文件中的Laravel Mysql配置
运行检查配置
php artisan RainbowTableIndex:checkConfig
配置选项
- .env配置
启用调试信息 DEBUG_LEVEL = debug
- config/rainbowtableindexconfig.php
为不加密调试RainbowIndexTable使用以下选项:RAINBOW_TABLE_INDEX_ENCRYPT=true
一切正常!您可以开始了!
创建一个工作演示
警告!此过程将在数据库中创建表
- 作者
并为测试填充这些表1000行数据。
复制模型
在app/models中,从...复制Author.php和Posts.php
运行dbseed
运行dbStats
创建模型Author
composer create-project laravel/laravel rainbow-table-index-app
cd rainbow-table-index-app
composer require paulodiff/rainbow-table-index
php artisan RainbowTableIndex:keyGenerator
.env
RAINBOW_TABLE_INDEX_ENCRYPT=true
RAINBOW_TABLE_INDEX_PREFIX=rti // TODO
php artisan RainbowTableIndex:checkConfig
配置并运行演示和测试
创建迁移
php artisan make:migration create_authors_table
编辑迁移文件
public function up() { Schema::create('authors', function (Blueprint $table) { $table->increments('id'); $table->text('name'); $table->text('name_enc'); // for test only $table->text('card_number'); $table->text('card_number_enc'); // for test only $table->text('address'); $table->text('address_enc'); // for test only $table->text('role'); $table->text('role_enc'); // for test only $table->timestamps(); }); } public function down() { Schema::dropIfExists('authors'); }
迁移数据库
php artisan migrate
创建Author模型
编辑App/Models/Author.php
<?php namespace App\Models; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; use Paulodiff\RainbowTableIndex\RainbowTableIndexTrait; class Author extends Model { use HasFactory; use RainbowTableIndexTrait; public static $rainbowTableIndexConfig = [ 'table' => [ 'primaryKey' => 'id', 'tableName' => 'authors', ], 'fields' => [ [ 'fName' => 'name_enc', 'fType' => 'ENCRYPTED_FULL_TEXT', 'fSafeChars' => " 'àèéìòùqwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM.", 'fTransform' => 'UPPER_CASE', 'fMinTokenLen' => 3, ], [ 'fName' => 'address_enc', 'fType' => 'ENCRYPTED_FULL_TEXT', 'fSafeChars' => " 'àèéìòùqwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM.", 'fTransform' => 'UPPER_CASE', 'fMinTokenLen' => 4, ], [ 'fName' => 'card_number_enc', 'fType' => 'ENCRYPTED_FULL_TEXT', 'fSafeChars' => '1234567890', 'fTransform' => 'NONE', 'fMinTokenLen' => 4, ], [ 'fName' => 'role_enc', 'fType' => 'ENCRYPTED', 'fSafeChars' => ' àèéìòùqwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM.', 'fTransform' => 'ENCRYPTED_FULL_TEXT', 'fMinTokenLen' => 0, ], ] ]; }
运行db seed(100行)
php artisan RainbowTableIndex:dbSeed 100
运行搜索测试和指标(100)
php artisan RainbowTableIndex:dbCrud 100
停止!Rainbow索引已配置并运行,您可以使用Web应用程序进行测试!
这是一个包含5个表的Web应用程序CRUD演示。
Player
'player_id'
'player_name', // ENCRYPTED
'player_address',
'player_credit_card_no', // ENCRYPTED
'player_phone',
PlayerRole
'player_role_id'
'player_role_description', // ENCRYPTED
'player_role_salary',
Team
'team_id', // ENCRYPTED
'team_name',
'team_type_id', (1-1 with TeamType)
TeamType
'team_type_id'
'team_type_description', // ENCRYPTED
'team_type_rules',
Roster
'roster_id'
'roster_description', // ENCRYPTED
'roster_player_id',
'roster_team_id',
'roster_player_role_id',
'roster_amount', // ENCRYPTED
Livewire安装 composer require livewire/livewire
设置Mysql Set .env 复制模型并重命名每个模型的路径 复制资源 复制web.app
php artisan RainbowTableIndex:dbCrud 100 php artisan optmize php artisan serve
composer require livewire/livewire
php artisan make:livewire posts
app/Http/Livewire/Authors.php
resources/views/livewire/authors.blade.php
# Security customization
- Laravel Encrypt/Decrypt functions
- Hash
# Service operation
You can rebuild all indexed data for an intaciated model:
```php
$a = Author::where('id', 3)->first();
$r1 = $a->rebuildRainbowIndex();
或者您可以重建模型的所有实例的所有索引
$r2 = Author::rebuildFullRainbowIndex();
统计/性能和维度
性能系统特性
- I3 / 16gb
- Windows 10 / XAMPP
- 1000个作者
- 4000篇帖子
实例的访问时间不同。我的测试
- 1000实例
- 索引维度
- 访问时间。 ù [2022-01-07 12:25:55] testing.INFO: CRUD:TOTAL TIMING: [["name_enc-2613#2613-time (enc,flat) : . [16.161010447761,2.5544727133563]","address_enc-1408#1408-time (enc,flat) : . [10.007975923295,2.5428640625]","card_number_enc-9100#9100-time (enc,flat) : . [43.496440604396,2.1048867032967]","role_enc-5#5-time (enc,flat) : . [5.10922,5.35346]"]]
可以计算要索引的每个数据行的索引数量($w是标记长度,$s是要分词的字符串)
for ($w=3;$w<= strlen($s); $w++) $numOfEntries += (strlen($s) + 1 - $w);
自定义
sanitize_string
最终考虑
- 优点 -- 加密!加密!!加密!!!
缺点
- 对加密数据的OrderBy不起作用! -> 使用集合排序!
- 其他SQL函数(SUM,MIN等)不起作用
- 搜索开销
