强曰为道

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

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日志监控不足结构化日志、告警
A10SSRF白名单校验、禁止内网访问

加密基础

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 保护接口。

📖 扩展阅读