0

I have a Spring Boot application that stores payment information in the database. The application has end-points

  • GET /api/orders - get orders by filter
  • POST /api/orders - add a new order
  • PUT /api/orders - update order
  • DELETE /api/orders - delete order

These endpoints are not secure itself, and I do not want to secure them on the application level. All traffic from the user goes to HTTPS proxy, which will decrypt it and forward to the application.

However, I use mongo atlas free version for prototyping https://www.mongodb.com/cloud/atlas/faq

All the data I put into the database must be encrypted. Even the document structure (fields names and types) must be encrypted.

How to encrypt a field does not work for me, because I want to encrypt the whole document. I do not want to use unofficial libraries like bellow (thus no one guarantees if the library is secure)

<dependency>
   <groupId>com.bol</groupId>
   <artifactId>spring-data-mongodb-encrypt</artifactId>
   <version>1.3.0</version>
</dependency>

One idea that came to me is to configure the application to use a password (somehow configured or generated at given moment of time).

/**
* Provides a password to encrypt a document.
**/
// TODO  How to do it better? I still have to improve it.
@Component
public class PasswordProviderImpl implements PasswordProvider {
    
    private static final byte[] MASTER_PASSWORD = {1, 11, 37, 166, 11, 77};

    @Autowired
    private Environment environment;

    // I do not care about the implementation yet
    public char [] getPassword() {
        final byte[] envPassword = environment.getProperty("appplicationPassword").toString().toByteArray();
        return envPassword;
    }
}
/**
* Encrypts input byte array with provided password, afterwards, cleans input data and password - populates them with zeros - 0.
**/
@Component
public class Encryptor {
    private PasswordProvider passwordProvider;

    public byte [] encrypt(final byte unecrypted) {
        final byte [] password = passwordProvider.getPassword();
        final byte [] encrypted = xor(unecrypted, password);
        makeZeros(password);
        makeZeros(unecrypted);
        return encrypted;
    }
    
    private void makeZeros(final byte[] array) { /*Implementation*/}
    private byte[] xor(final byte [] arg1, final byte[] arg2) {/*Implementation*/}
}
/**
* Represents a unit of data in my application. Its values and fields and structure - everything should be encrypted.
**/
public class Order {
    private ObjectId id;
    private Instant createdDate;
    private Instant updatedDate;
    private Money amount;
    private String additionalDetails;

    // gettters, setters, constructor
}

Converter, found Set MongoDb converter programmatically

/**
* It is declared application configuration. It defines how to store {@link Order} in mongodb
**/
@Component
public OrderConverter implements onverter<Order, SecuredOrder> {
    
    private ObjectMapper objectMapper;
    private Encryptor encryptor;
    private Base64Converter base64Converter;

    @Override 
    public SecuredOrder convert(Order source) { 
        final String json = objectMapper.writeValueAsString(source);
        final unencrypted = json.toByteArray();
        final byte[] encrypted = encryptor.encrypt(unencrypted);
        final String payload = base64Converter.toBase64(encrypted);
        return SecuredOrder.of(order.getId(), payload);
    }
}
public class SecuredOrder {
    private ObjectId id; // same as in order id
    private String encryptedPayload; // The converter will make it
}

@Service
public OrderService {
    public void saveOrder(Order order) {
        orderRepository.save(order);
    }
}

If you have done a similar thing, please give me a direction. I would really like to do it properly.

Also, mongodb provides encryption mechanism, so maybe I should use it?

https://docs.mongodb.com/manual/core/security-encryption-at-rest/

https://docs.mongodb.com/manual/core/security-encryption-at-rest/#encrypted-storage-engine

Yan Khonski
  • 12,225
  • 15
  • 76
  • 114
  • You say 'thus no one guarantees if the library is secure', but then copy random code snippets from the internet... BTW the spring-data-mongodb-encrypt library does exactly what you want, you just put your data in a sub-document and mark the field with @Encrypted, but up to you if you prefer homecooked solutions to opensource ones. – Agoston Horvath Aug 18 '21 at 13:58
  • OK, I was confused with the library group id bol (I had not know that company before). How did I know who will mainaint the library? I see it a company that open sourced some their solutions. And the company is known and will care about their reputation. – Yan Khonski Aug 18 '21 at 19:53

1 Answers1

2

If you're able to use the WiredTiger storage engine and you are using MongoDB 3.2 or above, you can utilize it's Encryption at Rest capability (as you mentioned at the bottom of your post!), but be advised this is available for the enterprise version only.

Eric Green
  • 1,151
  • 9
  • 17