Skip to content

Utility library to use with Jackson-Databind to provide custom POJO/JSON serialization and deserialization aiming to protect sensitive data via masking with encrypting-decrypting.

License

Notifications You must be signed in to change notification settings

bancolombia/data-mask

Repository files navigation

Data Masking Utility

Maven Central Version Quality Gate Status Maintainability Rating Reliability Rating Security Rating Coverage Bugs Code Smells Scorecards supply-chain security

Utility library to use with Jackson-Databind to provide custom POJO/JSON serialization and deserialization aiming to protect sensitive data via masking with additional encrypting-decrypting.

Functionality:

Using a customized Object Mapper you can:

  • Perform Masking on string members of an object

    • Scenario: masking a credit card number when serializing to json.

      public class Customer {     
      
          @Mask(rightVisible=4)
          public String creditCardNumber;
      
      }
      
      Customer c = new Customer();
      c.creditCardNumber = "1111222233334444";
      String json = objectMapper.writeValueAsString(c);
      
      assert json.equals("{ \"creditCardNumber\": \"***************4444\"}")
  • Encrypting:

    Converting string members of an object into a pair of masked an ecrypted values.

    • As an composite String:

      public class Customer {     
      
          @Mask(rightVisible=4, queryOnly=false)
          public String creditCardNumber;
      
      }
      
      Customer c = new Customer();
      c.creditCardNumber = "1111222233334444";
      String json = objectMapper.writeValueAsString(c);
      
      assert json.equals("{
        \"creditCardNumber\": \"masked_pair=***************4444|<credit card encrypted value>\"
      }")
    • Or as Json Object.

      public class Customer {     
      
          @Mask(rightVisible=4, queryOnly=false, format=DataMaskingConstants.ENCRYPTION_AS_OBJECT)
          public String creditCardNumber;
      
      }
      
      Customer c = new Customer();
      c.creditCardNumber = "1111222233334444";
      
      String json = objectMapper.writeValueAsString(c);
      
      assert json.equals("{
        \"creditCardNumber\": {
          \"masked\": \"***************4444\",
          \"enc\": \"<credit card encrypted value>\"
        }
      }")
  • Decrypting: Reverting an encrypted string/json input value to its original plain value.

    • Having a JSON with a composite string value:

      String json = "{
        \"creditCardNumber\": \"masked_pair=***************4444|<credit card encrypted value>\"
      }";
      
      Customer c = objectMapper.readValue(json, Customer.class);
      
      assert c.creditCardNumber.equals("1111222233334444");
    • Having a JSON with an Object value:

      String json = "{
        \"creditCardNumber\": {
          \"masked": \"***************4444\",
          \"enc": \"<credit card encrypted value>\"
        }
      }";
      
      Customer c = objectMapper.readValue(json, Customer.class);
      
      assert c.creditCardNumber.equals("1111222233334444");

Installing

With Gradle

implementation 'com.github.bancolombia:data-mask-core:1.2.0'

With maven

<dependency>
  <groupId>com.github.bancolombia</groupId>
  <artifactId>data-mask-core</artifactId>
  <version>1.2.0</version>
</dependency>

This library depends on:

  • org.apache.commons:commons-lang3
  • com.fasterxml.jackson.core:jackson-databind

Using Data-Mask

A. Implement Cipher and Decipher interfaces

This library defines two interfaces: DataCipher and DataDecipher which are used in the encryption/decryption processes.

User of this library must define implementation for both interfaces.

Dummy Example:

var dummyCipher = new DataCipher() {
    @Override
    public String cipher(String plainData) {
        return "the encrypted value";
    }
};

var dummyDecipher = new DataDecipher() {
    @Override
    public String decipher(String encryptedData) {
        return "the plain value";
    }
};

B. Declare the customized Object Mapper.

This library defines a custom ObjectMapper in order to provide the masking and unmasking functionality, and takes as constructor arguments, the implementations of both DataCipher and DataDecipher interfaces.

    public ObjectMapper objectMapper(DataCipher someCipherImpl, DataDecipher someDecipherImpl) {
        return new MaskingObjectMapper(someCipherImpl, someDecipherImpl);
    }

C. Decorate POJOs

Members to be masked/encrypted should be annotated with @Mask, eg:

    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    public static class Customer {
        private String name;

        @Mask(leftVisible = 3, rightVisible=4)
        private String email;

        @Mask(rightVisible=4, queryOnly=false, format=DataMaskingConstants.ENCRYPTION_AS_OBJECT)
        private String creditCardNumber;
    }

Anotation Properties

Attribute Default value Description
leftVisible 0 Masking: how many characters should remain visible on left. Example: Hello******
rightVisible 4 Masking: how many characters should remain visible on right Example: *****World
queryOnly true true: Serialization should generate masked value only.
false: serialization should generate masked value and encrypted value.
format ENCRYPTION_AS_OBJECT Describes how masked and encrypted data should be serialized. Using ENCRYPTION_INLINE means masked and encrypted values together are serialized as string: masked_pair=<masked_value>I<encrypted_value>
Using ENCRYPTION_AS_OBJECT, means masked and encrypted values are serialized as a json object.
isMultiMask false true: Enhanced the data masking capability to be dynamic using the separator property to identify each word separately and allowing masking each one. Example: H**** w****
false: The dynamic data masking is not allowed and the behavior will be as before Example: Hello******.
optional
separator " " With this property you can define the divisor character to use the multimask capability
optional

D. Use Custom ObjectMapper

Use the custom ObjectMapper, so, having this example of annotated class:

    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    public class Customer {
        private String name;

        @Mask(leftVisible = 3, rightVisible=4)
        private String email;

        @Mask(rightVisible=4, queryOnly=false, format=DataMaskingConstants.ENCRYPTION_AS_OBJECT)
        private String creditCardNumber;
    }

Serializing Process

An instance of example Customer annotated class:

    Customer customer = new Customer("Jhon Doe", 
        "jhon.doe123@someservice.com", 
        "4444555566665678");

Should be serialized as JSON like this:

String json = mapper.writeValueAsString(customer);
{
  "name": "Jhon Doe",
  "email": "Jho**************.com",
  "creditCardNumber": {
    "masked": "************5678",
    "enc": "dGhpcyBzaG91bGQgYmUgYW4gZWNyeXB0ZWQgdmFsdWUK"
  }
}

Deserializing Process

The deserialization process should construct an instance of the example Customer with is creditCardNumberproperty in plain text.

String json = "{\n" +
    "\"name\": \"Jhon Doe\",\n" +
    "\"email\": \"Jho**************.com\",\n" +
    "\"creditCardNumber\": {\n" +
    "\"masked\": \"************5678\",\n" +
    "\"enc\": \"dGhpcyBzaG91bGQgYmUgYW4gZWNyeXB0ZWQgdmFsdWUK\"\n" +
    "}\n" +
    "}";

Customer customer = mapper.readValue(json, Customer.class);
assertEquals("4444555566665678", customer.creditCardNumber());

E. Using library without POJO model

  • Transformation of Json

The library offers a funtionability for transform JSON without a model known. The transformations supported are Cyphering, Decyphering and Masking.

DISCLAIMER: This require high computer resources because it looping over JSON searching specific fields that we configurate.

  • How to configure specific field for cypher from JSON?

  • How to configure specific field for masking from JSON?

  • How to decypher a JSON previously cyphered?

1) Transforming obj(Any Json) with specific configuration explained in previos answers

2) Getting original obj previosly transformed

  • Can I use cyphering and masking in only one search?

AWS SDK integration

This library offers a concrete implementation for the DataCipher and DataDecipher interfaces called data-mask-aws which provides via the Aws crypto SDK and Secrets Manager for the encryption and decryption functionality.

Cloud Dependencies:

  • Secrets Manager for storing the symmetric key to configure the local AWS Crypto SDK

Using

With Gradle

implementation 'com.github.bancolombia:data-mask-aws:1.2.0'

With maven

<dependency>
  <groupId>com.github.bancolombia</groupId>
  <artifactId>data-mask-aws</artifactId>
  <version>1.2.0</version>
</dependency>

Additional configuration

Passed via configuration application.properties or application.yaml

Attribute Default value Description
secrets.dataMaskKey Name of the secret that holds the symmetric key in AWS Secrets manager.
Encryption key for data-masking should be at least 16 bytes. Other lengths supported for AES encryption are 24 and 32 bytes. Any given key greater than 16 bytes, and not multiple of 16, will be derived from first 16 bytes.
dataMask.encryptionContext "default_context" (Optional) The context for additional protection of the encrypted data. See Usage of Encryption contexts.
dataMask.keyId [blank] (Optional) The key Id
adapters.aws.secrets-manager.region Region for the Secrets Manager service
adapters.aws.secrets-manager.endpoint (Optional) for local dev only

Use with Spring-Boot

Just declare the customized Object Mapper as a Bean, and add @Primary annotation to use instead of the default ObjectMapper.

@Bean
@Primary
public ObjectMapper objectMapper(DataCipher awsCipher, DataDecipher awsDecipher) {
    return new MaskingObjectMapper(awsCipher, awsDecipher);
}

Then is all the same as described earlier in this guide in section C. Decorate-POJOs

Contribute

Please read our Code of conduct and Contributing Guide.

About

Utility library to use with Jackson-Databind to provide custom POJO/JSON serialization and deserialization aiming to protect sensitive data via masking with encrypting-decrypting.

Resources

License

Code of conduct

Security policy

Stars

Watchers

Forks

Packages

No packages published

Languages