Configuration Hardening in Java: Complete Security Guide

Introduction to Configuration Hardening

Configuration hardening involves securing application configurations to minimize attack surfaces and prevent security vulnerabilities. This comprehensive guide covers security best practices for Java applications, including environment-specific configurations, security headers, encryption, and compliance standards.

Core Security Configuration

Application Properties Security

application-security.yml

# Primary security configuration
spring:
application:
name: secure-java-app
# Security: Do not expose build information
build:
info:
enabled: false
# Security: Disable autoconfiguration for sensitive components
autoconfigure:
exclude:
- org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration
- org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration
# Security: Servlet configuration
servlet:
multipart:
max-file-size: 10MB
max-request-size: 10MB
enabled: true
# Security: Jackson configuration
jackson:
default-property-inclusion: non_null
deserialization:
fail-on-unknown-properties: true
parser:
allow-unquoted-control-chars: false
allow-comments: false
visibility:
field: any
getter: none
setter: none
creator: none
# Security: JPA configuration
jpa:
show-sql: false
properties:
hibernate:
format_sql: false
use_sql_comments: false
jdbc:
lob:
non_contextual_creation: true
# Security: Disable automatic DDL generation
hbm2ddl:
auto: validate
# Security: Data source configuration
datasource:
# Security: Use environment variables for credentials
url: ${DB_URL:jdbc:h2:mem:testdb}
username: ${DB_USERNAME:sa}
password: ${DB_PASSWORD:}
hikari:
connection-timeout: 30000
maximum-pool-size: 10
minimum-idle: 2
max-lifetime: 1800000
leak-detection-threshold: 60000
# Security: Mail configuration
mail:
properties:
mail:
smtp:
auth: true
starttls:
enable: true
# Security: Cache configuration
cache:
type: simple
cache-names:
- security-tokens
- rate-limits
caffeine:
spec: maximumSize=1000,expireAfterWrite=300s
# Security: Session configuration
session:
store-type: none
timeout: 1800
servlet:
filter-order: 100
# Security: Web configuration
web:
resources:
add-mappings: false
locale-resolver: fixed
# Security: Messages configuration
messages:
encoding: UTF-8
cache-duration: 3600
# Security: Server configuration
server:
# Security: Server information hiding
server-header: ""
# Security: Port configuration
port: ${SERVER_PORT:8080}
# Security: SSL/TLS configuration
ssl:
enabled: ${SSL_ENABLED:false}
key-store: ${SSL_KEY_STORE:}
key-store-password: ${SSL_KEY_STORE_PASSWORD:}
key-store-type: ${SSL_KEY_STORE_TYPE:PKCS12}
key-alias: ${SSL_KEY_ALIAS:}
protocol: TLS
enabled-protocols: TLSv1.2,TLSv1.3
ciphers: TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
# Security: Servlet configuration
servlet:
context-path: /
session:
cookie:
http-only: true
secure: ${COOKIE_SECURE:true}
max-age: 1800
same-site: strict
name: SESSION
encoding:
charset: UTF-8
enabled: true
force: true
# Security: HTTP configuration
http2:
enabled: true
compression:
enabled: true
mime-types: text/html,text/xml,text/plain,text/css,text/javascript,application/javascript,application/json
min-response-size: 1024
# Security: Hide server version
error:
include-stacktrace: never
include-message: never
include-binding-errors: never
include-exception: false
# Security: Connection timeout
connection-timeout: 30000
# Security: Maximum HTTP header size
max-http-header-size: 8KB
# Security: Logging configuration
logging:
level:
# Security: Reduce sensitive logging
com.example.secure: INFO
org.springframework.security: WARN
org.springframework.web: WARN
org.hibernate: WARN
# Security: Disable sensitive SQL logging
org.hibernate.SQL: ERROR
org.hibernate.type.descriptor.sql.BasicBinder: ERROR
# Security: Log file configuration
file:
name: /var/log/secure-app/application.log
max-size: 10MB
max-history: 30
total-size-cap: 1GB
pattern:
# Security: Avoid logging sensitive information
file: "%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %mask%msg%n"
console: "%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %mask%msg%n"
# Security: Actuator endpoints configuration
management:
endpoints:
web:
exposure:
# Security: Limit exposed endpoints
include: health,info,metrics,prometheus
exclude: env,beans,configprops,dump,heapdump,threaddump,shutdown
# Security: Custom management port
base-path: /management
enabled-by-default: false
jmx:
exposure:
exclude: "*"
endpoint:
health:
enabled: true
show-details: when_authorized
show-components: when_authorized
probes:
enabled: true
info:
enabled: true
metrics:
enabled: true
prometheus:
enabled: true
# Security: Disable sensitive endpoints
env:
enabled: false
beans:
enabled: false
configprops:
enabled: false
dump:
enabled: false
heapdump:
enabled: false
threaddump:
enabled: false
shutdown:
enabled: false
# Security: Management server configuration
server:
port: ${MANAGEMENT_PORT:8081}
address: 127.0.0.1
ssl:
enabled: true
# Security: Custom application security configuration
app:
security:
# Security: JWT configuration
jwt:
secret: ${JWT_SECRET:}
expiration: 3600
issuer: secure-java-app
audience: secure-users
# Security: CORS configuration
cors:
allowed-origins: ${ALLOWED_ORIGINS:https://localhost:3000,https://example.com}
allowed-methods: GET,POST,PUT,DELETE,OPTIONS
allowed-headers: Authorization,Content-Type,X-Requested-With
allow-credentials: true
max-age: 3600
# Security: Rate limiting
rate-limit:
enabled: true
requests-per-minute: 100
burst-capacity: 20
# Security: Password policy
password:
min-length: 12
require-uppercase: true
require-lowercase: true
require-digits: true
require-special-chars: true
max-age-days: 90
history-size: 5
# Security: Session management
session:
max-sessions-per-user: 1
prevent-session-fixation: true
# Security: Encryption configuration
encryption:
algorithm: AES/GCM/NoPadding
key-size: 256
iv-size: 96
salt-size: 128
# Security: Database encryption
encryption:
enabled: true
algorithm: AES
key: ${ENCRYPTION_KEY:}
salt: ${ENCRYPTION_SALT:}

Environment-Specific Configurations

application-development.yml

# Development environment configuration
spring:
config:
activate:
on-profile: development
# Security: Development-specific relaxations
security:
require-ssl: false
# Security: Development database
datasource:
url: jdbc:h2:mem:devdb
username: devuser
password: devpass
hikari:
maximum-pool-size: 5
# Security: Development logging
jackson:
serialization:
indent-output: true
jpa:
show-sql: true
properties:
hibernate:
format_sql: true
hbm2ddl:
auto: create-drop
# Security: Development server
server:
ssl:
enabled: false
servlet:
session:
cookie:
secure: false
# Security: Development logging
logging:
level:
com.example.secure: DEBUG
org.springframework.security: DEBUG
org.hibernate.SQL: DEBUG
org.hibernate.type.descriptor.sql.BasicBinder: TRACE
# Security: Development endpoints
management:
endpoints:
web:
exposure:
include: "*"
endpoint:
health:
show-details: always
env:
enabled: true
beans:
enabled: true
app:
security:
rate-limit:
enabled: false

application-production.yml

# Production environment configuration
spring:
config:
activate:
on-profile: production
# Security: Production database
datasource:
url: ${DB_URL}
username: ${DB_USERNAME}
password: ${DB_PASSWORD}
hikari:
maximum-pool-size: 20
minimum-idle: 5
leak-detection-threshold: 120000
# Security: Production JPA
jpa:
properties:
hibernate:
hbm2ddl:
auto: validate
jdbc:
batch_size: 50
order_inserts: true
order_updates: true
# Security: Production cache
cache:
type: redis
redis:
time-to-live: 3600s
cache-null-values: false
# Security: Production server
server:
ssl:
enabled: true
key-store: ${SSL_KEY_STORE}
key-store-password: ${SSL_KEY_STORE_PASSWORD}
servlet:
session:
timeout: 1800
cookie:
secure: true
same-site: strict
# Security: Production logging
logging:
level:
com.example.secure: INFO
org.springframework: WARN
org.hibernate: ERROR
file:
name: /var/log/secure-app/production.log
# Security: Production management
management:
endpoints:
web:
exposure:
include: health,info,metrics
jmx:
enabled: false
endpoint:
health:
show-details: never
app:
security:
rate-limit:
enabled: true
requests-per-minute: 60
burst-capacity: 10
session:
max-sessions-per-user: 1

Security Configuration Classes

Main Security Configuration

package com.example.secure.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.actuate.autoconfigure.security.servlet.EndpointRequest;
import org.springframework.boot.actuate.health.HealthEndpoint;
import org.springframework.boot.actuate.info.InfoEndpoint;
import org.springframework.boot.actuate.metrics.export.prometheus.PrometheusScrapeEndpoint;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import java.util.Arrays;
import java.util.List;
/**
* Main security configuration with comprehensive hardening
*/
@Configuration
@EnableWebSecurity
@EnableMethodSecurity(
prePostEnabled = true,
securedEnabled = true,
jsr250Enabled = true
)
public class SecurityConfig {
@Value("${app.security.cors.allowed-origins}")
private String[] allowedOrigins;
@Value("${app.security.cors.allowed-methods}")
private String[] allowedMethods;
@Value("${app.security.cors.allowed-headers}")
private String[] allowedHeaders;
@Value("${app.security.cors.allow-credentials}")
private boolean allowCredentials;
@Value("${app.security.cors.max-age}")
private long maxAge;
@Autowired
private JwtAuthenticationFilter jwtAuthenticationFilter;
@Autowired
private SecurityProperties securityProperties;
/**
* Password encoder with secure configuration
*/
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder(12); // High cost factor for better security
}
/**
* Authentication manager
*/
@Bean
public AuthenticationManager authenticationManager(
AuthenticationConfiguration authenticationConfiguration) throws Exception {
return authenticationConfiguration.getAuthenticationManager();
}
/**
* Security filter chain with comprehensive hardening
*/
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
// Disable CSRF for stateless API (handled by JWT)
.csrf(csrf -> csrf.disable())
// CORS configuration
.cors(cors -> cors.configurationSource(corsConfigurationSource()))
// Session management - stateless
.sessionManagement(session -> session
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
)
// Authorization rules
.authorizeHttpRequests(authz -> authz
// Public endpoints
.requestMatchers(
"/api/auth/login",
"/api/auth/register",
"/api/public/**",
"/error"
).permitAll()
// Actuator endpoints with role-based access
.requestMatchers(EndpointRequest.to(HealthEndpoint.class)).permitAll()
.requestMatchers(EndpointRequest.to(InfoEndpoint.class)).permitAll()
.requestMatchers(EndpointRequest.to(PrometheusScrapeEndpoint.class)).hasRole("MONITORING")
// All other endpoints require authentication
.anyRequest().authenticated()
)
// Security headers
.headers(headers -> headers
// Content Security Policy
.contentSecurityPolicy(csp -> csp
.policyDirectives("default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; font-src 'self'; connect-src 'self'; media-src 'self'; object-src 'none'; child-src 'self'; frame-ancestors 'none'; form-action 'self'; base-uri 'self'; manifest-src 'self'")
)
// HTTP Strict Transport Security
.httpStrictTransportSecurity(hsts -> hsts
.includeSubDomains(true)
.preload(true)
.maxAgeInSeconds(31536000) // 1 year
)
// Frame options
.frameOptions(frame -> frame
.deny()
)
// XSS Protection
.xssProtection(xss -> xss
.headerValue(org.springframework.security.web.header.writers.XXssProtectionHeaderWriter.HeaderValue.ENABLED_MODE_BLOCK)
)
// Content Type options
.contentTypeOptions(contentType -> contentType
.disable() // Spring Security enables this by default
)
// Referrer Policy
.referrerPolicy(referrer -> referrer
.policy(org.springframework.security.web.header.writers.ReferrerPolicyHeaderWriter.ReferrerPolicy.STRICT_ORIGIN_WHEN_CROSS_ORIGIN)
)
// Permissions Policy
.permissionsPolicy(permissions -> permissions
.policy("geolocation=(), microphone=(), camera=(), payment=()")
)
)
// JWT filter
.addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class)
// Exception handling
.exceptionHandling(exception -> exception
.authenticationEntryPoint(new JwtAuthenticationEntryPoint())
.accessDeniedHandler(new JwtAccessDeniedHandler())
);
return http.build();
}
/**
* CORS configuration source
*/
@Bean
public CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration configuration = new CorsConfiguration();
// Set allowed origins
configuration.setAllowedOrigins(Arrays.asList(allowedOrigins));
// Set allowed methods
configuration.setAllowedMethods(Arrays.asList(allowedMethods));
// Set allowed headers
configuration.setAllowedHeaders(Arrays.asList(allowedHeaders));
// Set exposed headers
configuration.setExposedHeaders(Arrays.asList(
"Authorization", 
"X-Request-ID",
"X-Rate-Limit-Remaining"
));
// Set allow credentials
configuration.setAllowCredentials(allowCredentials);
// Set max age
configuration.setMaxAge(maxAge);
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/api/**", configuration);
return source;
}
/**
* Development-specific security configuration
*/
@Configuration
@Profile("development")
public static class DevelopmentSecurityConfig {
@Bean
public SecurityFilterChain developmentSecurityFilterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests(authz -> authz
// Allow access to development endpoints
.requestMatchers(
"/h2-console/**",
"/actuator/**",
"/swagger-ui/**",
"/v3/api-docs/**"
).permitAll()
)
// Allow H2 console in development
.headers(headers -> headers
.frameOptions(frame -> frame.sameOrigin())
)
.csrf(csrf -> csrf
.ignoringRequestMatchers("/h2-console/**")
);
return http.build();
}
}
}

JWT Security Configuration

package com.example.secure.config;
import com.example.secure.security.JwtAuthenticationFilter;
import com.example.secure.security.JwtTokenProvider;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.crypto.password.PasswordEncoder;
import java.security.Key;
import java.util.Base64;
import javax.crypto.spec.SecretKeySpec;
/**
* JWT Security Configuration
*/
@Configuration
public class JwtSecurityConfig {
@Value("${app.security.jwt.secret}")
private String jwtSecret;
@Value("${app.security.jwt.expiration}")
private long jwtExpiration;
@Value("${app.security.jwt.issuer}")
private String jwtIssuer;
@Value("${app.security.jwt.audience}")
private String jwtAudience;
/**
* JWT token provider
*/
@Bean
public JwtTokenProvider jwtTokenProvider(PasswordEncoder passwordEncoder, ObjectMapper objectMapper) {
Key key = new SecretKeySpec(
Base64.getDecoder().decode(jwtSecret),
"HmacSHA512"
);
return new JwtTokenProvider(
key,
jwtExpiration,
jwtIssuer,
jwtAudience,
passwordEncoder,
objectMapper
);
}
/**
* JWT authentication filter
*/
@Bean
public JwtAuthenticationFilter jwtAuthenticationFilter(JwtTokenProvider jwtTokenProvider) {
return new JwtAuthenticationFilter(jwtTokenProvider);
}
}

Encryption Configuration

package com.example.secure.config;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.GCMParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.Base64;
/**
* Encryption configuration for data protection
*/
@Configuration
public class EncryptionConfig {
@Value("${app.security.encryption.algorithm:AES/GCM/NoPadding}")
private String encryptionAlgorithm;
@Value("${app.security.encryption.key-size:256}")
private int keySize;
@Value("${app.security.encryption.iv-size:96}")
private int ivSize;
@Value("${app.security.encryption.salt-size:128}")
private int saltSize;
@Value("${encryption.key:}")
private String encryptionKey;
@Value("${encryption.salt:}")
private String encryptionSalt;
/**
* Encryption service for sensitive data
*/
@Bean
public EncryptionService encryptionService() throws NoSuchAlgorithmException {
SecretKey secretKey;
if (encryptionKey != null && !encryptionKey.isEmpty()) {
// Use configured key
byte[] keyBytes = Base64.getDecoder().decode(encryptionKey);
secretKey = new SecretKeySpec(keyBytes, "AES");
} else {
// Generate new key (for development only)
KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
keyGenerator.init(keySize);
secretKey = keyGenerator.generateKey();
}
return new EncryptionService(
secretKey,
encryptionAlgorithm,
ivSize,
saltSize
);
}
/**
* Secure random number generator
*/
@Bean
public SecureRandom secureRandom() {
return new SecureRandom();
}
/**
* Encryption service implementation
*/
public static class EncryptionService {
private final SecretKey secretKey;
private final String algorithm;
private final int ivSize;
private final int saltSize;
private final SecureRandom secureRandom;
public EncryptionService(SecretKey secretKey, String algorithm, int ivSize, int saltSize) {
this.secretKey = secretKey;
this.algorithm = algorithm;
this.ivSize = ivSize;
this.saltSize = saltSize;
this.secureRandom = new SecureRandom();
}
public String encrypt(String plaintext) throws Exception {
byte[] iv = new byte[ivSize / 8];
secureRandom.nextBytes(iv);
Cipher cipher = Cipher.getInstance(algorithm);
GCMParameterSpec parameterSpec = new GCMParameterSpec(128, iv);
cipher.init(Cipher.ENCRYPT_MODE, secretKey, parameterSpec);
byte[] ciphertext = cipher.doFinal(plaintext.getBytes());
byte[] encrypted = new byte[iv.length + ciphertext.length];
System.arraycopy(iv, 0, encrypted, 0, iv.length);
System.arraycopy(ciphertext, 0, encrypted, iv.length, ciphertext.length);
return Base64.getEncoder().encodeToString(encrypted);
}
public String decrypt(String encrypted) throws Exception {
byte[] decoded = Base64.getDecoder().decode(encrypted);
byte[] iv = new byte[ivSize / 8];
System.arraycopy(decoded, 0, iv, 0, iv.length);
Cipher cipher = Cipher.getInstance(algorithm);
GCMParameterSpec parameterSpec = new GCMParameterSpec(128, iv);
cipher.init(Cipher.DECRYPT_MODE, secretKey, parameterSpec);
byte[] ciphertext = new byte[decoded.length - iv.length];
System.arraycopy(decoded, iv.length, ciphertext, 0, ciphertext.length);
byte[] plaintext = cipher.doFinal(ciphertext);
return new String(plaintext);
}
public byte[] generateSalt() {
byte[] salt = new byte[saltSize / 8];
secureRandom.nextBytes(salt);
return salt;
}
}
}

Security Headers Configuration

Custom Security Headers Filter

package com.example.secure.config;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
/**
* Custom security headers configuration
*/
@Configuration
public class SecurityHeadersConfig {
/**
* Custom security headers filter
*/
@Bean
public FilterRegistrationBean<SecurityHeadersFilter> securityHeadersFilter() {
FilterRegistrationBean<SecurityHeadersFilter> registrationBean = 
new FilterRegistrationBean<>();
registrationBean.setFilter(new SecurityHeadersFilter());
registrationBean.addUrlPatterns("/*");
registrationBean.setOrder(Ordered.HIGHEST_PRECEDENCE);
return registrationBean;
}
/**
* Custom security headers filter implementation
*/
public static class SecurityHeadersFilter implements Filter {
private final Map<String, String> securityHeaders = new HashMap<>();
public SecurityHeadersFilter() {
// Security headers configuration
securityHeaders.put("X-Content-Type-Options", "nosniff");
securityHeaders.put("X-Frame-Options", "DENY");
securityHeaders.put("X-XSS-Protection", "1; mode=block");
securityHeaders.put("Referrer-Policy", "strict-origin-when-cross-origin");
securityHeaders.put("Permissions-Policy", "geolocation=(), microphone=(), camera=()");
securityHeaders.put("X-Permitted-Cross-Domain-Policies", "none");
securityHeaders.put("X-Download-Options", "noopen");
securityHeaders.put("X-DNS-Prefetch-Control", "off");
securityHeaders.put("Strict-Transport-Security", "max-age=31536000; includeSubDomains; preload");
// Custom headers
securityHeaders.put("X-Request-ID", "");
securityHeaders.put("X-Runtime", "");
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, 
FilterChain chain) throws IOException, ServletException {
HttpServletRequest httpRequest = (HttpServletRequest) request;
HttpServletResponse httpResponse = (HttpServletResponse) response;
// Add security headers
securityHeaders.forEach((key, value) -> {
if (!httpResponse.containsHeader(key)) {
if (key.equals("X-Request-ID")) {
// Generate unique request ID
String requestId = java.util.UUID.randomUUID().toString();
httpResponse.setHeader(key, requestId);
} else if (key.equals("X-Runtime")) {
// Will be set after processing
} else {
httpResponse.setHeader(key, value);
}
}
});
// Measure processing time
long startTime = System.currentTimeMillis();
try {
chain.doFilter(request, response);
} finally {
long endTime = System.currentTimeMillis();
httpResponse.setHeader("X-Runtime", String.valueOf(endTime - startTime));
}
}
@Override
public void init(FilterConfig filterConfig) throws ServletException {
// Initialization logic if needed
}
@Override
public void destroy() {
// Cleanup logic if needed
}
}
}

Rate Limiting Configuration

package com.example.secure.config;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import java.util.concurrent.TimeUnit;
/**
* Rate limiting configuration
*/
@Configuration
public class RateLimitingConfig {
@Value("${app.security.rate-limit.enabled:true}")
private boolean rateLimitEnabled;
@Value("${app.security.rate-limit.requests-per-minute:100}")
private int requestsPerMinute;
@Value("${app.security.rate-limit.burst-capacity:20}")
private int burstCapacity;
/**
* Rate limiting service
*/
@Bean
public RateLimitingService rateLimitingService(RedisTemplate<String, Object> redisTemplate) {
return new RateLimitingService(
redisTemplate,
rateLimitEnabled,
requestsPerMinute,
burstCapacity
);
}
/**
* Redis template for rate limiting
*/
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory connectionFactory) {
RedisTemplate<String, Object> template = new RedisTemplate<>();
template.setConnectionFactory(connectionFactory);
template.setKeySerializer(new StringRedisSerializer());
template.setValueSerializer(new GenericJackson2JsonRedisSerializer());
template.setHashKeySerializer(new StringRedisSerializer());
template.setHashValueSerializer(new GenericJackson2JsonRedisSerializer());
template.setEnableTransactionSupport(true);
return template;
}
/**
* Rate limiting service implementation
*/
public static class RateLimitingService {
private final RedisTemplate<String, Object> redisTemplate;
private final boolean enabled;
private final int requestsPerMinute;
private final int burstCapacity;
public RateLimitingService(RedisTemplate<String, Object> redisTemplate, 
boolean enabled, int requestsPerMinute, int burstCapacity) {
this.redisTemplate = redisTemplate;
this.enabled = enabled;
this.requestsPerMinute = requestsPerMinute;
this.burstCapacity = burstCapacity;
}
public boolean isAllowed(String clientId, String endpoint) {
if (!enabled) {
return true;
}
String key = String.format("rate_limit:%s:%s", clientId, endpoint);
long currentTime = System.currentTimeMillis();
long windowSize = TimeUnit.MINUTES.toMillis(1);
// Get current count
Long currentCount = redisTemplate.opsForValue().increment(key, 1);
if (currentCount == 1) {
// First request in this window, set expiration
redisTemplate.expire(key, windowSize, TimeUnit.MILLISECONDS);
}
return currentCount <= requestsPerMinute;
}
public RateLimitInfo getRateLimitInfo(String clientId, String endpoint) {
String key = String.format("rate_limit:%s:%s", clientId, endpoint);
Long currentCount = redisTemplate.opsForValue().increment(key, 0); // Get without incrementing
if (currentCount == null) {
currentCount = 0L;
}
long remaining = Math.max(0, requestsPerMinute - currentCount);
long resetTime = System.currentTimeMillis() + TimeUnit.MINUTES.toMillis(1);
return new RateLimitInfo(remaining, resetTime);
}
}
/**
* Rate limit information
*/
public static class RateLimitInfo {
private final long remaining;
private final long resetTime;
public RateLimitInfo(long remaining, long resetTime) {
this.remaining = remaining;
this.resetTime = resetTime;
}
public long getRemaining() { return remaining; }
public long getResetTime() { return resetTime; }
}
}

Logging Security Configuration

Secure Logging Configuration

package com.example.secure.config;
import ch.qos.logback.classic.PatternLayout;
import ch.qos.logback.classic.spi.ILoggingEvent;
import ch.qos.logback.core.pattern.PatternLayoutEncoderBase;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.regex.Pattern;
/**
* Secure logging configuration
*/
@Configuration
public class LoggingSecurityConfig {
/**
* Pattern layout with sensitive data masking
*/
@Bean
public PatternLayoutEncoderBase<ILoggingEvent> patternLayoutEncoder() {
return new SecurePatternLayoutEncoder();
}
/**
* Secure pattern layout that masks sensitive information
*/
public static class SecurePatternLayoutEncoder extends PatternLayoutEncoderBase<ILoggingEvent> {
private static final Pattern SENSITIVE_PATTERNS = Pattern.compile(
"(?i)(password|pwd|secret|key|token|auth|credential|ssn|credit.?card)=[^&,\\s]+",
Pattern.CASE_INSENSITIVE
);
@Override
public void start() {
PatternLayout patternLayout = new PatternLayout() {
@Override
public String doLayout(ILoggingEvent event) {
String original = super.doLayout(event);
return maskSensitiveData(original);
}
};
patternLayout.setContext(context);
patternLayout.setPattern(getPattern());
patternLayout.setOutputPatternAsHeader(outputPatternAsHeader);
patternLayout.start();
this.layout = patternLayout;
super.start();
}
/**
* Mask sensitive data in log messages
*/
private String maskSensitiveData(String message) {
if (message == null) {
return null;
}
// Mask passwords, tokens, etc.
String masked = SENSITIVE_PATTERNS.matcher(message)
.replaceAll("$1=***");
// Mask email addresses
masked = Pattern.compile("\\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\.[A-Z|a-z]{2,}\\b")
.matcher(masked)
.replaceAll("***@***.***");
// Mask IP addresses
masked = Pattern.compile("\\b(?:[0-9]{1,3}\\.){3}[0-9]{1,3}\\b")
.matcher(masked)
.replaceAll("***.***.***.***");
// Mask credit card numbers
masked = Pattern.compile("\\b(?:4[0-9]{12}(?:[0-9]{3})?|5[1-5][0-9]{14}|3[47][0-9]{13}|3(?:0[0-5]|[68][0-9])[0-9]{11}|6(?:011|5[0-9]{2})[0-9]{12}|(?:2131|1800|35\\d{3})\\d{11})\\b")
.matcher(masked)
.replaceAll("****************");
return masked;
}
}
}

Database Security Configuration

JPA Configuration with Security

```java
package com.example.secure.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.orm.jpa.EntityManagerFactoryBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
import org.springframework.data.jpa.repository.config.EnableJpaAuditing;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;

import javax.sql.DataSource;
import java.util.HashMap;
import java.util.Map;

/**

  • JPA configuration with security enhancements
    */
    @Configuration
    @EnableJpaRepositories(
    basePackages = "com.example.secure.repository",
    entityManagerFactoryRef = "entityManagerFactory",
    transactionManagerRef = "transactionManager"
    )
    @EnableTransactionManagement
    @EnableJpaAuditing
    public class DatabaseSecurityConfig { @Autowired
    private DataSource dataSource; /**
    • Entity manager factory with security properties
      */
      @Bean
      public LocalContainerEntityManagerFactoryBean entityManagerFactory(
      EntityManagerFactoryBuilder builder) { Map properties = new HashMap<>();

Leave a Reply

Your email address will not be published. Required fields are marked *


Macro Nepal Helper