jove's avatar
Level 7

Hashed user password in error log, can it be removed?

So I tried to register a user, failed since it didn't have access to the .sqlite file (woops) But it then posted the failed sql query which does include the hashed password for the user, I don't really like passwords in the logs.

Is there a way to filter this out in Laravel natively?

0 likes
3 replies
devfrey's avatar

I don't know of a built-in way to do this.

Edit: code below doesn't work

----------------------------------

I haven't fully worked this out, but here's an idea:

  1. Modify your exception handler's report() method.
  2. Catch instances of \Illuminate\Database\QueryException and wrap it in a custom exception class.
  3. This custom exception (perhaps call it RedactedQueryException) class should extend the QueryException.
  4. In your custom exception's constructor, do something like this:
public function __construct(QueryException $exception)
{
    parent::__construct($exception->getSql(), $exception->getBindings(), $exception->getPrevious());

    if (isset($bindings['password'])) {
        $bindings = array_replace($bindings, ['password' => '******']);
    }
    
    // Update the exception message with the redacted bindings
    $this->message = $this->formatMessage($exception->getSql(), $bindings, $exception->getPrevious());
}

Let me know if it worked.

1 like
jove's avatar
Level 7

@DEVFREY - O I like this idea, I won't be able to integrate it right now but I will keep this in mind when I do.

devfrey's avatar

I checked the source code and my implementation will not work. For some reason the $bindings property doesn't contain a field-value array. It only contains the bound values :/

I came up with a solution that utilises the reflection API to modify the thrown exception (so it retains the correct line references and such). It redacts all bindings, and not a specific password binding. There's no easy way to identify the bindings.

public function report(\Exception $exception)
{
    if ($exception instanceof QueryException) {
        $redactedBindings = array_map(function ($value) {
            return str_repeat('*', max(3, strlen($value)));
        }, $exception->getBindings());

        $class = new \ReflectionClass($exception);

        $reflectionMethod = $class->getMethod('formatMessage'));
        $reflectionMethod->setAccessible(true);
        $redactedMessage = $reflectionMethod->invoke(
            $exception,
            $exception->getSql(),
            $redactedBindings,
            $exception->getPrevious()
        );

        $reflectionProperty = $class->getProperty('message');
        $reflectionProperty->setAccessible(true);
        $reflectionProperty->setValue($exception, $redactedMessage);
    }

    parent::report($exception);
}
1 like

Please or to participate in this conversation.