Secret values in Scala
Tags: scala, configuration, security, development
Published: 2024-02-13 13:49:22

## Preface
One of the most important topics in IT is surely the security, it's so complicated and intriguing that, either you love it or you hate it, but we can't help taking care of it. Nowadays, in a society based on computers and applications, crackers attacks are very concrete and dangerous.  
In my opinion, when we talk about IT security, it is always better to overestimate the risk and have a large margin of tolerance. 
The (hard) trade-off we have to make is that the solution is usable, has good performance, and is safe.

> Often, it is not a single solution that makes something safe; it is the sum of several approaches that mitigate the risk.

---

## History

It has been a while since I had my first idea for a library that would help developers securely manage secret values within their applications. Originally, I started with a very simple wrapper of `String` to avoid unwanted printing or logging of the secret value, then I created my own application [toolkit](https://github.com/geirolz/toolkit) where I added a dedicated module with a minimal version of the `Secret` type. 

Step by step, iteration by iteration, I abandoned the [toolkit](https://github.com/geirolz/toolkit) module in favor of a dedicated library for handling secrets.
In this article, I want to briefly introduce you to my new library, explain how it works, and explain why you should use it in your projects. 
As I just said, this is the latest iteration of this idea, not the final one, and since I am now releasing it as a standalone library, I hope to get feedback and ideas to make it even better. 

Secret library github page
https://github.com/geirolz/secret

Read this interesting article which inspired my about this library
https://westonal.medium.com/protecting-strings-in-jvm-memory-84c365f8f01c

---

## The problem of secrets in applications
I believe everyone who is reading this article already knows about these problems. 
Just to be pragmatic, I'll use one of my favorite tools, a list:
- Hard-coded secrets
- Unwanted printing and logging of secrets value
- Memory leaks due to cracker attacks (e.g. JVM Heap dump)

I will briefly review these 3 problems to give you a broader context and to share the ideas behind my library. If you are not interested in this part, you can skip to the end of the article for the introduction to the library, or you can look directly at the [library page on github](https://github.com/geirolz/secret). 

### Hard-coded secrets
Below is an image explaining how secure it is to have one's datacenter fenced and guarded by armed guards, a thousand layers of software security, and hard-coded secrets. 
![weak security](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5hw04ijc154tcc3e80xl.jpeg)

There are several approaches to avoid this bad practice; I won't go through them in this article, but just to give you a tip, if you are using Kubernetes, you could use [Secrets](https://kubernetes.io/docs/concepts/configuration/secret/); similar to [ConfigMaps](https://kubernetes.io/docs/concepts/configuration/configmap/) but specifically intended to hold confidential data. 

Then you can mount secrets as a volume, inject them as environment variables, or synchronously access the vault.

Let me know if you know more methods to solve this! 

### Printing and logging
Unfortunately, this problem doesn't have a definitive solution. Common sense and education prevent most of the cases, but we are humans, and we can easily get distracted.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/seasa8ky5g16rhqr2nak.jpg)

A very simple solution would be wrapping the secret value overriding the `toString` method.

```scala
case class Secret(value: String) extends AnyVal:
  override toString: String = "** SECRET **"
```
Cool! But the following example could easily happen

```scala
case class Config(databasePass: Secret)
def initDb(pass: String): Unit = ???

//usage
val config: Config = ???
initDb(config.databasePass.value)
```

The problem is that the `initDb` method has full access to the secret value, and someone could unintentionally log or print it. The easy solution would be to pass the type `Secret` instead of the `String`.

While one improvement for the `Secret` type might be to make the API a little more difficult to use to force the user to think. 

```scala
class Secret(value: String):
  override toString: String = "** SECRET **"
  def use[T](f: String => T): T = f(value)
```

This is not a solution; you can easily bypass it, but it makes it a little more difficult (sum of approaches). 

If you do this, you deserve a firing letter :)
```scala
val pass: String = secretPass.use(identity)
```

### Memory leaks

Ok, let's start with the assumption that if someone has access to your application environment, this is not the only problem you have, but surely we can make the lives of our friends crackers a bit harder.
Here we discuss the JVM heap dump attack, a common attack to steal secrets and sensible data from an application.

Basically, the attack consists of creating a snapshot of the JVM heap and analyzing it in order to find sensible information. 

To work around this problem, we can use a kind of `ByteBuffer` called `direct` that allocates the data directly to the memory, outside the JVM heap.

```scala
ByteBuffer.allocateDirect(bytesCapacity)
```

The heap will only contain the memory addresses of the byte buffer.

To improve security a bit, we can also obfuscate the bytes we are allocating by using some strategies, the most common of which is the use of the `xor` operator. 
Xor is simple, fast, and isomorphic. Xor is not secure because it is not a cryptographic algorithm, but it is sufficient if we add up all these tricks. 

Once finished with the secret byte buffer, you can overwrite the value with `0` and cancel the pointer to avoid unnecessary leaks. Secrets are usually used at startup to build connectors or instances; there is no need to keep them in memory forever unnecessarily. 

## Secret library 
Well, I've created a library called [Secret](https://github.com/geirolz/secret) (very creative) that implements what you just read in a type named `Secret`. 
It supports direct byte buffers, xor-ed values (all primitive types), secure destruction, map and flatMap.
With the special type `DeferredSeret` you can define a secret that is acquired and then destroyed whenever it is accessed (for example, a remote call to get the value from a vault). 

It has integration modules for [cats-effect](https://github.com/geirolz/secret?tab=readme-ov-file#cats-effect), [pureconfig](https://github.com/geirolz/secret?tab=readme-ov-file#pureconfig), [ciris](https://github.com/geirolz/secret?tab=readme-ov-file#ciris) and [Typesafe Config](https://github.com/geirolz/secret?tab=readme-ov-file#typesafe-config)

You can also extend it by defining a custom algorithm to use instead of xor (default). Check the [documentation](https://github.com/geirolz/secret?tab=readme-ov-file#custom-obfuscation-strategy-algebra) if you are interested. 

As I wrote in the README, `Secret` library does its best to avoid leaking information in memory and in the code, BUT an attack is always possible, and I don't give any certainties or guarantees about security using this library; you use it at your own risk. The code is open-sourced; you can check the implementation and make your decision consciously. I'll do my best to improve the security and documentation of this project.

Let me know what you think about this article and this project! Comments, feedback, PRs, and discussions are welcome.
If you like the library, please consider leaving a star on Github to support it!