dev-idkwhoami's avatar

Accessing cast-encrypted model property ?

Hey everyone,

I got a bit of a confusing situation here. I have a password that is stored in the database and automatically encrypted through the casts() method.

protected function casts(): array
    {
        return [
            'password' => 'encrypted',
        ];
    }

This works like i expect it to. Now i use this password in a service where it is used in an API Request for Basic Auth there i access it like this:

$response = Http::acceptJson()
            ->withoutVerifying()
            ->withQueryParameters($parameters)
            ->withHeaders($this->basicAuthHeader($credentials->username, $credentials->password))
            ->get("$this->base_url/do");

This seems to work as $credentials->password is automatically decrypted when i access it.

Now my problem is that this behavior is inconsistent. I allow the user to update that password through a Livewire Form but for some unknown reason when i access the value there it stays encrypted.

class CredentialsForm extends Form
{

    public ?Credentials $credentials;

    #[Validate('required|min:3')]
    public $username;
    #[Validate('required|min:3')]
    public $password;

    public function setCredentials(Credentials $credentials): void
    {
        $this->credentials = $credentials;
        $this->username = $this->credentials->username;
        $this->password = $this->credentials->password;
    }

}

Now i assume laravel-magic somehow knows this is "possibly dangerous" so it doesn't decrypt the value but how can i control what it does. I didn't find anything in the docs for this.

So maybe somebody else can explain this to me. Why it is not decrypting the value in the Livewire form but in my service class ?

Thanks in advance ^^

0 likes
4 replies
Nakov's avatar

You should never display the plain password to the user. Even on a registration form, you should never use old('password') to display what they entered before.

Here is a good tutorial on this topic: https://www.honeybadger.io/blog/an-introduction-to-hashing-and-encryption-in-laravel/

Comparing hashed values to plain text

As previously mentioned, it's not possible to reverse a hashed value. Therefore, if we want to determine the hashed value, we can only do so by verifying the hashed value against a plain-text value. This is where the Hash::check() method comes into play.

dev-idkwhoami's avatar

@Nakov I thank you for the attempt of making sure my site is secure. But this is not a security issue in this case which is also why i didn't ask how to make it more secure. The credentials are for an external API not connected to the app the password NEEDS to be in plain-text so it can be used to authenticate with that API.

In the meantime i found out why this inconsistency occurs, i seeded the database with a pre-encrypted string for the password. Which seems to confuse the encrypt cast somehow. Only thing coming to mind is the cast somehow "tracking" if it handled a string previously.

JussiMannisto's avatar
Level 50

@dev-idkwhoami

i seeded the database with a pre-encrypted string for the password. Which seems to confuse the encrypt cast somehow.

Where's the confusion? You pass in a string, which then gets encrypted. Either encrypt the string yourself or use casting. If you do both, of course it gets double-encrypted.

1 like
dev-idkwhoami's avatar

So to finish this topic here the solution:

Do not seed your database with pre-encrypted data, just set the property on your model like normally to the un-encrypted value and the cast will encrypt it for you. Then the decryption will also be reliable.

Please or to participate in this conversation.