🔄 How to close the feedback loop on an attacker

Why embedding SIEM into your application is not such a bad idea.

When we discussed adversarial cycle we mentioned that defending the system is a fundamentally unsolvable problem, because it's an infinite game. Our task, however, is not to win it but "tip the economics" in our favor. By that I mean trying to create an environment where attacking is less advantageous than doing something else. One of the key pieces of the cycle is the detection, hence making it easier and faster for us to detect an attack helps us tip that balance.

Security field has a concept of Security Information and Event Management (SIEM). The SIEM systems go far beyond simple logging in order to provide the service needed to discover attacks on the services. However when it comes to application security in order for the application to react to the attacker's action in real time the SIEM solution has to be integrated with the application itself. Having said that I don't mean we need to start integrating with Super Expensive Enterprise-Grade Solutions™️. If you just start collecting events from certain key actions that users make when they interact with the application - that's already SIEM. These events can be account creation, logins, logouts, profile updates, etc.

The most rudimentary event structure consists of the following key pieces of data:

  • Event name (to help us answer what happened)
  • Timestamp (to help us identify a point in time of the event)
  • Meta-data (information that is in one way or the other related to the event)

We are going to talk about what we want to store in meta-data in a different article, for now let's concentrate on what we want to do with these events.

In the most rudimentary example we can start with parsing HTTP logs. The default logging format of most HTTP servers looks like so. - - [04/Apr/2022:01:32:46 +0000] "GET /login HTTP/1.1" 200 2161 "-" "curl/7.68.0"

We can think of GET /login as the event name, 04/Apr/2022:01:32:46 +0000 is the timestamp, and the rest is the meta-data such as an IP address, user agent, size of the request and an HTTP code.

Practical tips on how to parse and quickly triage the logs are in the upcoming posts.

Modern SIEM platforms allow shipping logs and even fire custom events to them for the later discovery of the malicious patterns. Some of them support setting up rules and alerting mechanisms to bring attention to the malicious activity. These are fantastic tools to discover complicated attacks and investigate the activity after the incident is over.

What about dealing with an active attack? An non-integrated SIEM still means the defenders have to be present at the time of the attack. To allow the application to react to the attacker quickly and independently we need to close the feedback loop.

This means security even management should be a part of the codebase. To achieve this we can have points in the code that generate events and send them to a database or an event streaming platform. This will allow the application to react to them on-the-wire or in the background.

To leave a trace it can be a simple invocation of a function.

fire_event("auth.success", timestamp, metadata)

But can also use this as a gate to see if we should allow the user to proceed even if, say, the authentication was successful but we are confident this is an attempt to compromise an existing account.

if is_suspicious("auth.success", timestamp, metadata):
    # additional verification step

Detecting suspicious activity is a vast topic and goes beyond the scope of this article, but as soon as the feedback loop with at attacker is closed the game begins.