Securing Laravel

Share this post

Security Tip: Compare keys with hash_equals()

securinglaravel.com

Discover more from Securing Laravel

The essential security resource for Laravel devs, covering everything you need to keep your apps secure. Sign up to receive weekly security tips and monthly in depth articles, diving deep into security concepts you need to know!
Over 2,000 subscribers
Continue reading
Sign in

Security Tip: Compare keys with hash_equals()

[Tip#56] It may be tempting to compare keys/sensitive strings using `===`, or even `==`, but that opens you up to timing attacks! You should be using a timing attack safe string comparison function...

Stephen Rees-Carter
Sep 17, 2023
4
Share this post

Security Tip: Compare keys with hash_equals()

securinglaravel.com
3
Share

Greetings friends! I hope you enjoyed last week’s 2 years of Securing Laravel recap - it was great to take a look at how much we’ve covered in the past 12 months. This week I want to remind you about one of PHP’s security helper functions, which you should be using within your apps to protect against timing attacks. I’ve mentioned it a couple of times before

1
, but we haven’t specifically featured it yet, .

Before we get started with the Security Tip, I just wanted to mention that for personal reasons I’ll be reducing my hours next year for my Laravel Security Audits and Penetration Tests. Please reach out if you’re thinking about an audit, so I can reserve you time in my schedule

2
. 🕵️


Securing Laravel is 100% reader-supported. Please consider becoming a free or paid subscribe to receive new posts and support my security work in the Laravel community!


Compare keys with hash_equals()

It may be tempting to compare keys, or other sensitive strings, using the strict comparison `===` (or even the loose comparison `==`) however this opens up to timing attacks, which can be used to identify the keys you’re comparing.

But first, what I mean by “keys” or “sensitive strings”?

These are string values that the user does not know but needs to provide in order to do or access something. Common examples are API keys, passwords, tokens, secret phrases, answers, etc… Some apps will use these a lot, while others might not ever need them.

Consider this code:

// api.secret_token => 'V1cHt2S67DADJIm9sX9yzCc272EkSC'

if ($request->token === config('api.secret_token')) {
    // Do something...
}

In this example, the user needs to provide a valid token before they are allowed to do something. However, since the strict comparison in use (`===`) is not timing attack safe, an attacker can eventually figure out the value by providing specific values of `$request->token` and measuring the timing of the response

3
.

The solution is simple, all you need to do is to use `hash_equals()` to compare the two strings! This ensures the comparison always takes exactly the same amount of time regardless of the inputted string

4
, preventing an attacker from figuring out the secret key:

// api.secret_token => 'V1cHt2S67DADJIm9sX9yzCc272EkSC'

if (hash_equals(config('api.secret_token'), $request->token)) {
    // Do something...
}

Since it’s a simple function that replaces your strict (or loose) comparison, it’s trivial to implement, so there really is no reason not to use it. 🙂

You can learn more about `hash_equals()` in the PHP docs: https://www.php.net/manual/en/function.hash-equals.php.

If you want to learn more about timing attacks, go check out In Depth #6: Timing Attacks, where we covered them in detail, including a section about string comparisons which directly relates to this issue. You should check out Anthony Ferrara’s “It’s All About Time” article to dive deeper into timing attacks.


Looking to learn more?
⏩ Security Tip #37: New Password Generator
▶️ In Depth #13: Stealing Password Tokens with Forwarded Host Poisoning

1

We talked about it in: In Depth #9: Signed URLs, In Depth #10: Magic Emails, and In Depth #6: Timing Attacks.

2

I will be booking in past clients first, and then I would love to give Securing Laravel subscribers second preference before opening up to new clients.

3

It may take a lot of requests, and a simple rate limiter can make this significantly harder, but it’s still a very real problem that you need to take seriously.

4

Ok, it’s only “exactly the same” when both values are the same length. However, figuring out the length isn’t overly helpful if you can’t also figure out what it contains.

4
Share this post

Security Tip: Compare keys with hash_equals()

securinglaravel.com
3
Share
Previous
Next
3 Comments
Share this discussion

Security Tip: Compare keys with hash_equals()

securinglaravel.com
Paul Knisely
Sep 17Liked by Stephen Rees-Carter

So would it be wise to just replace all string comparisons with hash_equals() ? Or should it just be used with secret keys.

Expand full comment
Reply
Share
2 replies by Stephen Rees-Carter and others
2 more comments...
Top
New
Community

No posts

Ready for more?

© 2023 Stephen Rees-Carter
Privacy ∙ Terms ∙ Collection notice
Start WritingGet the app
Substack is the home for great writing