Spring Cloud Gateway安全防护架构设计:从API网关到零信任网络的全链路安全实践

D
dashi43 2025-09-11T23:21:31+08:00
0 0 264

Spring Cloud Gateway安全防护架构设计:从API网关到零信任网络的全链路安全实践

引言

在微服务架构日益普及的今天,API网关作为系统的入口和第一道防线,承担着至关重要的安全防护职责。Spring Cloud Gateway作为Spring生态系统中的新一代API网关,不仅提供了强大的路由和过滤功能,更内置了丰富的安全机制。本文将深入探讨如何基于Spring Cloud Gateway构建企业级的安全防护体系,并结合零信任网络理念,实现从API网关到全链路的安全实践。

Spring Cloud Gateway安全架构概览

网关安全的核心职责

Spring Cloud Gateway作为微服务架构的入口,其安全职责主要包括:

  1. 身份认证:验证请求来源的合法性
  2. 权限授权:控制用户对资源的访问权限
  3. 流量控制:防止系统过载和恶意攻击
  4. 攻击防护:识别和阻断恶意请求
  5. 安全审计:记录安全相关日志和事件
  6. 数据加密:保护敏感数据传输

安全架构层次

Spring Cloud Gateway的安全架构可以分为以下几个层次:

graph TD
    A[客户端请求] --> B[认证层]
    B --> C[授权层]
    C --> D[流量控制层]
    D --> E[攻击防护层]
    E --> F[业务路由层]
    F --> G[后端服务]

身份认证与授权机制

JWT Token认证实现

JWT(JSON Web Token)是现代微服务架构中最常用的认证方式之一。下面展示如何在Spring Cloud Gateway中实现JWT认证:

@Component
@Slf4j
public class JwtAuthenticationFilter implements GlobalFilter, Ordered {
    
    @Value("${jwt.secret}")
    private String secret;
    
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();
        
        // 跳过白名单路径
        if (isWhitelistPath(request.getURI().getPath())) {
            return chain.filter(exchange);
        }
        
        String token = extractToken(request);
        if (token == null) {
            return handleUnauthorized(exchange, "Missing token");
        }
        
        try {
            Claims claims = Jwts.parser()
                    .setSigningKey(secret)
                    .parseClaimsJws(token)
                    .getBody();
            
            // 验证token有效性
            if (isTokenExpired(claims)) {
                return handleUnauthorized(exchange, "Token expired");
            }
            
            // 将用户信息添加到请求头
            ServerHttpRequest mutatedRequest = request.mutate()
                    .header("X-User-ID", claims.getSubject())
                    .header("X-User-Roles", claims.get("roles", String.class))
                    .build();
            
            ServerWebExchange mutatedExchange = exchange.mutate()
                    .request(mutatedRequest)
                    .build();
            
            return chain.filter(mutatedExchange);
            
        } catch (JwtException e) {
            log.warn("Invalid token: {}", e.getMessage());
            return handleUnauthorized(exchange, "Invalid token");
        }
    }
    
    private String extractToken(ServerHttpRequest request) {
        String bearerToken = request.getHeaders().getFirst("Authorization");
        if (bearerToken != null && bearerToken.startsWith("Bearer ")) {
            return bearerToken.substring(7);
        }
        return null;
    }
    
    private boolean isTokenExpired(Claims claims) {
        return claims.getExpiration().before(new Date());
    }
    
    private boolean isWhitelistPath(String path) {
        return path.startsWith("/auth") || path.startsWith("/public");
    }
    
    private Mono<Void> handleUnauthorized(ServerWebExchange exchange, String message) {
        ServerHttpResponse response = exchange.getResponse();
        response.setStatusCode(HttpStatus.UNAUTHORIZED);
        response.getHeaders().add("Content-Type", "application/json;charset=UTF-8");
        
        String body = "{\"error\":\"Unauthorized\",\"message\":\"" + message + "\"}";
        DataBuffer buffer = response.bufferFactory().wrap(body.getBytes(StandardCharsets.UTF_8));
        return response.writeWith(Mono.just(buffer));
    }
    
    @Override
    public int getOrder() {
        return -100; // 确保在其他过滤器之前执行
    }
}

OAuth2集成实现

对于需要与外部认证服务集成的场景,可以通过OAuth2实现:

spring:
  cloud:
    gateway:
      routes:
        - id: oauth2-route
          uri: lb://user-service
          predicates:
            - Path=/api/users/**
          filters:
            - TokenRelay=
  security:
    oauth2:
      client:
        registration:
          gateway:
            provider: keycloak
            client-id: gateway-client
            client-secret: ${CLIENT_SECRET}
            authorization-grant-type: client_credentials
        provider:
          keycloak:
            issuer-uri: http://localhost:8080/auth/realms/myrealm
@Configuration
@EnableWebFluxSecurity
public class SecurityConfig {
    
    @Bean
    public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
        http
            .authorizeExchange()
                .pathMatchers("/auth/**", "/public/**").permitAll()
                .anyExchange().authenticated()
                .and()
            .oauth2ResourceServer()
                .jwt();
        
        return http.build();
    }
}

基于角色的访问控制(RBAC)

通过自定义过滤器实现细粒度的权限控制:

@Component
@Slf4j
public class AuthorizationFilter implements GlobalFilter, Ordered {
    
    private final Map<String, Set<String>> resourceRoles = new HashMap<>();
    
    public AuthorizationFilter() {
        // 初始化资源配置
        initResourceRoles();
    }
    
    private void initResourceRoles() {
        // 用户管理相关接口
        resourceRoles.put("/api/users/**", Set.of("ADMIN", "USER_MANAGER"));
        // 订单管理相关接口
        resourceRoles.put("/api/orders/**", Set.of("ADMIN", "ORDER_MANAGER"));
        // 产品管理相关接口
        resourceRoles.put("/api/products/**", Set.of("ADMIN", "PRODUCT_MANAGER"));
    }
    
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();
        String path = request.getURI().getPath();
        String method = request.getMethodValue();
        
        // 获取用户角色
        List<String> userRoles = request.getHeaders().get("X-User-Roles");
        if (userRoles == null || userRoles.isEmpty()) {
            return handleForbidden(exchange, "User roles not found");
        }
        
        // 检查权限
        if (!hasPermission(path, method, userRoles)) {
            return handleForbidden(exchange, "Insufficient permissions");
        }
        
        return chain.filter(exchange);
    }
    
    private boolean hasPermission(String path, String method, List<String> userRoles) {
        for (Map.Entry<String, Set<String>> entry : resourceRoles.entrySet()) {
            String pattern = entry.getKey();
            Set<String> requiredRoles = entry.getValue();
            
            if (pathMatcher.match(pattern, path)) {
                // 检查用户是否拥有任一所需角色
                return userRoles.stream().anyMatch(requiredRoles::contains);
            }
        }
        return true; // 默认允许访问
    }
    
    private Mono<Void> handleForbidden(ServerWebExchange exchange, String message) {
        ServerHttpResponse response = exchange.getResponse();
        response.setStatusCode(HttpStatus.FORBIDDEN);
        response.getHeaders().add("Content-Type", "application/json;charset=UTF-8");
        
        String body = "{\"error\":\"Forbidden\",\"message\":\"" + message + "\"}";
        DataBuffer buffer = response.bufferFactory().wrap(body.getBytes(StandardCharsets.UTF_8));
        return response.writeWith(Mono.just(buffer));
    }
    
    @Override
    public int getOrder() {
        return -90; // 在认证过滤器之后执行
    }
}

流量控制与熔断机制

基于Redis的分布式限流

使用Redis实现高并发场景下的分布式限流:

@Component
@Slf4j
public class RateLimitFilter implements GlobalFilter, Ordered {
    
    @Autowired
    private RedisTemplate<String, String> redisTemplate;
    
    @Value("${rate-limit.default-rate:100}")
    private int defaultRate;
    
    @Value("${rate-limit.window-size:60}")
    private int windowSize;
    
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();
        String clientIp = getClientIp(request);
        String path = request.getURI().getPath();
        
        String key = "rate_limit:" + path + ":" + clientIp;
        long current = System.currentTimeMillis() / 1000;
        
        try {
            // 使用Redis的滑动窗口算法实现限流
            Long count = redisTemplate.boundValueOps(key).increment();
            if (count == 1) {
                redisTemplate.expire(key, windowSize, TimeUnit.SECONDS);
            }
            
            if (count > defaultRate) {
                return handleRateLimitExceeded(exchange);
            }
            
        } catch (Exception e) {
            log.warn("Rate limit check failed: {}", e.getMessage());
        }
        
        return chain.filter(exchange);
    }
    
    private String getClientIp(ServerHttpRequest request) {
        List<String> xForwardedFor = request.getHeaders().get("X-Forwarded-For");
        if (xForwardedFor != null && !xForwardedFor.isEmpty()) {
            return xForwardedFor.get(0).split(",")[0].trim();
        }
        
        List<String> xRealIp = request.getHeaders().get("X-Real-IP");
        if (xRealIp != null && !xRealIp.isEmpty()) {
            return xRealIp.get(0);
        }
        
        return request.getRemoteAddress().getAddress().getHostAddress();
    }
    
    private Mono<Void> handleRateLimitExceeded(ServerWebExchange exchange) {
        ServerHttpResponse response = exchange.getResponse();
        response.setStatusCode(HttpStatus.TOO_MANY_REQUESTS);
        response.getHeaders().add("Content-Type", "application/json;charset=UTF-8");
        response.getHeaders().add("Retry-After", String.valueOf(windowSize));
        
        String body = "{\"error\":\"Rate limit exceeded\",\"message\":\"Too many requests\"}";
        DataBuffer buffer = response.bufferFactory().wrap(body.getBytes(StandardCharsets.UTF_8));
        return response.writeWith(Mono.just(buffer));
    }
    
    @Override
    public int getOrder() {
        return -80;
    }
}

基于Sentinel的流量控制

集成阿里巴巴的Sentinel实现更精细的流量控制:

<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
@Component
@Slf4j
public class SentinelRateLimitFilter implements GlobalFilter, Ordered {
    
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();
        String path = request.getURI().getPath();
        
        try {
            // 定义资源名称
            String resourceName = "gateway_route_" + path.replaceAll("/", "_");
            
            // 检查是否被限流
            Entry entry = SphU.entry(resourceName, EntryType.IN);
            
            return chain.filter(exchange)
                    .doFinally(signalType -> {
                        if (entry != null) {
                            entry.exit();
                        }
                    });
                    
        } catch (BlockException e) {
            log.warn("Request blocked by Sentinel: {}", e.getMessage());
            return handleBlockedRequest(exchange);
        }
    }
    
    private Mono<Void> handleBlockedRequest(ServerWebExchange exchange) {
        ServerHttpResponse response = exchange.getResponse();
        response.setStatusCode(HttpStatus.TOO_MANY_REQUESTS);
        response.getHeaders().add("Content-Type", "application/json;charset=UTF-8");
        
        String body = "{\"error\":\"Request blocked\",\"message\":\"Too many requests\"}";
        DataBuffer buffer = response.bufferFactory().wrap(body.getBytes(StandardCharsets.UTF_8));
        return response.writeWith(Mono.just(buffer));
    }
    
    @Override
    public int getOrder() {
        return -75;
    }
}

熔断器配置

使用Resilience4j实现熔断机制:

resilience4j:
  circuitbreaker:
    configs:
      default:
        registerHealthIndicator: true
        slidingWindowSize: 10
        minimumNumberOfCalls: 5
        permittedNumberOfCallsInHalfOpenState: 3
        automaticTransitionFromOpenToHalfOpenEnabled: true
        waitDurationInOpenState: 10s
        failureRateThreshold: 50
        eventConsumerBufferSize: 10
  timelimiter:
    configs:
      default:
        timeoutDuration: 5s
@Component
public class CircuitBreakerFilter implements GlobalFilter, Ordered {
    
    private final CircuitBreakerRegistry circuitBreakerRegistry;
    
    public CircuitBreakerFilter(CircuitBreakerRegistry circuitBreakerRegistry) {
        this.circuitBreakerRegistry = circuitBreakerRegistry;
    }
    
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();
        String serviceName = getServiceName(request.getURI());
        
        CircuitBreaker circuitBreaker = circuitBreakerRegistry.circuitBreaker(serviceName);
        
        Mono<Void> decoratedChain = Mono.fromCallable(() -> chain.filter(exchange))
                .transformDeferred(CircuitBreakerOperator.of(circuitBreaker));
        
        return decoratedChain.onErrorResume(throwable -> {
            if (throwable instanceof CallNotPermittedException) {
                return handleCircuitBreakerOpen(exchange);
            }
            return Mono.error(throwable);
        });
    }
    
    private String getServiceName(URI uri) {
        String host = uri.getHost();
        return host != null ? host : "unknown";
    }
    
    private Mono<Void> handleCircuitBreakerOpen(ServerWebExchange exchange) {
        ServerHttpResponse response = exchange.getResponse();
        response.setStatusCode(HttpStatus.SERVICE_UNAVAILABLE);
        response.getHeaders().add("Content-Type", "application/json;charset=UTF-8");
        
        String body = "{\"error\":\"Service unavailable\",\"message\":\"Circuit breaker is open\"}";
        DataBuffer buffer = response.bufferFactory().wrap(body.getBytes(StandardCharsets.UTF_8));
        return response.writeWith(Mono.just(buffer));
    }
    
    @Override
    public int getOrder() {
        return -70;
    }
}

防攻击防护机制

SQL注入防护

通过请求参数过滤防止SQL注入攻击:

@Component
@Slf4j
public class SqlInjectionFilter implements GlobalFilter, Ordered {
    
    private static final Pattern SQL_PATTERN = Pattern.compile(
        "(?:')|(?:--)|(/\\*(?:.|[\\n\\r])*?\\*/)|(\\b(select|update|delete|insert|trancate|char|into|substr|ascii|declare|exec|count|master|into|drop|execute)\\b)",
        Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL
    );
    
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();
        
        // 检查查询参数
        MultiValueMap<String, String> queryParams = request.getQueryParams();
        for (Map.Entry<String, List<String>> entry : queryParams.entrySet()) {
            for (String value : entry.getValue()) {
                if (containsSqlInjection(value)) {
                    log.warn("SQL injection detected in query parameter: {}", value);
                    return handleAttackDetected(exchange, "SQL injection detected");
                }
            }
        }
        
        // 检查请求体
        return request.getBody()
                .map(dataBuffer -> {
                    byte[] bytes = new byte[dataBuffer.readableByteCount()];
                    dataBuffer.read(bytes);
                    String body = new String(bytes, StandardCharsets.UTF_8);
                    if (containsSqlInjection(body)) {
                        log.warn("SQL injection detected in request body: {}", body);
                        throw new SecurityException("SQL injection detected");
                    }
                    return dataBuffer;
                })
                .then(chain.filter(exchange))
                .onErrorResume(throwable -> {
                    if (throwable instanceof SecurityException) {
                        return handleAttackDetected(exchange, throwable.getMessage());
                    }
                    return Mono.error(throwable);
                });
    }
    
    private boolean containsSqlInjection(String input) {
        if (input == null || input.isEmpty()) {
            return false;
        }
        return SQL_PATTERN.matcher(input).find();
    }
    
    private Mono<Void> handleAttackDetected(ServerWebExchange exchange, String message) {
        ServerHttpResponse response = exchange.getResponse();
        response.setStatusCode(HttpStatus.BAD_REQUEST);
        response.getHeaders().add("Content-Type", "application/json;charset=UTF-8");
        
        String body = "{\"error\":\"Security violation\",\"message\":\"" + message + "\"}";
        DataBuffer buffer = response.bufferFactory().wrap(body.getBytes(StandardCharsets.UTF_8));
        return response.writeWith(Mono.just(buffer));
    }
    
    @Override
    public int getOrder() {
        return -60;
    }
}

XSS攻击防护

防止跨站脚本攻击:

@Component
@Slf4j
public class XssFilter implements GlobalFilter, Ordered {
    
    private static final Pattern XSS_PATTERN = Pattern.compile(
        "<script>(.*?)</script>|<script(.*?)>|</script>|<iframe(.*?)>|</iframe>|<object(.*?)>|</object>|javascript:|vbscript:|onload(.*?)=",
        Pattern.CASE_INSENSITIVE
    );
    
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();
        
        // 检查查询参数
        MultiValueMap<String, String> queryParams = request.getQueryParams();
        for (Map.Entry<String, List<String>> entry : queryParams.entrySet()) {
            for (String value : entry.getValue()) {
                if (containsXss(value)) {
                    log.warn("XSS attack detected in query parameter: {}", value);
                    return handleAttackDetected(exchange, "XSS attack detected");
                }
            }
        }
        
        // 检查请求头
        HttpHeaders headers = request.getHeaders();
        for (Map.Entry<String, List<String>> entry : headers.entrySet()) {
            for (String value : entry.getValue()) {
                if (containsXss(value)) {
                    log.warn("XSS attack detected in header: {}", value);
                    return handleAttackDetected(exchange, "XSS attack detected");
                }
            }
        }
        
        return chain.filter(exchange);
    }
    
    private boolean containsXss(String input) {
        if (input == null || input.isEmpty()) {
            return false;
        }
        return XSS_PATTERN.matcher(input).find();
    }
    
    private Mono<Void> handleAttackDetected(ServerWebExchange exchange, String message) {
        ServerHttpResponse response = exchange.getResponse();
        response.setStatusCode(HttpStatus.BAD_REQUEST);
        response.getHeaders().add("Content-Type", "application/json;charset=UTF-8");
        
        String body = "{\"error\":\"Security violation\",\"message\":\"" + message + "\"}";
        DataBuffer buffer = response.bufferFactory().wrap(body.getBytes(StandardCharsets.UTF_8));
        return response.writeWith(Mono.just(buffer));
    }
    
    @Override
    public int getOrder() {
        return -55;
    }
}

IP黑白名单控制

实现基于IP的访问控制:

@Component
@Slf4j
public class IpFilter implements GlobalFilter, Ordered {
    
    @Value("${security.ip.whitelist:}")
    private String whitelist;
    
    @Value("${security.ip.blacklist:}")
    private String blacklist;
    
    private Set<String> whitelistSet;
    private Set<String> blacklistSet;
    
    @PostConstruct
    public void init() {
        whitelistSet = new HashSet<>(Arrays.asList(whitelist.split(",")));
        blacklistSet = new HashSet<>(Arrays.asList(blacklist.split(",")));
        whitelistSet.removeIf(String::isEmpty);
        blacklistSet.removeIf(String::isEmpty);
    }
    
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();
        String clientIp = getClientIp(request);
        
        // 检查黑名单
        if (blacklistSet.contains(clientIp)) {
            log.warn("Blocked request from blacklisted IP: {}", clientIp);
            return handleBlockedRequest(exchange);
        }
        
        // 检查白名单(如果配置了白名单)
        if (!whitelistSet.isEmpty() && !whitelistSet.contains(clientIp)) {
            log.warn("Blocked request from non-whitelisted IP: {}", clientIp);
            return handleBlockedRequest(exchange);
        }
        
        return chain.filter(exchange);
    }
    
    private String getClientIp(ServerHttpRequest request) {
        List<String> xForwardedFor = request.getHeaders().get("X-Forwarded-For");
        if (xForwardedFor != null && !xForwardedFor.isEmpty()) {
            return xForwardedFor.get(0).split(",")[0].trim();
        }
        
        List<String> xRealIp = request.getHeaders().get("X-Real-IP");
        if (xRealIp != null && !xRealIp.isEmpty()) {
            return xRealIp.get(0);
        }
        
        return request.getRemoteAddress().getAddress().getHostAddress();
    }
    
    private Mono<Void> handleBlockedRequest(ServerWebExchange exchange) {
        ServerHttpResponse response = exchange.getResponse();
        response.setStatusCode(HttpStatus.FORBIDDEN);
        response.getHeaders().add("Content-Type", "application/json;charset=UTF-8");
        
        String body = "{\"error\":\"Access denied\",\"message\":\"Your IP address is blocked\"}";
        DataBuffer buffer = response.bufferFactory().wrap(body.getBytes(StandardCharsets.UTF_8));
        return response.writeWith(Mono.just(buffer));
    }
    
    @Override
    public int getOrder() {
        return -50;
    }
}

API监控与审计

请求日志记录

实现详细的API访问日志:

@Component
@Slf4j
public class AccessLogFilter implements GlobalFilter, Ordered {
    
    private final MeterRegistry meterRegistry;
    
    public AccessLogFilter(MeterRegistry meterRegistry) {
        this.meterRegistry = meterRegistry;
    }
    
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();
        long startTime = System.currentTimeMillis();
        
        return chain.filter(exchange)
                .doFinally(signalType -> {
                    long duration = System.currentTimeMillis() - startTime;
                    ServerHttpResponse response = exchange.getResponse();
                    
                    // 记录访问日志
                    logAccess(request, response, duration);
                    
                    // 上报监控指标
                    recordMetrics(request, response, duration);
                });
    }
    
    private void logAccess(ServerHttpRequest request, ServerHttpResponse response, long duration) {
        String clientIp = getClientIp(request);
        String method = request.getMethodValue();
        String path = request.getURI().getPath();
        int status = response.getStatusCode() != null ? response.getStatusCode().value() : 0;
        String userAgent = request.getHeaders().getFirst("User-Agent");
        
        log.info("API Access - IP: {}, Method: {}, Path: {}, Status: {}, Duration: {}ms, User-Agent: {}",
                clientIp, method, path, status, duration, userAgent);
    }
    
    private void recordMetrics(ServerHttpRequest request, ServerHttpResponse response, long duration) {
        String path = request.getURI().getPath();
        int status = response.getStatusCode() != null ? response.getStatusCode().value() : 0;
        
        // 记录请求计数
        Counter.builder("api.requests.total")
                .tag("path", path)
                .tag("status", String.valueOf(status))
                .register(meterRegistry)
                .increment();
        
        // 记录响应时间
        Timer.builder("api.requests.duration")
                .tag("path", path)
                .register(meterRegistry)
                .record(duration, TimeUnit.MILLISECONDS);
    }
    
    private String getClientIp(ServerHttpRequest request) {
        List<String> xForwardedFor = request.getHeaders().get("X-Forwarded-For");
        if (xForwardedFor != null && !xForwardedFor.isEmpty()) {
            return xForwardedFor.get(0).split(",")[0].trim();
        }
        return request.getRemoteAddress().getAddress().getHostAddress();
    }
    
    @Override
    public int getOrder() {
        return Ordered.LOWEST_PRECEDENCE;
    }
}

安全事件审计

记录安全相关事件:

@Component
@Slf4j
public class SecurityAuditFilter implements GlobalFilter, Ordered {
    
    @Autowired
    private RedisTemplate<String, String> redisTemplate;
    
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();
        String clientIp = getClientIp(request);
        
        return chain.filter(exchange)
                .doOnError(throwable -> {
                    // 记录安全异常事件
                    auditSecurityEvent(request, throwable);
                })
                .doOnSuccess(aVoid -> {
                    ServerHttpResponse response = exchange.getResponse();
                    if (response.getStatusCode() != null && 
                        (response.getStatusCode().is4xxClientError() || 
                         response.getStatusCode().is5xxServerError())) {
                        auditSecurityEvent(request, null);
                    }
                });
    }
    
    private void auditSecurityEvent(ServerHttpRequest request, Throwable throwable) {
        String clientIp = getClientIp(request);
        String method = request.getMethodValue();
        String path = request.getURI().getPath();
        String userAgent = request.getHeaders().getFirst("User-Agent");
        String timestamp = Instant.now().toString();
        
        Map<String, String> event = new HashMap<>();
        event.put("timestamp", timestamp);
        event.put("clientIp", clientIp);
        event.put("method", method);
        event.put("path", path);
        event.put("userAgent", userAgent);
        
        if (throwable != null) {
            event.put("error", throwable.getClass().getSimpleName());
            event.put("message", throwable.getMessage());
        }
        
        String eventJson = new Gson().toJson(event);
        String key = "security_audit:" + timestamp;
        redisTemplate.opsForValue().set(key, eventJson, Duration.ofHours(24));
        
        log.warn("Security event: {}", eventJson);
    }
    
    private String getClientIp(ServerHttpRequest request) {
        List<String> xForwardedFor = request.getHeaders().get("X-Forwarded-For");
        if (xForwardedFor != null && !xForwardedFor.isEmpty()) {
            return xForwardedFor.get(0).split(",")[0].trim();
        }
        return request.getRemoteAddress().getAddress().getHostAddress();
    }
    
    @Override
    public int getOrder() {
        return Ordered.LOWEST_PRECEDENCE - 1;
    }
}

零信任网络架构集成

零信任核心原则

零信任网络的核心原则包括:

  1. 永不信任,始终验证:不信任任何网络流量,无论是内部还是外部
  2. 最小权限原则:只授予用户和系统完成任务所需的最小权限
  3. 持续验证:在整个会话过程中持续验证身份和权限
  4. 微分段:将网络划分为小的安全区域

零信任网关实现

基于零信任理念的网关实现:

@Component
@Slf4j
public class ZeroTrustFilter implements GlobalFilter, Ordered {
    
    @Autowired
    private DeviceTrustService deviceTrustService;
    
    @Autowired
    private BehaviorAnalysisService behaviorAnalysisService;

相似文章

    评论 (0)