1
votes

I'm using Laravel 4.2.

I'm creating a registration form where the user fills in their name and email address which upon successful validation then gets stored in a DB as encrypted values using Crypt::encrypt() for the email field and Hash::make() for the password field.

My issue is with generating a validation rule for the email filter which needs to be unique for each user that signs up.

With Crypt::encrypt() and Hash::make() generating random strings every time for the same input string, I can't seem to match the input value with the value in the database even though they may be the same?

What is the best practice for validating an email address (or another field) as being unique when they have to be encrypted in the database at all times?

Also, how would I amend my Auth::attempt() feature to accommodate the fact that the email field is encrypted?

2
Why are you hashing the email? - Bowersbros
Because in the context of the project, it's considered sensitive data. - Sinmok
@Sinmok How did u solve this issue? - Saumini Navaratnam

2 Answers

0
votes

I assume that you encrypted the email address with Crypt::encrypt(), and because the method generates a different IV every time, the result is non comparable.

Whenever you need a searchable/comparable field you cannot use an IV (encryption) or a salt (hashing). One way to solve this problem is to calculate a HMAC with the email and a server side key as input, but without a salt. This hash you can store side by side with the encrypted email.

If an attacker knows the server side key, he will be able to brute-force the email hash, but then he probably knows the encryption key as well and can decrypt the email directly. Please note that this would not apply to passwords, because they should be stored unretrievable.

0
votes

Laravel has Custom Validation Rules (https://laravel.com/docs/8.x/validation#using-rule-objects) For example I have a table named clients who has two unique fields ecnrypt using Laravel's encryption services (https://laravel.com/docs/8.x/encryption) and because its encrypted, i can't aply the unique directive of validation method (https://laravel.com/docs/8.x/validation#rule-unique). The fields are code_client and email

That's the reason of implements a Custom Validation Rules. this Service has two methods: passes and message. The method passes take two variables: $attributes (take de field to validate) and $value (take de value of field), and return true or false. Te method message retrieve message in case of failure.

In clients example i mentioned, folow the next steps:

  1. php artisan make:rule ValidateFieldsClients

  2. in class that composer creates ValidateFieldsClients, I have to declare a method for validate the fields in passes, I use this method for validate both fields (code_client and email).

  3. next i complete de method message to retrieve the issue to user in views

  4. additionally i declare a property $field to identify what´s the field it have the errors

  5. The class ValidateFieldsClients example:

         /***/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. Then to validate I use Form Request Validation (https://laravel.com/docs/8.x/validation#form-request-validation)

  7. php artisan make:request ClientRequest

  8. And in the validate method of the recently created class:

    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. Finally in controller:

     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!');
        }