2020-07-13 18:16:00
围观(4754)
使用场景
先说一下什么是"虚位密码"
例如微信支付 / 支付宝支付 都有支付密码并且都是六位的长度.
输入密码的时候, 如果旁边的人盯着你输入密码, 密码就极其容易的泄露, 因为密码才六位非常容易记住.
此时虚位密码的作用就来了, 假设支付密码是 147258 , 开启虚位密码之后, 输入 265599465265265914725826526569556 也能验证密码正确, 原因就是这段密码中含有 147258, 而旁观者即使在旁边看了, 也不可能记得住你输入的密码了...
当然, 虚位密码防止了偷窥, 但是也存在一些安全隐患.
例如, 密码是六位的那么六位数字的排序方法无非就是 000000 到 999999, 假如恶意的从 000000 开始排序数字组合进行尝试验证密码, 到最后肯定会验证成功. 那么就需要加一个判断, 验证每次的密码长度及频繁请求, 例如每次密码长度不能大于 64 位, 一分钟最多输入 10 次.
使用 PHP 实现
说一下博主想到的实现原理, 假设如果是交易系统, 设置密码长度都是六位, 那么设置密码(用户注册)的时候将密码进行 哈希 / MD5 / 其他加密 后存入数据库, 验证密码(用户登录)的时候将用户输入的密码进行偏移获取六位, 然后对比数据库存的密码(密码经过了加密, 如果经过了 MD5 则需要将偏移获取到的密码也经过加密后才对比).
博主使用 Laravel 框架简单写写代码实现了一下. 为了简单实现, 不写前端代码, 直接写 API 接口, 然后使用 PostMan 进行请求测试.
首先在 .ENV 文件配置数据库, 例如博主这样的配置(具体要根据自己环境及数据库设置而定):
DB_CONNECTION=mysql DB_HOST=127.0.0.1 DB_PORT=3306 DB_DATABASE=xuwei DB_USERNAME=root DB_PASSWORD=root
在 API 的路由文件写下两个路由:
Route::post('register', 'Api\AuthController@register'); Route::post('login', 'Api\AuthController@login');
创建 users 表:
CREATE TABLE `users` ( `id` INT(11) NOT NULL AUTO_INCREMENT, `name` VARCHAR(50) NOT NULL DEFAULT '0' COLLATE 'utf8_unicode_ci', `password` VARCHAR(128) NOT NULL DEFAULT '0' COLLATE 'utf8_unicode_ci', `length` INT(11) NOT NULL DEFAULT '0', `created_at` TIMESTAMP NULL DEFAULT NULL, `updated_at` TIMESTAMP NULL DEFAULT NULL, PRIMARY KEY (`id`) USING BTREE ) COMMENT='用户' COLLATE='utf8_unicode_ci' ENGINE=InnoDB ;
使用命令创建模型:
php artisan make:model Model/User
如果使用 Laravel 自带的用户系统, 则可以直接使用 APP 目录下的 User , 博主是为了方便简单实现, 不使用 Laravel 自带的.
使用命令创建控制器:
php artisan make:controller Api/AuthController
在控制器里面写入两个方法:
public function register(Request $request) { $input = $request->all(); $validator = Validator::make($input, [ 'name' => 'required|unique:users|max:50', 'password' => 'required|min:6|max:128', ]); if ($validator->fails()) { return response()->json(['msg' => $validator->errors()->first()]); } $model_user = new User(); $model_user->name = $input['name']; $model_user->password = Hash::make($input['password']); $model_user->length = mb_strlen($input['password']); $model_user->save(); return response()->json(['msg' => 'success']); } public function login(Request $request) { $input = $request->all(); $validator = Validator::make($input, [ 'name' => 'required|max:50', 'password' => 'required|min:6|max:128', ]); if ($validator->fails()) { return response()->json(['msg' => $validator->errors()->first()]); } $model_user = new User(); // 博主为了偷懒(快速实现) 直接在这查询 正常应该是写入模型 为后面复用 $row_user = $model_user->where('name', $input['name'])->first(); $password_length = mb_strlen($input['password']); if (!$row_user || $password_length < $row_user['length']) { return response()->json(['msg' => 'account or password does not exist']); } if ($password_length == $row_user['length']) { if (!Hash::check($input['password'], $row_user['password'])) { return response()->json(['msg' => 'account or password does not exist']); } // 登录成功 继续操作 这里正常是返回 token 博主就不继续写了... // code... return response()->json(['msg' => 'login success']); } $offset = 0; $offset_times = $password_length - $row_user['length'] + 1; for ($i = 0; $i < $offset_times; $i++) { $password = mb_substr($input['password'], $offset, $row_user['length']); $offset++; if (Hash::check($password, $row_user['password'])) { // 登录成功 继续操作 这里正常是返回 token 博主就不继续写了... // code... return response()->json(['msg' => 'login success']); } } return response()->json(['msg' => 'account or password does not exist']); }
别忘了需要引入:
use Illuminate\Support\Facades\Validator; use Illuminate\Support\Facades\Hash; use App\Model\User; // 这个应该不用多说了
接下来测试下注册:
注册是成功的, 这里说一下, 注册方法里面计算了一下密码长度, 这是为了登录(验证密码)的时候可以偏移组合密码, 不然不知道密码真实的长度就没办法做虚位了, 除非定死每个人的密码只能设置为 XX 位.
测试正常登录:
测试虚位密码登录:
为了验证是否正确验证(将虚位密码中的 147258 去掉):
至此, 虚位密码已经成功实现.
博主限制的长度是 128 位, 其实可以减少到 64 位, 另外博主的实现方法没限制请求频率, 如果使用 Laravel 可以通过中间件实现限制.
本文地址 : bubaijun.com/page.php?id=196
版权声明 : 未经允许禁止转载!
上一篇文章: 使用 Mysql 存储过程生成5万条数据记录
下一篇文章: Laravel自定义错误及全局事务