Security Tip: Login Logging

[Tip#25] Try saying that fast 3 times...

Security Tip: Login Logging

Do you log login attempts in your app?

Both successes and failures?

Why not?

Unless your app has some very specific privacy requirements, you should be logging all login attempts. Both failures and successes should be recorded, alongside both the IP address and email/username used in the login attempt. (But don’t record the password!) Even if it goes into some log you never look at, and is rotated out in X days, it’s still better to have login attempts recorded somewhere.

Why? I hear you ask…

  1. In the worst case scenario that your app is hacked, you’ll want to review login logs to see if that’s how the attacker got in. You might notice a significant number of failed login attempts and one successful - that could indicate a credential stuffing attack on your site. Or maybe no logins were recorded - that could indicate a vulnerability that allowed the hacker access. When you’re tracking down a breach, you‘ll want this information.
  2. Maybe you’ve had some customers reporting weird activity in their accounts - you can check the logs to see if there are suspicious logins.
  3. If your site is under heavy load, lots of login attempts in the log could indicate an active brute-force attack.
  4. If a user is having trouble logging in (or at least reporting having trouble), you can check the logs to see what username they are attempting and go from there.
Logs are like backups: you hope you’ll never need them, but you’ll wish you had them if you don’t!

Laravel makes logging logins trivial through the authentication events:

Illuminate\Auth\Events\Registered
Illuminate\Auth\Events\Attempting
Illuminate\Auth\Events\Authenticated
Illuminate\Auth\Events\Login
Illuminate\Auth\Events\Failed
Illuminate\Auth\Events\Validated
Illuminate\Auth\Events\Verified
Illuminate\Auth\Events\Logout
Illuminate\Auth\Events\CurrentDeviceLogout
Illuminate\Auth\Events\OtherDeviceLogout
Illuminate\Auth\Events\Lockout
Illuminate\Auth\Events\PasswordReset

The ones you’ll want to reach for first are:

Illuminate\Auth\Events\Login
Illuminate\Auth\Events\Failed

I’d also suggest logging registrations and password resets, for the same reasons:

Illuminate\Auth\Events\Registered
Illuminate\Auth\Events\PasswordReset

You can register to listen to these events in your Event service provider like any other events, and simply check the class of the event to find out what parameters it includes.

For example, the Login event comes with:

/**
 * The authentication guard name.
 *
 * @var string
 */
public $guard;

/**
 * The authenticated user.
 *
 * @var \Illuminate\Contracts\Auth\Authenticatable
 */
public $user;

/**
 * Indicates if the user should be "remembered".
 *
 * @var bool
 */
public $remember;

And the Failed event:

/**
 * The authentication guard name.
 *
 * @var string
 */
public $guard;

/**
 * The user the attempter was trying to authenticate as.
 *
 * @var \Illuminate\Contracts\Auth\Authenticatable|null
 */
public $user;

/**
 * The credentials provided by the attempter.
 *
 * @var array
 */
public $credentials;

You should have no problems extracting the details you need to throw into the logs from there. 🙂

To give you an example of how I would log logins, this Gist is based off one of my projects: https://gist.github.com/valorin/b90dc36197f47323a9207093f6a6dfc5


🕵️
Want me to hack into your app and tell you how I did it, so you can fix it before someone else finds it? Book in a Laravel Security Audit and Penetration Test!
🥷
Looking to dive deeper into Laravel security? Check out Practical Laravel Security, my hands-on security course that uses interactive hacking challenges to teach you about how vulnerabilities work, so you can avoid them in your own code!