It’s not a secret that we’re big chess fans here at Oxeye. Our engineering team and marketing team are locked in a battle for chess supremacy, asynchronously, across the Atlantic Ocean, via a chess app. It should come as no surprise then, that we see many analogies between application security and chess.
Just as there’s a huge difference between the abilities of great chess players and those who’ve just learned how to apply the rules, there’s a massive divide between application security approaches that are focused on narrow analyses, and those that look at applications comprehensively and incorporate all the layers of modern applications into their analysis. In this post, we’ll use an example of a chess match that’s mid-game to illustrate the point.
Let’s begin by looking at this interesting chess puzzle. Let’s imagine ourselves playing the black pieces, and we need to find the best move… the one that will give us a winning advantage!
The black queen is on d2, very close to the white king. Surely we can take advantage of this proximity to the king and leverage a well-chosen check.
Look at this nice move, we can move our queen to d4, both checking the king, AND threatening the rook in the corner! The king will be forced to move away, and we will be able to eat the rook! Did you find it by yourself before reading on from the previous paragraph? It is really satisfying to play such a nice move.
We just removed this threatening rook from the board, before it had a chance to wreak any havoc on our pieces! Good job 🙂 Or was it?
We just neutralized a very powerful threat.If we were to really think about it, though, is it possible that we were focusing on the wrong thing by looking at what appears to be the simplest move, and the one that seemed most obvious? 🤔 How could this move be the wrong one?
In chess, addressing all the threats on the board is a great pursuit. But addressing them in the right order is just as, and maybe even more important. Every move we make will significantly impact our ability to fend off, or recover from a future attack from our opponent. What we perceive as threats in the current situation, may be irrelevant over the course of the match, and we should not invest time and effort addressing every hypothetical threat. To ensure victory, we should adopt a broader and longer-term point of view, and prioritize the threats. Let’s see how this plays out in our game.
Let’s come back to the original position and take a look at the possible threats that we should consider.
There are numerous permutations of what the next move could be, and every move that we make unlocks a new set of permutations. Do you feel overwhelmed with all the possible threats? How much time and effort should we invest in order to make an informed decision about our next move? And that’s even before starting to think about the counter measures of each possible threat.
And that’s for only one decision - the next move. Our threat model must be updated after each move during the game. If you wanted to play chess perfectly, you should have considered in advance all the possible paths in an incredibly huge game tree. The size of this game tree is estimated to be around 10120 (referred to as the Shannon number, named after the American mathematician Claude Shannon, who developed this conservative lower bound of the game-tree complexity of chess). Even if you consider only the valid board positions, it is estimated to be around 1044 of them. While it would be nice to have an exhaustive model that maps out all possible possibilities so we can make an informed decision, it is impractical in the real world. Even the best computer in the world, with its incredible computing power, cannot be used to brute-force this game as it would take too long.
The best players in the world have a holistic view of the board, and don’t miss any serious threats. But more importantly, they know how to recognize and focus on the most important threats. Let’s return to our game and see what that looks like.
For the player playing black, these potential moves by white are the most critical threats to their position, as they could result in the loss of important pieces and/or put their king in jeopardy. Now that we’ve prioritized and highlighted only the most important threats, we can focus and develop a plan to address them.
We have 3 black pieces directly attacked by the white queen and rook, close to our black king. So let’s build up a strategy for disabling those threats at the least possible cost.
Let’s check the white king by moving our queen to d4. The white king is forced to move away. That allows us to place our queen in a much better position without taking any risk. The white king cannot stay on the first row, otherwise we will just check it again, while eating the rook in the corner. So it’s forced to move to h2.
Now comes the interesting stuff, that will neutralize the dangerous white queen and rook. Let’s move our black knight from e5 to f3.
We’ve simultaneously checked the white king and revealed an attack on the unprotected white queen! The best next move for white is to take our knight with the rook.
The dangerous white rook has moved away, and we can take the dangerous white queen, which has been left unprotected, at no cost to us.
Focusing on the threats that really matter greatly improved our posture.
We understood that the price to pay is to sacrifice one knight, but it was a relatively low cost compared to the benefits. The dangerous white queen and rook have been neutralized, and we still keep a close eye on the remaining white rook in the corner. We addressed each threat with the right priority, without wasting our time and energy focusing on an endless list of theoretical threats.
Modern applications can be complex, involving dozens or hundreds of services. The way they are connected to each other is very important for accurately prioritizing the most important threats. Real-world applications are much more complex than a game with 64 squares and 32 pieces!
They are constantly evolving with new services and new connections.
If you simply scan your application with a legacy SAST, SCA or DAST tool, you could be overwhelmed by the number of detected vulnerabilities, in particular if you have a large application. These legacy tools were developed when applications were written as a giant monolith and hosted on a server. They treat applications like boxes and make approximations to find vulnerabilities.
SAST tools use an “open box” or “white box” approach to analyze the contents of the box - the code - in the development phase. The determination of whether the code is vulnerable or not is based on a set of predefined rules. As it’s impossible to write a perfect set of rules to encompass all situations, SAST tools make approximations. Additionally, not all the code at the development phase makes it to production, adding further to the already overwhelming amount of false positives and noise.
DAST tools view applications as a “closed box” or “black box”. They inject malicious payloads into the application when it’s running, and look for anomalous responses from the application. Unusual responses are flagged as potential vulnerabilities, with no way of validating the veracity of the findings. This results in a lot of false positives. DAST tools don’t have access to the source code, and cannot tie the vulnerability to the line of code where the vulnerability originates. Validating the vulnerabilities discovered in DAST requires manual intervention.
Using a combination of tools, and aggregating and trying to correlate the results of disparate tools can be helpful, but it still lacks the context that will enable us to precisely understand how to prioritize each vulnerability that the tools detect.
Much like the chess example, a sound approach to prioritization of vulnerabilities in application security would focus on a subset of all potential vulnerabilities by seeking out the most immediate, and dangerous threats. A framework for approaching it in AppSec would include the following questions:
This would enable us to use a data-driven approach to prioritizing detected vulnerabilities. Not only would this approach consider the way your services are connected together, and how data flows across them, but also leverages all the relevant insights related to modern applications, including the configuration of the infrastructure layer. Without asking these questions, we will find ourselves in a scenario where we believe that we’re making a move that will set us up for success, but that actually puts us at a significant disadvantage in the future.