mcpField
J
java-security

java-security

github.com/claude-dev-suite安全4651 次安装2 天前更新
代码仓库

关于 java-security

java-security 是面向 Java 应用开发者的安全速查技能,重点涉及 Spring Security。内容涵盖依赖审计、常见 Web 漏洞防护、认证、校验和安全运维。

主要功能

  1. 01Maven 与 Gradle 依赖审计
  2. 02Spring Security 配置示例
  3. 03SQL 注入与 XSS 防护
  4. 04认证、输入校验与文件上传
  5. 05安全事件记录和故障排查

适用场景

  1. 01审查 Maven 或 Gradle 依赖风险
  2. 02为 Spring Boot 配置安全过滤器
  3. 03避免 SQL 注入和跨站脚本漏洞
  4. 04检查 JWT、文件上传与访问规则

MCP 相关

README 指出可通过 mcp__documentation__fetch_docs 获取 Spring Boot 文档;未说明该技能提供 MCP 服务或客户端功能。

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/claude-dev-suite/claude-dev-suite --skill java-security

安装后在 Claude Code 中输入/java-security确认已加载。

详细介绍

Java 安全 - 快速参考

何时不应使用此技能

  • 通用 OWASP 概念 - 使用 owasp 或 owasp-top-10 技能
  • Node.js/TypeScript 安全 - 使用基础安全技能
  • Python 安全 - 使用 python-security 技能
  • 密钥管理 - 使用 secrets-management 技能

深入了解:使用 mcp__documentation__fetch_docs,并将技术指定为 spring-boot,以获取 Spring Security 文档。

依赖项审计

# Maven - OWASP Dependency Check
mvn dependency-check:check

# Maven - check for updates
mvn versions:display-dependency-updates

# Gradle - dependency check plugin
./gradlew dependencyCheckAnalyze

# Snyk for Java
snyk test --all-projects
Maven 插件配置
<plugin>
    <groupId>org.owasp</groupId>
    <artifactId>dependency-check-maven</artifactId>
    <version>9.0.9</version>
    <configuration>
        <failBuildOnCVSS>7</failBuildOnCVSS>
        <suppressionFile>dependency-check-suppression.xml</suppressionFile>
    </configuration>
</plugin>

Spring Security 配置

基本安全配置(Spring Boot 3.x)
@Configuration
@EnableWebSecurity
public class SecurityConfig {

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        return http
            .csrf(csrf -> csrf
                .csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
            )
            .cors(cors -> cors.configurationSource(corsConfigurationSource()))
            .headers(headers -> headers
                .contentSecurityPolicy(csp ->
                    csp.policyDirectives("default-src 'self'; script-src 'self'"))
                .frameOptions(frame -> frame.deny())
                .xssProtection(xss -> xss.disable()) // Use CSP instead
                .contentTypeOptions(Customizer.withDefaults())
            )
            .sessionManagement(session -> session
                .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
            )
            .authorizeHttpRequests(auth -> auth
                .requestMatchers("/api/public/**").permitAll()
                .requestMatchers("/api/admin/**").hasRole("ADMIN")
                .anyRequest().authenticated()
            )
            .build();
    }

    @Bean
    public CorsConfigurationSource corsConfigurationSource() {
        CorsConfiguration config = new CorsConfiguration();
        config.setAllowedOrigins(List.of("https://myapp.com"));
        config.setAllowedMethods(List.of("GET", "POST", "PUT", "DELETE"));
        config.setAllowCredentials(true);

        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/api/**", config);
        return source;
    }
}
密码编码
@Bean
public PasswordEncoder passwordEncoder() {
    // BCrypt with strength 12 (recommended)
    return new BCryptPasswordEncoder(12);
}

// Usage
String encoded = passwordEncoder.encode(rawPassword);
boolean matches = passwordEncoder.matches(rawPassword, encoded);
方法级安全
@Configuration
@EnableMethodSecurity(prePostEnabled = true)
public class MethodSecurityConfig {}

// Usage in service
@PreAuthorize("hasRole('ADMIN')")
public void deleteUser(Long id) { ... }

@PreAuthorize("#userId == authentication.principal.id or hasRole('ADMIN')")
public User getUser(Long userId) { ... }

@PostAuthorize("returnObject.owner == authentication.principal.username")
public Document getDocument(Long id) { ... }

防止 SQL 注入

JPA/Hibernate - 安全
// SAFE - Named parameters
@Query("SELECT u FROM User u WHERE u.email = :email")
Optional<User> findByEmail(@Param("email") String email);

// SAFE - Criteria API
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<User> query = cb.createQuery(User.class);
Root<User> root = query.from(User.class);
query.where(cb.equal(root.get("email"), email));

// SAFE - Spring Data JPA method names
Optional<User> findByEmailAndStatus(String email, Status status);
JPA/Hibernate - 不安全
// UNSAFE - String concatenation
@Query("SELECT u FROM User u WHERE u.email = '" + email + "'")  // NEVER!

// UNSAFE - Native query without parameters
@Query(value = "SELECT * FROM users WHERE email = " + email, nativeQuery = true)  // NEVER!
JDBC Template - 安全
// SAFE - Parameterized query
jdbcTemplate.query(
    "SELECT * FROM users WHERE email = ? AND status = ?",
    new Object[]{email, status},
    userRowMapper
);

// SAFE - Named parameters
namedParameterJdbcTemplate.query(
    "SELECT * FROM users WHERE email = :email",
    Map.of("email", email),
    userRowMapper
);

防止 XSS

Thymeleaf(自动转义)

<p th:text="${userInput}"></p>


<p th:utext="${userInput}"></p>  
API 响应净化
// Use OWASP Java HTML Sanitizer
import org.owasp.html.PolicyFactory;
import org.owasp.html.Sanitizers;

PolicyFactory policy = Sanitizers.FORMATTING.and(Sanitizers.LINKS);
String safeHtml = policy.sanitize(userInput);

身份验证最佳实践

JWT 配置
@Component
public class JwtTokenProvider {

    @Value("${jwt.secret}")
    private String secret;

    @Value("${jwt.expiration:3600000}") // 1 hour
    private long expiration;

    public String generateToken(Authentication auth) {
        Date now = new Date();
        Date expiryDate = new Date(now.getTime() + expiration);

        return Jwts.builder()
            .setSubject(auth.getName())
            .setIssuedAt(now)
            .setExpiration(expiryDate)
            .signWith(Keys.hmacShaKeyFor(secret.getBytes()), SignatureAlgorithm.HS512)
            .compact();
    }

    public boolean validateToken(String token) {
        try {
            Jwts.parserBuilder()
                .setSigningKey(Keys.hmacShaKeyFor(secret.getBytes()))
                .build()
                .parseClaimsJws(token);
            return true;
        } catch (JwtException | IllegalArgumentException e) {
            return false;
        }
    }
}
使用 Resilience4j 进行速率限制
@RateLimiter(name = "loginRateLimiter", fallbackMethod = "loginFallback")
public AuthResponse login(LoginRequest request) {
    // login logic
}

public AuthResponse loginFallback(LoginRequest request, RequestNotPermitted ex) {
    throw new TooManyRequestsException("Too many login attempts. Try again later.");
}
# application.yml
resilience4j:
  ratelimiter:
    instances:
      loginRateLimiter:
        limitForPeriod: 5
        limitRefreshPeriod: 15m
        timeoutDuration: 0

输入验证

public record CreateUserRequest(
    @NotBlank
    @Email
    @Size(max = 255)
    String email,

    @NotBlank
    @Size(min = 12, max = 128)
    @Pattern(regexp = "^(?=.*[a-z])(?=.*[A-Z])(?=.*\\d)(?=.*[@$!%*?&]).*$",
             message = "Password must contain uppercase, lowercase, number and special char")
    String password,

    @NotBlank
    @Size(min = 2, max = 100)
    @Pattern(regexp = "^[a-zA-Z\\s-']+$")
    String name
) {}

@PostMapping("/users")
public ResponseEntity<User> createUser(@Valid @RequestBody CreateUserRequest request) {
    // request is already validated
}

安全文件上传

@PostMapping("/upload")
public ResponseEntity<String> uploadFile(@RequestParam("file") MultipartFile file) {
    // Validate file type
    String contentType = file.getContentType();
    if (!ALLOWED_TYPES.contains(contentType)) {
        throw new InvalidFileTypeException("File type not allowed");
    }

    // Validate file size (also configure in application.yml)
    if (file.getSize() > MAX_FILE_SIZE) {
        throw new FileTooLargeException("File exceeds maximum size");
    }

    // Generate safe filename
    String originalName = file.getOriginalFilename();
    String safeName = UUID.randomUUID() + getExtension(originalName);

    // Store outside web root
    Path destination = uploadPath.resolve(safeName);
    Files.copy(file.getInputStream(), destination);

    return ResponseEntity.ok(safeName);
}

记录安全事件

@Slf4j
@Component
public class SecurityEventLogger {

    public void logLoginAttempt(String username, boolean success, HttpServletRequest request) {
        log.info("Login attempt: user={}, success={}, ip={}, userAgent={}",
            username,
            success,
            request.getRemoteAddr(),
            request.getHeader("User-Agent")
        );
    }

    public void logAccessDenied(String username, String resource, HttpServletRequest request) {
        log.warn("Access denied: user={}, resource={}, ip={}",
            username,
            resource,
            request.getRemoteAddr()
        );
    }

    // NEVER log sensitive data
    // log.info("Password: {}", password);  // NEVER!
    // log.info("Token: {}", jwt);          // NEVER!
}

反模式

反模式问题所在正确做法
使用字符串拼接的 @QuerySQL 注入使用命名参数 :param
对用户内容使用 th:utextXSS 漏洞使用 th:text(自动转义)
使用 MD5/SHA1 存储密码容易被破解使用强度为 12+ 的 BCrypt
在代码中存储 JWT 密钥密钥暴露使用环境变量
对敏感端点使用 permitAll()未授权访问定义明确的身份验证规则
对有状态应用禁用 CSRFCSRF 攻击为会话启用 CSRF
静默捕获 Exception掩盖安全问题记录日志并针对性处理

快速故障排查

问题可能原因解决方案
有效请求返回 403缺少 CSRF 令牌在请求中包含 CSRF 令牌
有效 JWT 返回 401令牌已过期或密钥错误检查过期时间和密钥
浏览器出现 CORS 错误缺少 CORS 配置将来源添加到 allowedOrigins
密码验证失败BCrypt 版本不匹配使用相同版本的编码器
方法安全未生效缺少 @EnableMethodSecurity在配置类中添加注解
依赖项检查导致构建失败CVSS 阈值过低调整 failBuildOnCVSS 或添加抑制规则

安全扫描命令

# OWASP Dependency Check
mvn dependency-check:check
./gradlew dependencyCheckAnalyze

# SpotBugs with Security Plugin
mvn spotbugs:check -Dspotbugs.plugins=com.h3xstream.findsecbugs:findsecbugs-plugin:1.12.0

# Snyk
snyk test --all-projects

# SonarQube (if configured)
mvn sonar:sonar -Dsonar.host.url=http://localhost:9000

相关技能

评论

支持 Markdown