Developer security best practices: protecting against timing attacks

One of the great things about security is that there is always more to learn. When you’re protecting your applications and users, understanding the kinds of attacks bad actors may attempt can help you get a better sense of how you should protect your applications and the kind of business logic threats you may be exposed to. In this article, we’re going to take a look at timing attacks. Timing attacks are a particular type of attack that exploits flaws in code that impact execution time to discover hints about secrets, and can be used for ATO attacks.

tl;dr

The main takeaway for protecting against timing attacks is don’t use the string comparison == when checking for secrets or token equality. Use constant-time implementations instead.

Here’s an example of vulnerable code

To understand timing attacks and what the vulnerability looks like in code, let’s start by taking a look at some vulnerable code. The following Python code snippet is vulnerable to timing attacks. See if you can spot why:

Why is this code vulnerable to timing attacks?

The code snippet above is vulnerable, despite its simplicity. Why is that? The reason is that the code that compares two string is equivalent to this one:

It iterates over each character of the two strings and returns False as soon as two characters differ. This means that comparing two strings can take differing amounts of time depending on the location of the first difference.

String comparison
the comparison function checking a password attempt

The difference appears negligible, and it is indeed very small, but statistics dictate that even small differences can be detected with precise enough measurements. Moreover, network jitter can now be precisely modeled and can be removed from measures over the internet. According to one of the reference papers on the subject, “we have shown that, even though the Internet induces significant timing jitter, we can reliably distinguish remote timing differences as low as 20µs”. This means that the difference in returning False in this function is actually a signal and valuable information for an attacker.

Timing attacks can occur when the attacker controls the value that is compared to the secret. For an authorization key, for example, if they discover that the first character is f, they can start sending keys beginning with f to find the next characters. It’s a simple matter to find the outlier (i.e. the correct letter) based on the time it takes the function to return False if the attacker has the right tooling in place.

How to strengthen your code against timing attack vulnerabilities

To prevent having a timing attack vulnerability in your code, the solution is to compare the two strings in a way that is not dependent on the length of the strings. This algorithm is called “constant time string comparison.”

To successfully protect against timing attack vulnerabilities, the algorithm must:

  • Compare all of the characters before returning true or false
    • returning early will leak information and create an opportunity for attackers
  • Compare strings of equal length
    • if one string is longer or shorter, you’ll return early and leak information about the secret string length

Depending on the details of your environment, there is likely a function you can use for these comparisons. Django provides a function constant_time_compare that can be used to securely check two strings. The Python standard lib also provides the function hmac.compare_digest, starting in Python 3.3+.

What timing attacks look like in practice

If you’d like to play around with timing attacks and see what they look like, we have provided a sample Python web application coded in Flask that checks authorization token in an unsecure manner vulnerable to timing attacks. You can also find a script that will exploit this vulnerability to retrieve the expected token.

How to run the sample vulnerable web application

In order to run the example vulnerable web application, first create a virtualenv:

Then install the dependencies:

You can then run the web application this way:

The web application expects to receive the token named SECRET_TOKEN in app.py in the header named X-TOKEN. If the header matches the hardcoded one, it returns a 200 OK status code, else it returns a 403 Forbidden.

Hacking the web application with a timing attack

With the vulnerable application set up, the next step is running the timing attack to hack it. In order to run the script to hack the web application, create a virtualenv:

Then install the dependencies:

Finally, launch it with:

Customize the example for yourself

You can change the hardcoded token in app.py to validate that the script is effectively working.

Do note, if you change the expected token size, also change the variable TOKEN_SIZE in hack.py. The hacking script is fairly simplistic, and was not made smart enough to try to find the right token size.

You can play with the code located here.

Conclusion

With all the different types of attacks and vulnerabilities out there, writing perfectly secure code is all but impossible (which is why we believe in Application Security Management), but by implementing best practices like secure code review and making smart choices, you can make a positive difference in your security posture. Understanding how different attacks work are a big element of this. Timing attacks are a great example of a vulnerability you can mitigate in code, but that can lead to account takeovers if not addressed. Of course, as with anything security-related, the devil is in the details. For more on strengthening your code against attacks, check out our blog on Preventing SQL injection in Python.

References:

1
Leave a Reply

avatar
1 Comment threads
0 Thread replies
0 Followers
 
Most reacted comment
Hottest comment thread
0 Comment authors
Recent comment authors
  Subscribe  
newest oldest most voted
Notify of
trackback

[…] Properly validating your inputs can go a long way towards improving the security of your code, and preventing third parties from accidentally or intentionally making your code do something it wasn’t supposed to. In this article, we took a look at some ways to validate inputs in Python. If you’d like to read more about good developer security best practices, check out our post on protecting against timing attacks. […]

You May Also Like