Open In App

Spring Boot – Enhancing Data Security Column Level Encryption

Last Updated : 05 Feb, 2024
Improve
Improve
Like Article
Like
Save
Share
Report

Column-level encryption is crucial to enhancing data security in a Spring Boot application. It involves encrypting sensitive data at the column level in a database, ensuring that even if the database itself is compromised, the sensitive information remains secure. In a Spring Boot application, you can achieve column-level encryption by combining the use of encryption libraries, database features, and proper coding practices. Here’s a step-by-step guide.

Importance of Implementing Column-Level Encryption in a Spring Boot Application

  • Protects Sensitive Data: Safeguards personal and financial information, ensuring confidentiality.
  • Ensures Compliance: Meets industry regulations, preventing legal consequences.
  • Defends Against Insider Threats: Adds an extra layer of protection against misuse by those with database access.
  • Minimizes Breach Impact: Reduces the impact of data breaches, making it harder for attackers to exploit information.
  • Builds Trust: Demonstrates a commitment to data security, enhancing user trust and organizational reputation.

Steps to Implement Column-Level Encryption in a Spring Boot Application

Below are steps to be followed while implementing Column-Level Encryption in a Spring Boot Application

Step 1: Set Up a Spring Boot Project

You can use Spring Initializer spring_initializer to generate a basic Spring Boot project. Choose the following options:

  • Project: Maven or Gradle (depending on your preference)
  • Language: Java
  • Spring Boot: The latest stable version
  • Group: Your project’s group name (e.g., com.example)
  • artefactArtifact: Your project’s artifact name (e.g., column-level-encryption)Dependencies: Add Spring Web and Spring Data JPA

Click “Generate” to download the project archive. consider below-given pom.xml file below:

XML




<?xml version="1.0" encoding="UTF-8"?>
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
                        https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <!-- Maven Project Configuration -->
    <modelVersion>4.0.0</modelVersion>
  
    <!-- Parent Project Information -->
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.2.1</version>
        <relativePath /> <!-- lookup parent from repository -->
    </parent>
  
    <!-- Project Information -->
    <groupId>com.example</groupId>
    <artifactId>SecureColumnEncryptionDemo</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>SecureColumnEncryptionDemo</name>
    <description>RESTful API for Secure Column Encryption Demo</description>
  
    <!-- Java Version -->
    <properties>
        <java.version>17</java.version>
    </properties>
  
    <!-- Project Dependencies -->
    <dependencies>
        <!-- Spring Boot Starter for Data JPA -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
        <!-- Spring Boot Starter for Web -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!-- H2 Database (Runtime Scope) -->
        <dependency>
            <groupId>com.h2database</groupId>
            <artifactId>h2</artifactId>
            <scope>runtime</scope>
        </dependency>
        <!-- Project Lombok (Optional) -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <!-- Jasypt Encryption Library -->
        <dependency>
            <groupId>org.jasypt</groupId>
            <artifactId>jasypt</artifactId>
            <version>1.9.3</version>
        </dependency>
        <!-- Spring Boot Starter for Testing -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>
  
    <!-- Maven Build Configuration -->
    <build>
        <plugins>
            <!-- Spring Boot Maven Plugin Configuration -->
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <!-- Exclude Lombok from Spring Boot Plugin Processing -->
                    <excludes>
                        <exclude>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok</artifactId>
                        </exclude>
                    </excludes>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>


Step 2: Import the Project into your IDE

Unzip the downloaded archive and import the project into your preferred Integrated Development Environment (IDE) like Spring tool suite (STS), IntelliJ IDEA, Eclipse, or Visual Studio Code.

Step 3: Configure Jasypt in Application Properties

Open src/main/resources/application.properties (or application.yml) and configure the Jasypt properties:

# DataSource settings
spring.datasource.url=jdbc:h2:mem:testdb
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=password
spring.jpa.database-platform=org.hibernate.dialect.H2Dialect

# H2 Console settings
spring.h2.console.enabled=true
spring.h2.console.path=/h2-console

# Hibernate settings
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.format_sql=true

# Server port
server.port=8080

# Jasypt Configuration
jasypt.encryptor.algorithm=PBEWithMD5AndDES
jasypt.encryptor.password=mySecretKeys

Replace mySecretEncryptionKey with your actual encryption password.

Step 4: Create an Entity whose column data needs to be encrypted

Let us create an Entity named ‘Geeks’ and add encryption on its fields

Java




package com.example.securecolumnencryptiondemo.entity;
  
import java.time.LocalDateTime;
import java.util.UUID;
  
import com.example.securecolumnencryptiondemo.convertor.StringCryptoConverter;
  
import jakarta.persistence.Column;
import jakarta.persistence.Convert;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.PrePersist;
import jakarta.persistence.PreUpdate;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
  
/**
 * The `Geek` entity represents a geek with encrypted fields for mobile number and email ID.
 * It also includes timestamps for creation and last update.
 
 * Note: Ensure that the `StringCryptoConverter` is configured to handle encryption and decryption
 * for the mobileNumber and emailId fields.
 
 * @author rahul.chauhan
 */
@Entity
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Geek {
  
    @Id
    @GeneratedValue(strategy = GenerationType.UUID)
    private UUID id;
  
    @Column
    private String firstName;
  
    @Column
    private String lastName;
  
    // The mobile number field is annotated with @Convert to use the StringCryptoConverter
    // for encrypting and decrypting the data.
    @Convert(converter = StringCryptoConverter.class)
    private String mobileNumber;
  
    // The email ID field is also annotated with @Convert for encryption and decryption.
    @Convert(converter = StringCryptoConverter.class)
    private String emailId;
  
    @Column(name = "create_date_time", updatable = false)
    private LocalDateTime createDateTime;
  
    @Column(name = "updated_date_time")
    private LocalDateTime updatedDateTime;
  
    /**
     * This method is annotated with @PrePersist and is called before an entity is persisted
     * to the database. It sets the createDateTime and updatedDateTime to the current timestamp.
     */
    @PrePersist
    protected void onCreate() {
        createDateTime = LocalDateTime.now();
        updatedDateTime = LocalDateTime.now();
    }
  
    /**
     * This method is annotated with @PreUpdate and is called before an entity is updated in
     * the database. It updates the updatedDateTime to the current timestamp.
     */
    @PreUpdate
    protected void onUpdate() {
        updatedDateTime = LocalDateTime.now();
    }
}


Step 5: Create the StringCryptoConverter

StringCryptoConverter class responsible for encrypting and decrypting string attributes. Below is the class StringCryptoConverter.

Java




package com.example.securecolumnencryptiondemo.convertor;
  
import org.jasypt.encryption.pbe.StandardPBEStringEncryptor;
import org.springframework.core.env.Environment;
  
import jakarta.persistence.AttributeConverter;
import jakarta.persistence.Converter;
  
/**
 * JPA Attribute Converter for encrypting and decrypting String attributes. This
 * converter uses the Jasypt library for encryption and decryption operations.
 * It is configured with an environment variable for the encryption password.
 
 * Note: Ensure that the Jasypt library is correctly configured in your project.
 * The encryption password should be provided through the
 * "jasypt.encryptor.password" property.
 
 * @author rahul.chauhan
 */
@Converter
public class StringCryptoConverter implements AttributeConverter<String, String> {
  
    // Property name for the encryption password
    private static final String ENCRYPTION_PASSWORD_PROPERTY = "jasypt.encryptor.password";
  
    // Jasypt StringEncryptor for performing encryption and decryption
    private final StandardPBEStringEncryptor encryptor;
  
    /**
     * Constructor for StringCryptoConverter.
     
     * @param environment The Spring Environment used to access properties.
     */
    public StringCryptoConverter(Environment environment) {
        // Initialize the encryptor with the encryption password from the environment
        this.encryptor = new StandardPBEStringEncryptor();
        this.encryptor.setPassword(environment.getProperty(ENCRYPTION_PASSWORD_PROPERTY));
    }
  
    /**
     * Converts the attribute value to the encrypted form.
     
     * @param attribute The original attribute value to be encrypted.
     * @return The encrypted form of the attribute.
     */
    @Override
    public String convertToDatabaseColumn(String attribute) {
        return encryptor.encrypt(attribute);
    }
  
    /**
     * Converts the encrypted database value to its decrypted form.
     
     * @param dbData The encrypted value stored in the database.
     * @return The decrypted form of the database value.
     */
    @Override
    public String convertToEntityAttribute(String dbData) {
        return encryptor.decrypt(dbData);
    }
}


Step 6: Create the GeekRepository

Generate the GeekRepository interface, extending JpaRepository<Geek, UUID>, to provide basic CRUD operations for the Geek entity. This interface is automatically implemented by Spring Data JPA.

Java




package com.example.securecolumnencryptiondemo.repository;
  
import com.example.securecolumnencryptiondemo.entity.Geek;
import org.springframework.data.jpa.repository.JpaRepository;
import java.util.UUID;
  
public interface GeekRepository extends JpaRepository<Geek, UUID> {
}


Step 7: Create the GeekService Interface

Define the GeekService interface, declaring methods for creating and retrieving Geek entities.

Java




package com.example.securecolumnencryptiondemo.service;
  
import java.util.UUID;
import com.example.securecolumnencryptiondemo.entity.Geek;
  
public interface GeekService {
    Geek createGeek(Geek geek);
  
    Geek getGeek(UUID id);
}


Step 8: Implement the GeekServiceImpl

Develop the GeekServiceImpl class, which implements the GeekService interface. This class uses the GeekRepository for persisting and retrieving Geek entities.

Java




package com.example.securecolumnencryptiondemo.service.impl;
  
import java.util.UUID;
  
import org.springframework.stereotype.Service;
  
import com.example.securecolumnencryptiondemo.entity.Geek;
import com.example.securecolumnencryptiondemo.repository.GeekRepository;
import com.example.securecolumnencryptiondemo.service.GeekService;
  
/**
 * @author rahul.chauhan
 */
@Service
public class GeekServiceImpl implements GeekService {
  
    private final GeekRepository geekRepository;
  
    public GeekServiceImpl(GeekRepository geekRepository) {
        this.geekRepository = geekRepository;
    }
  
    @Override
    public Geek createGeek(Geek geek) {
        return geekRepository.save(geek);
    }
  
    @Override
    public Geek getGeek(UUID id) {
        return geekRepository.findById(id).orElse(null);
    }
}


Step 9: Create the GeekController

Build the GeekController class, which serves as the REST API endpoint for creating and retrieving Geek entities. Use the GeekService to handle the business logic.

Java




package com.example.securecolumnencryptiondemo.controller;
  
import java.util.UUID;
  
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
  
import com.example.securecolumnencryptiondemo.entity.Geek;
import com.example.securecolumnencryptiondemo.service.GeekService;
  
@RestController
@RequestMapping("/api/geeks")
public class GeekController {
  
      
    private final GeekService geekService;
  
    public GeekController(GeekService geekService) {
        this.geekService = geekService;
    }
  
    @PostMapping
    public Geek createGeek(@RequestBody Geek geek) {
        return geekService.createGeek(geek);
    }
  
    @GetMapping("/{id}")
    public Geek getGeek(@PathVariable UUID id) {
        return geekService.getGeek(id);
    }
}


Spring Boot Application Project Directory:

imresizer-1705156716248

Step 10: Test Your Application

Write unit and integration tests to verify that data is encrypted when stored in the database and decrypted when retrieved. Ensure that all components of your application work as expected.

Step 11: Run Your Application

Start your Spring Boot application and test the functionality by making HTTP requests to the defined API endpoints. Verify that the data is encrypted and decrypted appropriately.

Testing The Spring Boot application

  • Step 1: Start Your Spring Boot Application : Ensure that your Spring Boot application is running.
  • Step 2: Open Postman : Open Postman on your machine.
  • Step 3: Create a New Request : Click on the “New” button in Postman to create a new request.
  • Step 4: Set Request Details

Request Type: Choose the appropriate HTTP method (e.g., POST for creating a new entity).
Request URL: Use the URL of your Spring Boot application endpoint (e.g., http://localhost:8080/api/geeks).
Headers: If required, set any headers needed for your request.
Body: In the request body, provide JSON data for creating a new Geek entity with sensitive information. For example:

{
    "firstName": "Virat",
    "lastName": "Chauhan",
    "mobileNumber": "8755757578",
    "emailId": "virat.chauhan@gmail.com"
}
  • Step 5: Send the Request : Click the “Send” button to send the request to your Spring Boot application.
  • Step 6: Verify Encryption :Check the response from the server to ensure that the entity is created successfully.

Verify that the sensitive fields (mobileNumber and emailId) are not returned in their original form. They should be encrypted. Find below attached image of database where geek entity is saved
imresizer-1705120692410As it is visible form attached image that EMAIL_ID and MOBILE_NUMBER are being encrypted.

  • Step 7: Retrieve and Verify Decryption

Create a new request to retrieve the entity you just created (e.g., use a GET request to http://localhost:8080/api/geeks/{id}, replacing {id} with the actual ID). Check the response to verify that the retrieved entity’s sensitive fields are decrypted correctly.consider below image.
imresizer-1705120934951

Key Points for Column-Level Encryption in Spring Boot

  • Identify Sensitive Data:Clearly pinpoint the data fields containing sensitive information.
  • Compliance Check:Ensure compliance with industry or legal standards for data security.
  • Choose Strong Encryption:Select a robust encryption method, such as AES.
  • Secure Key Handling:Implement secure key management, restricting access and rotating keys regularly.
  • Configure Jasypt:Set up Jasypt with the right settings and protect your encryption password.
  • Selective Encryption:Use JPA annotations to selectively encrypt specific fields.
  • Custom Converters:Implement custom converters (e.g., StringCryptoConverter) for targeted encryption.
  • Thorough Testing:Develop comprehensive tests to ensure encryption and decryption work correctly in various scenarios.


Like Article
Suggest improvement
Previous
Next
Share your thoughts in the comments

Similar Reads