Security Practices
Spring Security Configuration
@Configuration
@EnableWebSecurity
class SecurityConfig {
@Bean
fun securityFilterChain(http: HttpSecurity): SecurityFilterChain = http
.csrf { it.disable() } // disable for API-only services
.sessionManagement { it.sessionCreationPolicy(SessionCreationPolicy.STATELESS) }
.authorizeHttpRequests {
it.requestMatchers("/actuator/health/**").permitAll()
it.requestMatchers("/api/v1/**").authenticated()
it.anyRequest().denyAll()
}
.oauth2ResourceServer { it.jwt { } }
.build()
}
Parameterized Queries — ALWAYS
// GOOD — parameterized
@Query("SELECT o FROM Order o WHERE o.customerId = :customerId")
fun findByCustomerId(@Param("customerId") customerId: String): List<Order>
// NEVER — string concatenation (SQL injection!)
"SELECT * FROM orders WHERE customer_id = '$customerId'" // FATAL SECURITY BUG
Input Validation
data class CreateOrderRequest(
@field:NotBlank val customerId: String,
@field:NotEmpty val items: List<@Valid OrderItemRequest>,
@field:Size(max = 500) val notes: String? = null
)
@PostMapping("/orders")
fun createOrder(@Valid @RequestBody request: CreateOrderRequest): ResponseEntity<Order> { ... }
Secret Management
- NEVER hardcode credentials in source code
- Use environment variables:
${DB_PASSWORD}, ${API_KEY}
- Use Spring
@ConfigurationProperties to bind env vars
- Rotate secrets regularly
.gitignore all .env, *.key, *.pem, credentials.json files
OWASP Top 10 Checklist
- Injection → Parameterized queries only
- Broken Auth → OAuth2/JWT, no custom auth
- Sensitive Data → Encrypt at rest/transit, never log secrets
- XXE → Disable external entity processing
- Broken Access Control → Role-based + resource-level checks
- Misconfiguration → Security headers, disable unused endpoints
- XSS → Content-Type headers, input sanitization
- Insecure Deserialization → Whitelist allowed types
- Known Vulnerabilities → Regular dependency scanning
- Insufficient Logging → Audit all auth events