Post

2024-08-20-TIL

2024-08-20-TIL

Today I Learned

Spring Data JPA and Interface Projections

인터페이스 프로젝션을 사용했더니 배치에서 성능이 현저히 떨어진 것을 확인할 수 있었다. GC가 안되어서 메모리 용량이 부족해진 것일까?

  • https://www.youtube.com/watch?v=XtpZvD8zt9w
  • https://stackoverflow.com/questions/52380365/best-practices-with-interface-projections-for-jpa-repository-in-spring
  • https://medium.com/javarevisited/mastering-projections-in-spring-data-jpa-a-comprehensive-introduction-7bc2e64e4c14
  • https://docs.spring.io/spring-data/jpa/reference/repositories/projections.html
  • https://vladmihalcea.com/spring-jpa-dto-projection/

CQRS Pattern

  • https://learn.microsoft.com/en-us/azure/architecture/patterns/cqrs
  • https://microservices.io/patterns/data/cqrs.html
  • https://microservices.io/patterns/data/cqrs.html

Redact?

edit (text) for publication.

  • https://stackoverflow.com/questions/61569702/graphql-best-practice-on-redacting-fields-that-require-authorization
  • https://cloud.google.com/sensitive-data-protection/docs/redacting-sensitive-data?hl=ko
  • https://naveen-metta.medium.com/secure-your-data-masking-sensitive-information-in-spring-boot-apis-2d66fb5d09cd
  • https://docs.spring.io/spring-data/mongodb/docs/current/api/org/springframework/data/mongodb/core/aggregation/RedactOperation.html
  • https://stackoverflow.com/questions/61569702/graphql-best-practice-on-redacting-fields-that-require-authorization
  • https://docs.axway.com/bundle/axway-open-docs/page/docs/apim_administration/apigtw_admin/admin_redactors/index.html
  • https://fastercapital.com/topics/best-practices-for-redacting-sensitive-data.html
  • https://stackoverflow.blog/2020/03/02/best-practices-for-rest-api-design/
  • https://softwareengineering.stackexchange.com/questions/438401/in-restful-apis-whats-the-proper-way-to-have-different-resource-properties-bas

Redacting sensitive fields in a REST API is crucial to ensure that confidential or personally identifiable information (PII) is not exposed unintentionally. Here are some best practices for redacting fields in REST APIs:

1. Identify Sensitive Data

  • Classify Data: Identify fields that contain sensitive information, such as passwords, social security numbers, credit card details, API keys, and personal data like addresses, phone numbers, and email addresses.
  • Data Mapping: Create a mapping of the data model to track which fields should be redacted.

2. Implement Redaction at the Source

  • Data Sanitization: Ensure that sensitive data is either not stored in the first place (if not necessary) or stored in a sanitized format, like hashing passwords.
  • Data Masking: For certain fields, implement masking at the source level, such as storing only the last four digits of a credit card number.

3. Control Redaction Based on Context

  • Role-Based Access Control (RBAC): Implement RBAC to ensure that only authorized users can access sensitive data. Redact fields for users who do not have the necessary permissions.
  • Contextual Redaction: Based on the request context (e.g., API client type, environment), redact certain fields dynamically.

4. Use Secure Serialization Libraries

  • Custom Serializers: Implement custom serializers or filters in your API framework to automatically redact or mask sensitive fields before sending a response.
  • Annotations/Attributes: Use annotations (e.g., @JsonIgnore, @SensitiveField) to mark fields that should be redacted. Many frameworks allow you to define these annotations for automatic handling during serialization.

5. Logging and Monitoring

  • Redacted Logging: Ensure that logging mechanisms also redact sensitive fields to prevent leaks through logs. This includes using tools that support sensitive data redaction in logs.
  • Audit Trails: Maintain audit logs to track who accessed or attempted to access sensitive data.

6. Data Encryption

  • In-Transit Encryption: Use TLS/SSL to encrypt data in transit, ensuring that sensitive fields are not exposed over the network.
  • At-Rest Encryption: Encrypt sensitive data at rest to protect it from unauthorized access.

7. Response Redaction Techniques

  • Response Filters: Implement response filters that scan outgoing API responses and redact sensitive fields before they reach the client.
  • Partial Redaction: Instead of completely removing sensitive fields, consider partial redaction (e.g., replacing all but the last four characters with *).

8. Secure API Documentation

  • Avoid Sensitive Data in Examples: Ensure that API documentation does not expose real or sensitive data in example requests and responses.
  • Dynamic Documentation: If your API documentation is auto-generated, implement redaction rules to ensure sensitive fields are not shown.

9. Testing and Validation

  • Automated Tests: Implement automated tests to ensure that sensitive fields are correctly redacted in all API responses.
  • Manual Review: Periodically review API responses to check for any sensitive data exposure.

10. Compliance

  • Legal Requirements: Ensure that your redaction practices comply with relevant data protection laws (e.g., GDPR, CCPA). This might involve special handling for PII and sensitive personal data.
  • Security Audits: Regularly audit your API for compliance with security standards and best practices.

11. Versioning and Deprecation

  • Version Control: When introducing new redaction policies or modifying existing ones, use API versioning to prevent breaking changes.
  • Graceful Deprecation: Deprecate old fields or APIs in a way that gives clients time to adapt, ensuring that sensitive data isn’t exposed in the process.

12. Client-Side Best Practices

  • Client Filtering: Encourage or enforce client-side filtering of sensitive fields, especially when dealing with third-party integrations.
  • Educate Clients: Provide guidelines for clients on how to handle and store sensitive data securely.

By following these best practices, you can ensure that sensitive data is adequately protected in your REST APIs, minimizing the risk of data breaches and ensuring compliance with security standards.


Certainly! Here’s an example of how to redact sensitive fields in a REST API using Spring Boot and Spring Security.

Scenario:

Let’s assume we have a User entity that contains sensitive information like password and socialSecurityNumber. We want to ensure these fields are redacted in the API responses.

Step 1: Define the User Entity

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
package com.example.demo.model;

import com.fasterxml.jackson.annotation.JsonIgnore;

public class User {

    private Long id;
    private String username;

    @JsonIgnore // This will prevent serialization of the password field
    private String password;

    private String email;

    // Custom annotation to mark sensitive fields
    @SensitiveField
    private String socialSecurityNumber;

    // Getters and Setters
    // ...
}

Step 2: Create a Custom Annotation for Sensitive Fields

Create an annotation called @SensitiveField to mark fields that need to be redacted.

1
2
3
4
5
6
7
8
package com.example.demo.security;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

@Retention(RetentionPolicy.RUNTIME)
public @interface SensitiveField {
}

Step 3: Implement a Custom Serializer

Use a custom serializer to automatically redact fields annotated with @SensitiveField.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
package com.example.demo.security;

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.ser.std.StdSerializer;

import java.io.IOException;
import java.lang.reflect.Field;

public class SensitiveFieldSerializer extends StdSerializer<Object> {

    public SensitiveFieldSerializer() {
        this(null);
    }

    public SensitiveFieldSerializer(Class<Object> t) {
        super(t);
    }

    @Override
    public void serialize(Object value, JsonGenerator gen, SerializerProvider provider) throws IOException {
        gen.writeStartObject();
        Field[] fields = value.getClass().getDeclaredFields();

        for (Field field : fields) {
            field.setAccessible(true);
            try {
                Object fieldValue = field.get(value);
                if (field.isAnnotationPresent(SensitiveField.class)) {
                    gen.writeStringField(field.getName(), "REDACTED");
                } else {
                    gen.writeObjectField(field.getName(), fieldValue);
                }
            } catch (IllegalAccessException e) {
                // Handle exception
            }
        }
        gen.writeEndObject();
    }
}

Step 4: Configure Jackson to Use the Custom Serializer

Configure Jackson to use the custom serializer globally.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
package com.example.demo.config;

import com.example.demo.security.SensitiveFieldSerializer;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.module.SimpleModule;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class JacksonConfig {

    @Bean
    public ObjectMapper objectMapper() {
        ObjectMapper objectMapper = new ObjectMapper();
        SimpleModule module = new SimpleModule();
        module.addSerializer(Object.class, new SensitiveFieldSerializer());
        objectMapper.registerModule(module);
        return objectMapper;
    }
}

Step 5: Create a Controller to Test the Redaction

Now, create a simple controller to expose the User data via a REST API.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package com.example.demo.controller;

import com.example.demo.model.User;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/api/users")
public class UserController {

    @GetMapping("/me")
    public User getCurrentUser() {
        User user = new User();
        user.setId(1L);
        user.setUsername("john_doe");
        user.setPassword("password123");
        user.setEmail("john.doe@example.com");
        user.setSocialSecurityNumber("123-45-6789");

        return user;
    }
}

Step 6: Test the API

When you call the /api/users/me endpoint, the response should look like this:

1
2
3
4
5
6
{
    "id": 1,
    "username": "john_doe",
    "email": "john.doe@example.com",
    "socialSecurityNumber": "REDACTED"
}

Explanation:

  • Password Redaction: The @JsonIgnore annotation on the password field prevents it from being serialized in the JSON response.
  • Custom Redaction: The SensitiveFieldSerializer checks for the @SensitiveField annotation and redacts any marked fields by replacing their values with "REDACTED".

Step 7: Secure Access Based on Roles (Optional)

If you want to secure access to this data based on roles or other security criteria, you can integrate Spring Security with Role-Based Access Control (RBAC).

Here’s an example configuration:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
package com.example.demo.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.web.SecurityFilterChain;

@Configuration
@EnableWebSecurity
public class SecurityConfig {

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http
            .authorizeRequests(authorizeRequests ->
                authorizeRequests
                    .antMatchers("/api/users/me").authenticated()
                    .anyRequest().permitAll()
            )
            .httpBasic();

        return http.build();
    }
}

In this setup, only authenticated users can access the /api/users/me endpoint.

Conclusion

This example demonstrates how to use Spring Boot and Spring Security to redact sensitive fields in API responses, ensuring sensitive information is not exposed unintentionally.

This post is licensed under CC BY 4.0 by the author.