Skip to content

Defense In Depth

Definition

Defense in Depth Definition


Security Layers

Security Layers


Application Security Layers

// Layer 1: Input Validation (Edge)
@RestController
public class UserController {

    @PostMapping("/users")
    public User createUser(@Valid @RequestBody UserRequest request) {
        // Annotations validate input format
        return userService.create(request);
    }
}

public class UserRequest {
    @NotBlank
    @Size(min = 2, max = 50)
    @Pattern(regexp = "^[a-zA-Z0-9]+$")
    private String username;

    @NotBlank
    @Email
    private String email;
}

// Layer 2: Authentication (Who)
@Configuration
public class SecurityConfig {

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) {
        return http
            .oauth2ResourceServer(oauth2 -> oauth2.jwt())
            .authorizeHttpRequests(auth -> auth
                .requestMatchers("/public/**").permitAll()
                .anyRequest().authenticated()
            )
            .build();
    }
}

// Layer 3: Authorization (What)
@Service
public class DocumentService {

    @PreAuthorize("hasRole('ADMIN') or @accessChecker.canAccess(#docId)")
    public Document getDocument(String docId) {
        return documentRepository.findById(docId);
    }
}

@Component
public class AccessChecker {
    public boolean canAccess(String docId, Authentication auth) {
        // Check ownership, team membership, explicit sharing
        Document doc = documentRepository.findById(docId);
        return doc.getOwnerId().equals(auth.getName()) ||
               doc.getSharedWith().contains(auth.getName());
    }
}

// Layer 4: Data Protection
@Entity
public class User {

    @Convert(converter = EncryptedStringConverter.class)
    private String ssn;  // Encrypted at rest

    @JsonIgnore
    private String passwordHash;  // Never exposed
}

Network Defense Layers

Network Security Layers


Principle of Least Privilege

// Defense in Depth includes limiting access at every layer

// Database: Different users for different operations
// Read-only user for reporting
CREATE USER 'reporting'@'%' WITH PASSWORD 'xxx';
GRANT SELECT ON app.orders TO 'reporting';

// Limited write user for application
CREATE USER 'app'@'%' WITH PASSWORD 'xxx';
GRANT SELECT, INSERT, UPDATE ON app.orders TO 'app';
-- No DELETE, no schema changes

// Admin user for migrations only
CREATE USER 'admin'@'%' WITH PASSWORD 'xxx';
GRANT ALL ON app.* TO 'admin';
-- Only used by CI/CD, not application

// Application: Role-based access
public class OrderService {

    @PreAuthorize("hasRole('CUSTOMER')")
    public Order createOrder(OrderRequest request) { }

    @PreAuthorize("hasRole('CUSTOMER')")
    public Order getOrder(String orderId) {
        Order order = orderRepo.findById(orderId);
        // Additional check: only own orders
        if (!order.getCustomerId().equals(getCurrentUserId())) {
            throw new AccessDeniedException("Not your order");
        }
        return order;
    }

    @PreAuthorize("hasRole('ADMIN')")
    public List<Order> getAllOrders() { }

    @PreAuthorize("hasRole('ADMIN')")
    public void deleteOrder(String orderId) { }
}

// API Keys: Scoped permissions
{
    "apiKey": "sk_live_xxx",
    "permissions": ["orders:read", "orders:create"],
    "rateLimits": { "requests": 1000, "period": "hour" },
    "ipWhitelist": ["203.0.113.0/24"]
}

Redundant Controls

Redundant Security Controls


Monitoring and Detection

// Detection layer - know when defenses are probed/breached

@Component
public class SecurityEventListener {

    @EventListener
    public void onAuthenticationFailure(AuthenticationFailureEvent event) {
        String ip = extractIp(event);
        String username = event.getAuthentication().getName();

        // Log for analysis
        securityLog.warn("Auth failure: user={}, ip={}", username, ip);

        // Detect brute force
        if (failureTracker.recordFailure(ip) > 10) {
            securityAlerts.send(
                "Possible brute force attack from IP: " + ip);
            // Temporary IP block
            ipBlocker.block(ip, Duration.ofHours(1));
        }
    }

    @EventListener
    public void onAccessDenied(AuthorizationFailureEvent event) {
        // Log authorization failures
        securityLog.warn("Access denied: user={}, resource={}",
            event.getAuthentication().getName(),
            event.getSource());

        // Detect privilege escalation attempts
        if (suspiciousPattern(event)) {
            securityAlerts.send("Possible privilege escalation attempt");
        }
    }
}

// Audit trail - who did what when
@Aspect
@Component
public class AuditAspect {

    @AfterReturning("@annotation(Audited)")
    public void auditAction(JoinPoint jp) {
        AuditEntry entry = AuditEntry.builder()
            .user(SecurityContext.getCurrentUser())
            .action(jp.getSignature().getName())
            .resource(extractResource(jp))
            .timestamp(Instant.now())
            .outcome("SUCCESS")
            .build();

        auditRepository.save(entry);
    }
}

Tips & Tricks

Tips and Tricks