java-security

Java Security - Quick Reference

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "java-security" with this command: npx skills add claude-dev-suite/claude-dev-suite/claude-dev-suite-claude-dev-suite-java-security

Java Security - Quick Reference

When NOT to Use This Skill

  • General OWASP concepts - Use owasp or owasp-top-10 skill

  • Node.js/TypeScript security - Use base security skills

  • Python security - Use python-security skill

  • Secrets management - Use secrets-management skill

Deep Knowledge: Use mcp__documentation__fetch_docs with technology: spring-boot for Spring Security documentation.

Dependency Auditing

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 Configuration

<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 Configuration

Basic Security Config (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;
}

}

Password Encoding

@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);

Method-Level Security

@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 Injection Prevention

JPA/Hibernate - Safe

// 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

// 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

// 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 Prevention

Thymeleaf (Auto-escaping)

<!-- SAFE - Auto-escaped --> <p th:text="${userInput}"></p>

<!-- UNSAFE - Unescaped HTML --> <p th:utext="${userInput}"></p> <!-- Avoid if possible -->

API Response Sanitization

// 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);

Authentication Best Practices

JWT Configuration

@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;
    }
}

}

Rate Limiting with 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

Input Validation

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

@NotBlank
@Size(min = 12, max = 128)
@Pattern(regexp = "^(?=.*[a-z])(?=.*[A-Z])(?=.*\\d)(?=.*[@$!%*?&#x26;]).*$",
         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 }

Secure File Upload

@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);

}

Logging Security Events

@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!

}

Anti-Patterns

Anti-Pattern Why It's Bad Correct Approach

@Query with string concat SQL injection Use named parameters :param

th:utext for user content XSS vulnerability Use th:text (auto-escaped)

MD5/SHA1 for passwords Easily cracked Use BCrypt with strength 12+

Storing JWT secret in code Secret exposure Use environment variables

permitAll() for sensitive endpoints Unauthorized access Define explicit auth rules

Disabling CSRF for stateful apps CSRF attacks Keep CSRF enabled for sessions

Catching Exception silently Hides security issues Log and handle specifically

Quick Troubleshooting

Issue Likely Cause Solution

403 on valid request CSRF token missing Include CSRF token in requests

401 with valid JWT Token expired or wrong key Check expiration and secret key

CORS error in browser Missing CORS config Add origin to allowedOrigins

Password validation fails BCrypt version mismatch Use same encoder version

Method security not working @EnableMethodSecurity missing Add annotation to config class

Dependency check fails build CVSS threshold too low Adjust failBuildOnCVSS or suppress

Security Scanning Commands

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

Related Skills

  • OWASP Top 10:2025

  • OWASP General

  • Secrets Management

  • Supply Chain Security

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

Security

rust-security

No summary provided by upstream source.

Repository SourceNeeds Review
Security

dotnet-security

No summary provided by upstream source.

Repository SourceNeeds Review
Security

spring-security

No summary provided by upstream source.

Repository SourceNeeds Review