API安全设计与防护实战

API安全设计与防护实战

一、API安全概述

API作为系统间交互的接口,是攻击的主要目标。一个安全的API设计需要考虑多个层面的防护,包括认证、授权、数据保护、攻击防护等。

二、API认证机制

2.1 API Key认证

java 复制代码
@Component
public class ApiKeyFilter extends OncePerRequestFilter {
    
    private static final String API_KEY_HEADER = "X-API-Key";
    private static final String VALID_API_KEY = "your-api-key-here";
    
    @Override
    protected void doFilterInternal(HttpServletRequest request, 
                                    HttpServletResponse response,
                                    FilterChain filterChain) throws ServletException, IOException {
        String apiKey = request.getHeader(API_KEY_HEADER);
        
        if (!VALID_API_KEY.equals(apiKey)) {
            response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
            response.getWriter().write("Unauthorized: Invalid API Key");
            return;
        }
        
        filterChain.doFilter(request, response);
    }
}

2.2 基于证书的双向认证

yaml 复制代码
server:
  ssl:
    enabled: true
    key-store: classpath:server.jks
    key-store-password: password
    trust-store: classpath:truststore.jks
    trust-store-password: password
    client-auth: need

三、API授权策略

3.1 RBAC基于角色的访问控制

java 复制代码
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
            .antMatchers("/api/admin/**").hasRole("ADMIN")
            .antMatchers("/api/user/**").hasRole("USER")
            .antMatchers("/api/public/**").permitAll()
            .anyRequest().authenticated();
    }
}

3.2 ABAC基于属性的访问控制

java 复制代码
@Component
public class AbacAuthorizationManager {
    
    public boolean isAllowed(User user, Resource resource, Action action) {
        // 根据用户属性、资源属性、环境属性进行动态授权判断
        if ("admin".equals(user.getRole())) {
            return true;
        }
        
        if ("read".equals(action) && resource.isPublic()) {
            return true;
        }
        
        if (resource.getOwnerId().equals(user.getId())) {
            return true;
        }
        
        return false;
    }
}

四、输入验证与数据保护

4.1 参数校验

java 复制代码
@RestController
@RequestMapping("/api/users")
public class UserController {
    
    @PostMapping
    public ResponseEntity<User> createUser(@Valid @RequestBody UserCreateRequest request) {
        // 参数已通过@Valid注解自动校验
        User user = userService.createUser(request);
        return ResponseEntity.ok(user);
    }
}

public class UserCreateRequest {
    
    @NotBlank(message = "用户名不能为空")
    @Size(min = 3, max = 50, message = "用户名长度必须在3-50之间")
    private String username;
    
    @Email(message = "邮箱格式不正确")
    @NotBlank(message = "邮箱不能为空")
    private String email;
    
    @NotBlank(message = "密码不能为空")
    @Size(min = 8, message = "密码长度至少8位")
    private String password;
}

4.2 SQL注入防护

错误写法:

java 复制代码
// 存在SQL注入风险
String sql = "SELECT * FROM users WHERE username = '" + username + "'";

正确写法:

java 复制代码
// 使用预编译语句
String sql = "SELECT * FROM users WHERE username = ?";
PreparedStatement stmt = connection.prepareStatement(sql);
stmt.setString(1, username);
ResultSet rs = stmt.executeQuery();

4.3 XSS攻击防护

java 复制代码
import org.jsoup.Jsoup;
import org.jsoup.safety.Safelist;

public class XssUtils {
    
    public static String clean(String input) {
        if (input == null) {
            return null;
        }
        return Jsoup.clean(input, Safelist.relaxed());
    }
}

五、API限流与熔断

5.1 使用Bucket4j进行限流

java 复制代码
@Configuration
public class RateLimitConfig {
    
    @Bean
    public Bucket bucket() {
        Refill refill = Refill.greedy(100, Duration.ofMinutes(1));
        Bandwidth limit = Bandwidth.classic(100, refill);
        return Bucket.builder().addLimit(limit).build();
    }
}

@Component
public class RateLimitFilter extends OncePerRequestFilter {
    
    @Autowired
    private Bucket bucket;
    
    @Override
    protected void doFilterInternal(HttpServletRequest request,
                                    HttpServletResponse response,
                                    FilterChain filterChain) throws ServletException, IOException {
        if (bucket.tryConsume(1)) {
            filterChain.doFilter(request, response);
        } else {
            response.setStatus(HttpServletResponse.SC_TOO_MANY_REQUESTS);
            response.getWriter().write("Rate limit exceeded");
        }
    }
}

5.2 Hystrix熔断配置

java 复制代码
@Configuration
public class HystrixConfig {
    
    @Bean
    public HystrixCommand.Setter defaultCommandProperties() {
        return HystrixCommand.Setter
            .withGroupKey(HystrixCommandGroupKey.Factory.asKey("DefaultGroup"))
            .andCommandPropertiesDefaults(HystrixCommandProperties.Setter()
                .withExecutionTimeoutInMilliseconds(5000)
                .withCircuitBreakerRequestVolumeThreshold(20)
                .withCircuitBreakerErrorThresholdPercentage(50)
                .withCircuitBreakerSleepWindowInMilliseconds(30000));
    }
}

六、安全审计与日志

6.1 审计日志记录

java 复制代码
@Aspect
@Component
public class AuditAspect {
    
    @Autowired
    private AuditLogRepository auditLogRepository;
    
    @Around("@annotation(auditable)")
    public Object audit(ProceedingJoinPoint joinPoint, Auditable auditable) throws Throwable {
        AuditLog log = new AuditLog();
        log.setAction(auditable.action());
        log.setResource(auditable.resource());
        log.setTimestamp(LocalDateTime.now());
        
        try {
            Object result = joinPoint.proceed();
            log.setStatus("SUCCESS");
            return result;
        } catch (Exception e) {
            log.setStatus("FAILED");
            log.setErrorMessage(e.getMessage());
            throw e;
        } finally {
            auditLogRepository.save(log);
        }
    }
}

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Auditable {
    String action();
    String resource();
}

6.2 安全日志脱敏

java 复制代码
public class LogSanitizer {
    
    private static final Pattern EMAIL_PATTERN = Pattern.compile("[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}");
    private static final Pattern PHONE_PATTERN = Pattern.compile("1[3-9]\\d{9}");
    private static final Pattern CARD_PATTERN = Pattern.compile("\\d{4}\\s*\\d{4}\\s*\\d{4}\\s*\\d{4}");
    
    public static String sanitize(String message) {
        if (message == null) {
            return null;
        }
        
        String sanitized = EMAIL_PATTERN.matcher(message).replaceAll("***@***.com");
        sanitized = PHONE_PATTERN.matcher(sanitized).replaceAll("1*** **** ****");
        sanitized = CARD_PATTERN.matcher(sanitized).replaceAll("**** **** **** ****");
        
        return sanitized;
    }
}

七、API安全测试

7.1 使用OWASP ZAP进行安全扫描

bash 复制代码
# 启动ZAP代理
zap.sh -daemon -port 8080 -config scanner.maxRuleDurationInMins=5

# 运行主动扫描
curl -X POST http://localhost:8080/JSON/ascan/action/scan \
  -d '{"apikey":"your-api-key","url":"http://localhost:8080/api","recurse":"true"}'

# 获取扫描结果
curl http://localhost:8080/JSON/ascan/view/alerts \
  -d '{"apikey":"your-api-key","baseurl":"http://localhost:8080/api"}'

7.2 安全测试清单

复制代码
认证测试:
- [ ] 无Token访问受限API
- [ ] 使用过期Token访问
- [ ] 使用无效Token访问
- [ ] Token劫持测试

授权测试:
- [ ] 越权访问其他用户数据
- [ ] 普通用户访问管理员接口
- [ ] 未授权访问敏感资源

输入验证测试:
- [ ] SQL注入测试
- [ ] XSS攻击测试
- [ ] 参数边界值测试
- [ ] 恶意文件上传测试

安全配置测试:
- [ ] HTTPS强制测试
- [ ] CORS配置验证
- [ ] 敏感信息泄露检查
- [ ] 错误信息泄露检查

八、总结

API安全是一个系统性工程,需要从认证授权、输入验证、限流熔断、审计日志等多个维度进行防护。通过采用业界成熟的安全框架和最佳实践,可以有效降低API被攻击的风险。同时,定期进行安全测试和漏洞扫描,及时修复发现的安全问题,是保障API安全的重要环节。


参考资料:

相关推荐
噢,我明白了13 分钟前
java中Excel的导入和导出(EasyExcel)
java·开发语言·excel
吠品15 分钟前
Zabbix Web界面误报Server未运行的排查与解决
java·服务器·数据库
啊湘18 分钟前
天气查询API接口 按月Token鉴权 实时天气 物联网可用 文档齐全
java·后端·struts
Java内核笔记1 小时前
告别十亿美元的错误 : Spring Boot 4 空安全 (JSpecify) 实战
java·spring boot·后端
糖果店的幽灵1 小时前
langgraph的 MessagesState 解读
java·开发语言·人工智能·windows·langgraph
极光代码工作室2 小时前
基于SpringBoot的在线博客系统
java·springboot·web开发·后端开发
我是唐青枫2 小时前
Java Spring Security 实战详解:从登录认证到 JWT 权限控制
java·spring
ihuyigui3 小时前
海外签收通知短信接口
android·java·开发语言·前端·数据库·后端
海棠Flower未眠3 小时前
SpringBoot 消息死信队列(荣耀典藏版)
java·数据库·spring boot
暖和_白开水3 小时前
数据分析agent (七):contextvars 模块上下文request_id
java·前端·数据分析