强曰为道
与天地相似,故不违。知周乎万物,而道济天下,故不过。旁行而不流,乐天知命,故不忧.
文档目录

Java 完全指南 / 28 - 安全:加密、认证、OWASP、SQL 注入防护

28 - 安全:加密、认证、OWASP、SQL 注入防护

OWASP Top 10(2021)

排名 漏洞类型 Java 防护措施
A01 访问控制失效 Spring Security、RBAC
A02 加密机制失败 使用成熟库,不自创算法
A03 注入 PreparedStatement、参数校验
A04 不安全设计 威胁建模、安全评审
A05 安全配置错误 最小权限、关闭调试端口
A06 过时组件 定期更新依赖(Dependabot)
A07 认证失败 强密码策略、MFA
A08 数据完整性失败 签名验证、CI/CD 安全
A09 日志监控不足 结构化日志、告警
A10 SSRF 白名单校验、禁止内网访问

加密基础

import javax.crypto.*;
import javax.crypto.spec.*;
import java.security.*;
import java.util.Base64;

public class CryptoUtils {
    // ---- 对称加密 AES ----
    private static final String AES_KEY = "0123456789abcdef";  // 16字节 = AES-128

    public static String aesEncrypt(String plainText) throws Exception {
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        SecretKeySpec keySpec = new SecretKeySpec(AES_KEY.getBytes(), "AES");
        byte[] iv = new byte[16];
        new SecureRandom().nextBytes(iv);
        cipher.init(Cipher.ENCRYPT_MODE, keySpec, new IvParameterSpec(iv));
        byte[] encrypted = cipher.doFinal(plainText.getBytes());
        // IV + 密文
        byte[] combined = new byte[iv.length + encrypted.length];
        System.arraycopy(iv, 0, combined, 0, iv.length);
        System.arraycopy(encrypted, 0, combined, iv.length, encrypted.length);
        return Base64.getEncoder().encodeToString(combined);
    }

    public static String aesDecrypt(String cipherText) throws Exception {
        byte[] combined = Base64.getDecoder().decode(cipherText);
        byte[] iv = Arrays.copyOfRange(combined, 0, 16);
        byte[] encrypted = Arrays.copyOfRange(combined, 16, combined.length);
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        SecretKeySpec keySpec = new SecretKeySpec(AES_KEY.getBytes(), "AES");
        cipher.init(Cipher.DECRYPT_MODE, keySpec, new IvParameterSpec(iv));
        return new String(cipher.doFinal(encrypted));
    }

    // ---- 哈希 SHA-256 ----
    public static String sha256(String input) throws Exception {
        MessageDigest digest = MessageDigest.getInstance("SHA-256");
        byte[] hash = digest.digest(input.getBytes());
        return Base64.getEncoder().encodeToString(hash);
    }

    // ---- BCrypt 密码哈希(推荐)----
    // 依赖: org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder
    public static String bcryptHash(String password) {
        var encoder = new org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder();
        return encoder.encode(password);
    }

    public static boolean bcryptVerify(String password, String hash) {
        var encoder = new org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder();
        return encoder.matches(password, hash);
    }
}

加密算法对比

算法 类型 用途 推荐
AES-256 对称加密 数据加密
RSA-2048+ 非对称加密 密钥交换、签名
SHA-256 哈希 完整性校验
BCrypt 哈希 密码存储 ✅ 强烈推荐
MD5 哈希 仅校验 ❌ 不安全
SHA-1 哈希 ❌ 已被破解

JWT 认证

import io.jsonwebtoken.*;
import java.util.Date;

public class JwtUtils {
    private static final String SECRET = "your-256-bit-secret-key-here-minimum-32-chars";
    private static final long EXPIRATION = 3600000; // 1小时

    public static String generateToken(Long userId, String username) {
        return Jwts.builder()
            .setSubject(String.valueOf(userId))
            .claim("username", username)
            .setIssuedAt(new Date())
            .setExpiration(new Date(System.currentTimeMillis() + EXPIRATION))
            .signWith(SignatureAlgorithm.HS256, SECRET)
            .compact();
    }

    public static Claims parseToken(String token) {
        return Jwts.parser()
            .setSigningKey(SECRET)
            .parseClaimsJws(token)
            .getBody();
    }

    public static boolean isValid(String token) {
        try {
            Claims claims = parseToken(token);
            return !claims.getExpiration().before(new Date());
        } catch (JwtException e) {
            return false;
        }
    }
}

SQL 注入防护

// ❌ 危险 —— SQL 注入
String sql = "SELECT * FROM users WHERE name = '" + userInput + "'";
// 输入: ' OR '1'='1  → 返回所有用户!

// ✅ 安全 —— PreparedStatement
String sql = "SELECT * FROM users WHERE name = ?";
PreparedStatement ps = conn.prepareStatement(sql);
ps.setString(1, userInput);  // 自动转义

// ✅ 安全 —— JPA/Hibernate
@Query("SELECT u FROM User u WHERE u.name = :name")
List<User> findByName(@Param("name") String name);

// ✅ 安全 —— MyBatis #{}
// <select>SELECT * FROM users WHERE name = #{name}</select>

// ❌ 危险 —— MyBatis ${}
// <select>SELECT * FROM users WHERE name = ${name}</select>

XSS 防护

// 输出时转义
import org.springframework.web.util.HtmlUtils;

public String sanitize(String input) {
    return HtmlUtils.htmlEscape(input);
    // <script>alert('xss')</script> → &lt;script&gt;alert('xss')&lt;/script&gt;
}

// CSP 响应头
@GetMapping("/page")
public ResponseEntity<String> page() {
    return ResponseEntity.ok()
        .header("Content-Security-Policy", "default-src 'self'; script-src 'self'")
        .body(htmlContent);
}

Spring Security 快速配置

@Configuration
@EnableWebSecurity
public class SecurityConfig {

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        return http
            .csrf(csrf -> csrf.ignoringRequestMatchers("/api/**")) // REST API 禁用 CSRF
            .sessionManagement(sm -> sm.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
            .authorizeHttpRequests(auth -> auth
                .requestMatchers("/api/public/**").permitAll()
                .requestMatchers("/api/admin/**").hasRole("ADMIN")
                .anyRequest().authenticated()
            )
            .addFilterBefore(jwtFilter(), UsernamePasswordAuthenticationFilter.class)
            .build();
    }

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }
}

⚠️ 注意事项

  1. 密码永远不要明文存储 — 使用 BCrypt。
  2. 密钥不要硬编码 — 使用环境变量或密钥管理服务。
  3. HTTPS 必须 — 生产环境禁止 HTTP。
  4. 依赖安全扫描 — 定期检查已知漏洞(CVE)。

💡 技巧

  1. Spring Boot Actuator 安全 — 生产环境只暴露必要端点。
  2. Rate Limiting — 使用 Bucket4j 或 Resilience4j 限流防暴力破解。
  3. CORS 配置
    @Bean
    CorsConfigurationSource corsConfigurationSource() {
        var config = new CorsConfiguration();
        config.setAllowedOrigins(List.of("https://example.com"));
        config.setAllowedMethods(List.of("GET", "POST"));
        var source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", config);
        return source;
    }
    

🏢 业务场景

  • 用户认证: JWT + Spring Security 实现无状态认证。
  • 数据加密: 敏感字段(身份证、银行卡)加密存储。
  • API 安全: OAuth2 + API Key 保护接口。

📖 扩展阅读