Security Tip: Timebox for Timing Attacks
[Tip#38] Let's take a look at another recent addition to Laravel's security features
Greetings my friends! If you haven’t seen it yet, don’t forget to check out last week’s Security Tip on the New Password Generator in Laravel. Keeping in the spirit of looking at new features, we’ve got one that was added back in September 2022 by Jens Just Iversen from Ephort: the Timebox class to defeat timing attacks.
Also, as a bit of a teaser, the next In Depth1 will be covering a recent security fix PR I submitted to Laravel with some security fixes, that has since been rolled back. I want to talk about my fixes, why I felt they were important, and why we decided to roll them back2. It’s going to be a really interesting one, so look out for it!
👉 Security Audits: Want me to hack your app and help you improve your security? 🕵️
Looking to learn more?
⏩ Security Tip #22: Validating HTML & Markdown Input
▶️ In Depth #8: Policy Objects
Timebox for Timing Attacks
We’ve talked about timing attacks before, back in In Depth #6 and Security Tip #27, and previously there hasn’t been a good default solution to defending against them in Laravel. I’ve even said that it’s a difficult problem to solve in general, which is true3, but there are steps you can take to make it harder to detect timing differences.
There is a specific technique called a Timeless Timing Attack that uses HTTP/2 multiplexing to send multiple requests at the same time, allowing you to easily compare the timing of specific requests without needing to account for slow connections, rate limiting, attempt limits, etc. There is a great write-up about this vulnerability in Laravel by Jens Just Iversen from Ephort, which I recommend checking out if you’ve got time.
Not only did they investigate and report the issue, they also came up with a fix and introduced the new `Illuminate\Support\Timebox`
class to Laravel in September 2022.
The class works by accepting a callback, inside which you perform your time-sensitive operation, and the minimum execution time in microseconds. If the callback takes less time to run execute than the minimum execution time, it waits for the remainder of the time. As long as the execution time is less than the minimum, it’ll always execute in the same time - defeating a timing attack! 🎉
Using it is as simple as this:
(new Timebox)->call(function (Timebox $timebox) {
// time-sensitive operation here
}, $minimumExecutionTime);
This is how it’s used to protect Laravel login credentials:
protected function hasValidCredentials($user, $credentials)
{
return $this->timebox
->call(function ($timebox) use ($user, $credentials) {
$validated = ! is_null($user)
&& $this->provider->validateCredentials($user, $credentials);
if ($validated) {
$timebox->returnEarly();
$this->fireValidatedEvent($user);
}
return $validated;
}, 200 * 1000);
}
It’s not currently documented, but the class is very easy to understand so go check it out to learn more!
So if you’re implementing your own authentication system, or have other areas in your app where timing attacks are a risk, this is a great tool to reach for to protect your app.
Thanks Jens and Ephort! 😁
Due out 14th March 🙂
Spoiler alert: We encountered some backwards compatibility concerns, and will solve them in a different way going forward.
Every line of code takes time to execute, so even single-line differences can cause different execution times - although it can be incredibly difficult to measure these timing differences with such small variances.