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安全的重要环节。


参考资料:

相关推荐
aloha_7899 小时前
信息系统项目管理师真题做题笔记
java·笔记·学习·软件工程·学习方法
努力发光的程序员9 小时前
互联网大厂Java面试故事:Spring Boot与微服务全栈技术实战问答
java·spring boot·spring cloud·微服务·kafka·hibernate·面试技巧
SuperArc19999 小时前
jar包文件修改(java编译与反编译)
java·开发语言·后端·jar·反编译
阿维的博客日记10 小时前
简单介绍一下CompletableFuture,从最简单的用法介绍,
java
zandy101110 小时前
2026 BI平台安全治理体系构建:从权限模型到零信任架构
java·开发语言
SuniaWang10 小时前
《Agentx专栏》02-技术选型:预算有限时如何做出正确的技术决策
java·spring·架构·langchain·milvus·agenx·opl
羡寒.10 小时前
接口突然变慢,你怎么排查?
java·后端·spring
zuowei288910 小时前
编程语言对比:C/C++/Java/C#/PHP
java·c语言·c++
百数平台10 小时前
功能更新——百数详情页“数据简报”与“关联标签页”配置指南
java·服务器·前端