How we use linting, static and dynamic analysis

‘Shifting left’ has had a massive impact on modern software development practices. We should try to fix bugs earlier (often shown on the left) in the development lifecycle,  because it is easier and cheaper. This means that it is worth trying to identify them earlier too.

A graph of attention to quality at different stages in the development lifecycle.

We try to do this for security bugs by combining linting, static and dynamic analysis tools. Each of these tools has its own pros and cons. By using all of them, we can find many issues.

This blog shows a simple example involving the comparison of stored hash values. This is done in web applications when managing passwords. The user submitted password  needs to be stored securely and is hashed. This hash is then compared to a hashed generated on log in.

The problem with hash comparison

The difference in time between successful and unsuccessful requests can reveal information. When comparing hashes, this can happen if a simple string comparison algorithm is used. These algorithms work on a character-by-character basis and stop if there is any difference. Why keep going if you know the results don’t match?

This is dangerous when a stored secret, like a password hash, is compared – the processing time reveals the difference.  It may take many thousands of measurements and changes to the input character-by-character, but the stored secret can be found. This is a timing attack.

There are alternative algorithms that always take the same time in successful or unsuccessful cases. We can use different security tools to find where these are required and stop timing attacks.

Our example for this blog.

Preventing this with linting

Linters break the application source code down into a series of tokens. Rules then run on top of these token streams to identify patterns. These rules match specific sequences of tokens to reason about what the code is trying to do.

Matching tokens against rules is fast and does not need the whole program to be analysed. This allows for feedback to be provided to the developer in real-time. 

Linters lack context though. They can not tell if the operation is sensitive. A developer may be performing a hash to, for example, pseudo-anonymise a data set. This will still be highlighted by the linter.

Data flow analysis

Data flow analysis transforms the token stream and analyses it at a much deeper level. Instead of ‘rule matching’ on tokens it builds a control-flow graph. This graph represents all the possible execution flows. It is possible to highlight risks by checking how the data moves through it. 

On a large code base this process takes a lot of time and a lot of memory because the control-flow graph can be large.  This may be out-of-reach for a developer’s machine and it may take longer for feedback to be provided.

A data flow analysis may highlight that user input has reached the hash function. It may also match more complicated code that rule matching can not.

Dynamic analysis

Data flow analysis lacks context and can not catch run-time or configuration issues. It also requires access to the source code, which may not be available. This is where dynamic analysis can be used.

Dynamic analysis sends input to the application and measures how the application behaves. By comparing the behaviour for different inputs, issues can be found. This is similar to how attackers find and exploit weaknesses.

The problem with this approach is that the input may not cover all code. There may be code that does not run or misbehave. This is a particular problem in large applications. This is also the slowest approach to getting feedback to the developers. 

What can we do?

The best approach is to combine all the tools and use them at different points in the software lifecycle. This is what we do at Reward Gateway. We’ve developed a large set of rules based on real-world problems we’ve had with our application. These rules run on every change and we perform the slower checks later in the process. This finds the issues early.

We don’t just use this approach for security either. We’ve got checks for accessibility, internationalisation and more. 

This helps us ship great products to customers with quality ‘built in’.

Leave a Reply