DEV Community

Cover image for Treat security as a risk
Nicolas Fränkel
Nicolas Fränkel

Posted on • Originally published at blog.frankel.ch

Treat security as a risk

Security is the poster child of a Non-Functional Requirement: most people don't care until the proverbial fecal matter hits the rotary propeller. Consequences can range from losing reputation to legal liability to putting the business out. In my post on running unsecured code, I concluded that you should treat security as a risk - and left it at that. I think it warrants a dedicated post.

Risk management is pretty much documented. You can find it in many engineering disciplines, if not every one of them. A risk management process consists of the following steps:

IdentifyAnalyzePrioritizeTreatMonitor

Let's see how we can apply it to security using the Attach API as an example.

Identify the risk

In short, the Attach API allows one to change the bytecode already loaded in a running JVM 1.6+. For that, you need:

  • The PID of the running JVM
  • The ability to run another JVM on the same system

When the attached JVM starts again, it discards the updated bytecode and loads the code from the expected location. Hence, there's no trace that the bytecode has been changed via the feature.

With the Attach API, a malicious actor could change the behavior of a running application. For example, the actor could direct a few cents on every transaction to their account in a banking system.

Analyze the risk

Now that we have correctly identified the risk, we need to quantify its likelihood: how likely can a malicious actor trigger the risk?

For our example, we need to evaluate the likelihood of:

  1. Accessing the system
  2. Getting permissions to start a JVM
  3. Getting the JVM's PID

The system access and the permission depend on unknown factors in the context of this blog post. However, getting hold of the JVM's PID is straightforward if you fulfill the other two.

With JVMs lower than version 9, we need to default to the Runtime class and use the jps command:

long pid = Runtime.getRuntime()
               .exec("jps")
               .inputStream
               .bufferedReader(Charset.forName("UTF-8"))
               .lines()
               .map { it.split(" ").toTypedArray() }
               .filter { it.size > 1 && it[1].endsWith("BusinessApplicationKt") }
               .map { it[0] }
Enter fullscreen mode Exit fullscreen mode

Starting from 9 onwards, the JVM added a dedicated ProcessHandle class in the Process API:

long pid = ProcessHandle.current().pid()
Enter fullscreen mode Exit fullscreen mode

Prioritize

To prioritize, we need to evaluate the impact of a successful attack.

In the context of the Attach API, it depends on the target system.
It's very context-dependent, so here's a sample of some domains:

Impact Scale Example
Threat to human life Very high
  • Dangerous industrial process
  • Surgery device
  • Hospital
Economic with large radius High to very high
  • Banking transaction involving millions
  • Stock exchange
  • Food-related goods trading
Gaming (except competitive) Low Candy Crush

Treat

Treating includes two separate things:

  • Preventing the risk from happening
  • Mitigations, if any

Mitigations allow reducing the impact of the attack. There might be several mitigations. With each, you need to describe: how much it reduces the impact and how much it costs.

With the Attach API, the feature is enabled by default. The treatment is to disable it explicitly. I couldn't come up with any mitigation. Once the malicious actor has injected the bytecode, the latter will run its course.

Risk management in the real-world

Security is not a black-and-white concern. There's no such thing as a secure system vs. an insecure one. Some systems are more secure than others against specific threats. Moreover, improving security against a threat has a cost in general. Hence, one needs to find the right balance between the likelihood of the risk, its impact, the cost of the treatment, and possible mitigations.

If you implement all of the risk management steps that I described above, you'll probably fail anyway. The reason is that we work within human organizations: it involves politics, blame games, avoidance of responsibility, and similar company-related niceties.

If you want to have any chance of making risk management work, you need to track the decision taken. The record should include all of the above: risk, description, likelihood, impact, mitigations, etc., without forgetting the decision. It can be acceptance, refusal or any mitigation action.

A critical piece of info is missing: the person who took the decision. By having a person accountable, they will be committed and not only involved. At this point, there's still no guarantee. However, the organization will be better equipped to avoid the worst fiascos such as the Equifax data breach.

Originally published at A Java Geek on January 23rd, 2022

Top comments (1)

Collapse
 
jpaulin profile image
Jukka Paulin

Loved this piece!

I quote from my unfinished B.Sc. thesis for the financial aspects of security:
Security breaches are enabled by many things, but one of the
factor that creeps from human assumptions is that the software
team responsible for developing the code might never imagine
the software to be used in a particular setting.

"Small web servers", which were supposed to live for a few months, then one day find their way not only to rather closed and protected intranets, but indeed are out in the wild, facing all the hostile network traffic the world of Internet can bring about. These same software are also running perhaps as a utility glue in children's toys and what-not - essentially in as many places as you could NOT imagine. People might have forgotten (during a typical lifespan of 5-10 years) the origins of the software, and might take for granted certain security properties - "since it (software) is popular and has been time-tested".