GDPR Compliance with Spring Boot Applications Part I: External Databases
The new European General Data Protection Regulation (GDPR) comes with novel challenges when dealing with personal data. GDPR Article 25 requires data protection by design by default. This means that all of the application’s privacy settings must be set to protect a user’s privacy when the application is provisioned to users. Technical measures need to be implemented in order to protect precious personal data of individuals and companies. Article 32 states several technical details on the requirements for processing data in GDPR compliant applications.
According to article 32, it is necessary to always have full control over personal data. Therefore, external third party database services (e.g. hosted database as a service solutions) must be treated with caution. Such services might automatically store backups or replicate the data on multiple servers, which makes it challenging to delete personal (and sensitive) data consistently upon request. Another risk comes with the fact that service providers might be able to physically access data stored in the database. Both issues can be addressed with encrypting the data in the actual application before it leaves the application and is being stored in an external database.
This is the first article in a series, which has the goal to show several technical solutions for some of the new challenges. During the series, I will mainly focus on Spring Boot based applications. This first article shows an example application, which utilises functionalities from the Java Persistance API (JPA) for encrypting data before it is sent to a database service. It seamlessly integrates into the Spring Boot technology and, therefore, comes with little additional overhead. The source code of this project is available on GitHub. Let’s get started and do things GDPR-style.
The project comes with a self-contained Docker setup. The following versions are used throughout the example:
Spring Boot: 2.0.2.RELEASE
Bouncy Castle: 1.59
Due to the fact that a self-contained setup is provided, the following call builds and executes the application connected to a PostgreSQL database:
docker-compose up --build
This command also starts a simple database viewer, which can be used to explore the stored data. After the application was executed successfully, the content of the database can be displayed on http://localhost:8081/. It can be seen that the exemplary customer data (go to Tables > customer) is fully encrypted and can not be read.
In general, the application exploits the Attribute Converters introduced in JPA 2.1. It allows specifying methods to convert between the database and the Java representation of an attribute. An implementation of the interface has to implement the following methods:
public Y convertToDatabaseColumn (X attribute);
public X convertToEntityAttribute (Y dbData);
In our case, the database column is the encrypted String representation of the attribute. The following code snippet shows the applied implementation of the interface:
Every attribute is encrypted before it is sent to the database and decrypted after it was fetched. The concrete String representation is specific to the class of the attribute and is obtained via the concrete implementation of:
abstract T stringToEntityAttribute(String data);
abstract String entityAttributeToString(T attribute);
Implemented converters (i.e. StringConverter, LocalDateConverter, LocalDateTimeConverter) and are attached to individual columns via the @Convert annotation, as shown in the entity definition below.
Encryption is done via the BouncyCastleAesCbcBytesEncryptor, which applies AES256 with Cipher Block Chaining to the respective string representation. PBKDF2 is used as the password-based key derivation function.
The application mainly stores two separate customers and queries them by mail afterwards (see code snippet below). It can be seen that the familiar workflow of Spring Boot repositories stays untouched, even though all data is being encrypted.
Applying encryption to attributes via converters has the nice effect that no unencrypted data leaves the application. This leads to a higher level of control when dealing with personal data. Additionally, this mechanism is independent of the underlying database technology (e.g. PostreSQL) and, therefore, provides more freedom for developers. Some database technologies have built-in encryption capabilities (e.g. PostresSQL). In such scenarios, the encryption key has to leave the application, which lowers the level of security. Stay tuned for part II of this series.