In a world where APIs are quickly becoming the standard, most of us understand the importance of following best practices for API security. We authenticate, authorize and throttle requests. We encrypt the data that we share with other applications (hopefully!). But we often neglect one of the most essential components of the API layer: data storage.

Encrypting Data as a Component of API Management Security

We often forget that APIs are not meant to protect data, rather, to share data across applications. While providers are certainly responsible for designing their APIs to be secure, we must be equally cautious about each component of the API layer.

Data Storage in apiman

Designing, building, and maintaining an API can be a lot of work, often making security an afterthought. Using an API management platform can save you valuable time, allowing you to focus on other critical aspects of your business.

Apiman was designed with the goal of providing a secure, customizable platform for API providers that is easy to use. As an open source platform, it is highly extendable and maintained by a community of developers with the common goal of streamlining API management without compromising security.

All sensitive data stored by apiman is fully encrypted so that it is not stored in plain text, then later decrypted again on runtime or when publishing services. By default, the API Manager uses a relational database for storage. One of the many examples of data that gets stored are the credentials that must be provided when the manager wants to publish an API and makes an authenticated REST call to the gateway.

Data for the API gateway and API manager are stored separately to keep components fully decoupled. For a more detailed overview, please see our API layer architecture.

Let’s swan dive into some code!

IDataEncrypter Interface and Data Encryption Classes

The component interface used by apiman to encrypt data (both in the API Manager and in the API Gateway) is called IDataEncrypter. This interface provides the structure for the classes that encrypt keys and data, which is done synchronously using AES.

By default, the DefaultDataEncrypter class is the encrypter for the gateway. The encrypt and decrypt methods accept a single parameter for the string to be encrypted or decrypted, respectively. If you look at the code, you’ll notice that the key is hard coded. For those of us that are looking for a more secure approach, we offer an alternative.

The AesDataEncrypter class is a data encrypter that accepts an encrypted secret key. When it is invoked, it expects a configuration object that contains a previously defined encrypted secret key.

At this point you may be wondering how secret keys are obtained. A factory class called ConfigFactory is responsible for creating a configuration Map using information from apiman.properties. This configuration Map is later passed to AesDataEncrypter as a parameter when it is constructed. The secret key included in the configuration Map is then used whenever data is encrypted or decrypted.

Setting the Gateway to use a Custom Encrypted Secret Key

We highly recommend that users change the default gateway encryption class to the more secure AesDataEncrypter class. To do so, please follow these steps:

1. Locate and open the apiman.properties file.

2. Uncomment the following lines, located toward the top of the file (around line 10), by removing the hashtag at the beginning of each line:

apiman.encrypter.type=io.apiman.common.util.crypt.AesDataEncrypter
apiman.encrypter.type.secretKey=

3. Add your encrypted secret key (the key must be a 16 character string).

4. Save and close the file.

5. $$$ Profit!

Writing Your Own Encryption Plugin

One of the major benefits of working with an open source API management platform, and open source projects in general, is the ability to read and modify the source code to make it work for your business needs. In apiman, we make it easy for you to write your own implementation of the data encrypter by creating a plugin that encrypts data.

Once your basic plugin is set up, you can then begin working on the Java component of your plugin that contains the functionality.

Every encryption plugin must implement the IDataEncrypter interface like this:

public class SuperDataEncrypter implements IDataEncrypter {
  /**
  * Constructor.
  */
  public SuperDataEncrypter(Map<String, String> config) {
    thing = config.get("thing"); //$NON-NLS-1$

    if (thing == null) {
      throw new RuntimeException("Missing configuration property: apiman-manager.config.thing"); //$NON-NLS-1$
    }
  }
}

As you can see, the class is constructed with the configuration Map we discussed above. Once the SuperDataEncrypter class is built, the configuration Map is checked for a "thing" key. If it is null, a runtime exception is thrown. Pretty, straightforward so far, right?

Whenever data is stored in a persistent store (either by the API Manager or by the API Gateway), the data encrypter is used to encrypt that data. You can pretty much guess what our next step will be:

public class SuperDataEncrypter implements IDataEncrypter {
  /**
  * Constructor.
  */
  public SuperDataEncrypter(Map<String, String> config) {
    thing = config.get("thing"); //$NON-NLS-1$

    if (thing == null) {
      throw new RuntimeException("Missing configuration property: apiman-manager.config.thing"); //$NON-NLS-1$
    }
  }


  /* (non-Javadoc)
   * @see io.apiman.common.util.crypt.IDataEncrypter#encrypt(java.lang.String)
   */
  @Override
  public String encrypt(String plainText) {
      return AesEncrypter.encrypt(secretKey, plainText);
  }

  /* (non-Javadoc)
   * @see io.apiman.common.util.crypt.IDataEncrypter#decrypt(java.lang.String)
   */
  @Override
  public String decrypt(String encryptedText) {
      return AesEncrypter.decrypt(secretKey, encryptedText);
  }
}

From there, you can use your SuperDataEncrypter class to write the functionality you need. For an example of an implementation you can take a look at the AesDataEncrypter class we discussed earlier. You should be up and running in no time!

If you are kind enough to want to share your plugin with the rest of the apiman community, create a pull request on the apiman plugins repository. Contributors, please don’t forget to write a unit test for any plugin you write (one that actually passes, kthx!).

Key Takeaways

If your memory is as short-lived as mine, it’s probably best that we do a quick recap. In this article we discussed the importance of securing stored data, and why it should be treated as an essential component of your API security strategy. We then discussed how apiman encrypts and decrypts sensitive data, with a detailed review of the IDataEncrypter interface and the classes that implement it.

For those of us with a guilty security conscience, we went over how to configure the API gateway to use an encrypted key that you provided in the apiman.properties file. Because we’re über ambitious, we also took a look at how to write your very own implementation of said IDataEncrypter interface and the methods you are required to implement.

As always, we love hearing from you! So, if you have any questions or comments, feel free to leave them below or reach out to us.