对散列/加密值进行Laravel唯一验证



我使用的是Laravel 4.2。

我正在创建一个注册表,用户在其中填写他们的姓名和电子邮件地址,成功验证后,这些地址将作为加密值存储在数据库中,其中Crypt::encrypt()用于电子邮件字段,Hash::make()用于密码字段。

我的问题是为电子邮件过滤器生成一个验证规则,该规则需要对每个注册的用户都是唯一的。

由于Crypt::encrypt()Hash::make()每次都为同一个输入字符串生成随机字符串,即使它们可能相同,我似乎也无法将输入值与数据库中的值匹配?

当电子邮件地址(或其他字段)必须始终在数据库中加密时,验证其唯一性的最佳做法是什么?

此外,我将如何修改我的Auth::attempt()功能以适应电子邮件字段已加密的事实?

Laravel有自定义验证规则(https://laravel.com/docs/8.x/validation#using-规则对象)例如,我有一个名为client的表,它有两个使用Laravel加密服务的唯一字段ecnrypt(https://laravel.com/docs/8.x/encryption)由于它是加密的,我无法使用验证方法的唯一指令(https://laravel.com/docs/8.x/validation#rule-唯一)。字段为code_client电子邮件

这就是实现自定义验证规则的原因。此服务有两种方法:传递消息。方法传递获取两个变量:$attributes(获取字段的值进行验证)和$value(获取字段值),并返回true或false。Te方法消息在失败的情况下检索消息。

在我提到的客户端示例中,遵循以下步骤:

  1. php artisan make:rule ValidateFieldsClients

  2. 在composer创建ValidateFieldsClients的类中,我必须声明一个方法来验证pass中的字段,我使用这个方法来验证这两个字段(code_client电子邮件)。

  3. 接下来,我在视图中完成反方法消息,以向用户检索问题

  4. 另外,我声明了一个属性$field,以确定它有错误的字段

  5. ValidateFieldsClients类示例:

         /***/class ValidateFieldsClients implements Rule{protected $field; /**
         * Create a new rule instance.
         *
         * @return void
         */
        public function __construct()
        {                
        }
        /**
         * Determine if the validation rule passes.
         *
         * @param  string  $attribute
         * @param  mixed  $value
         * @return bool
         */
        public function passes($attribute, $value)
        {
            $clients = client::all();   
            $this->field = $attribute;
            foreach ($clients as $client ) {
                if ($value == Crypt::decryptString($client->$attribute)) return false;            
            } 
            return true;
        }
        /**
         * Get the validation error message.
         *
         * @return string
         */
        public function message()
        {
            return strtoupper($this->field).' exists, check.';
        }
    }
    
  6. 然后为了验证,我使用表单请求验证(https://laravel.com/docs/8.x/validation#form-请求验证)

  7. php artisan make:request ClientRequest

  8. 在最近创建的类的验证方法中:

    class ClientRequest extends FormRequest
    {   /**
         * Determine if the user is authorized to make this request.
         *
         * @return bool
         */
        public function authorize()
        {
            return true;  } 
    
    /**
     * Get the validation rules that apply to the request.
     *
     * @return array
     */
    public function rules()
    {
        return [ 
            'code_client'=> ['required', new ValidateFieldsClients],                
            'email'=>['required', new ValidateFieldsClients],
        ];
    }
    
  9. 最后在控制器中:

     public function store(ClientRequest $request)
            { $clientRequest = $request->validated();
                foreach ($clientRequest as $key => $client) {
                    $encryptedClient[$key] = Crypt::encryptString($client);
                };      client::create($encryptedClient+ [
                'idorga' => 1,
                'idcrea' => 1,
                'idmodifica' => 1
            ]);
            return redirect('clientes/create')->with('success', 'Registro creado correctamente');
            //return redirect('cuadros')->with('success', 'Registro exitoso!');
        }
    

我假设您使用Crypt::encrypt()加密了电子邮件地址,并且由于该方法每次都会生成不同的IV,因此结果是不可比较的。

当你需要一个可搜索/可比较的字段时,你不能使用IV(加密)或salt(哈希)。解决这个问题的一种方法是使用电子邮件和服务器端密钥作为输入,但不使用salt来计算HMAC。您可以将此哈希与加密电子邮件并排存储。

如果攻击者知道服务器端的密钥,他将能够强行使用电子邮件哈希,但随后他可能也知道加密密钥,并可以直接解密电子邮件。请注意,这不适用于密码,因为它们应该存储为不可检索的。

最新更新