前置知识: Java

Java与安全

00:00
3 min Intermediate 2026/6/14

Java安全编程

概述

Java 安全编程涵盖加密解密、身份认证、访问控制和安全编码规范等多个方面。Java 标准库提供了丰富的安全 API(JCA/JCE),配合 Spring Security 等框架,可以构建企业级安全系统。本文介绍 Java 安全编程的核心技术和最佳实践。

基础概念

安全核心术语

术语说明
对称加密加密和解密使用同一密钥,如 AES
对称加密使用公钥加密、私钥解密,如 RSA
哈希向不可逆,用于数据完整性校验
签名用私钥签名、公钥验证,确保来源可信
(Salt)哈希前追加的随机值,防止彩虹攻击

Java 安全架构

  • JCA(Java Cryptography Architecture)提供加密、哈希签名等基础 API
  • JCE(Java Cryptography Extension)扩展 JCA,支持 AES、RSA 等强加密算法
  • JSSE(Java Secure Socket Extension)提供 SSL/TLS 支持
  • JAAS(Java Authentication and Authorization Service:认证与授权框架

快速上手

AES 对称加密

// 生成 AES 密钥
KeyGenerator keyGen = KeyGenerator.getInstance("AES");
keyGen.init(256); // 使用 256 位密钥
SecretKey secretKey = keyGen.generateKey();

// AES-GCM 加密(推荐模式,自带认证)
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
cipher.init(Cipher.ENCRYPT_MODE, secretKey);
byte[] encrypted = cipher.doFinal(plainText.getBytes());

// 获取初始化向量(解密时需要)
byte[] iv = cipher.getIV();

密码哈希

// 使用 SHA-256 进行哈希
MessageDigest md = MessageDigest.getInstance("SHA-256");
byte[] hash = md.digest("password".getBytes(StandardCharsets.UTF_8));

// 转换为十六进制字符串
String hexHash = HexFormat.of().formatHex(hash);
System.out.println("SHA-256 哈希值: " + hexHash);

详细用法

AES-GCM 完整加解密

// 完整的 AES-GCM 加密与解密流程
public class AesGcmCrypto {
    private static final String ALGORITHM = "AES/GCM/NoPadding";
    private static final int TAG_LENGTH = 128; // 认证标签长度(位)
    private static final int IV_LENGTH = 12;   // 初始化向量长度(字节)

    // 加密
    public static String encrypt(String plainText, SecretKey key) throws Exception {
        byte[] iv = new byte[IV_LENGTH];
        SecureRandom.getInstanceStrong().nextBytes(iv);

        Cipher cipher = Cipher.getInstance(ALGORITHM);
        GCMParameterSpec spec = new GCMParameterSpec(TAG_LENGTH, iv);
        cipher.init(Cipher.ENCRYPT_MODE, key, spec);
        byte[] cipherText = cipher.doFinal(plainText.getBytes(StandardCharsets.UTF_8));

        // 将 IV 和密文拼接在一起
        ByteBuffer byteBuffer = ByteBuffer.allocate(iv.length + cipherText.length);
        byteBuffer.put(iv);
        byteBuffer.put(cipherText);
        return Base64.getEncoder().encodeToString(byteBuffer.array());
    }

    // 解密
    public static String decrypt(String encryptedText, SecretKey key) throws Exception {
        byte[] decoded = Base64.getDecoder().decode(encryptedText);
        ByteBuffer byteBuffer = ByteBuffer.wrap(decoded);

        byte[] iv = new byte[IV_LENGTH];
        byteBuffer.get(iv);
        byte[] cipherText = new byte[byteBuffer.remaining()];
        byteBuffer.get(cipherText);

        Cipher cipher = Cipher.getInstance(ALGORITHM);
        GCMParameterSpec spec = new GCMParameterSpec(TAG_LENGTH, iv);
        cipher.init(Cipher.DECRYPT_MODE, key, spec);
        byte[] plainText = cipher.doFinal(cipherText);
        return new String(plainText, StandardCharsets.UTF_8);
    }
}

RSA 非对称加密

// 生成 RSA 密钥对
KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
keyGen.initialize(2048);
KeyPair keyPair = keyGen.generateKeyPair();

// 用公钥加密
Cipher encryptCipher = Cipher.getInstance("RSA");
encryptCipher.init(Cipher.ENCRYPT_MODE, keyPair.getPublic());
byte[] encrypted = encryptCipher.doFinal("敏感数据".getBytes());

// 用私钥解密
Cipher decryptCipher = Cipher.getInstance("RSA");
decryptCipher.init(Cipher.DECRYPT_MODE, keyPair.getPrivate());
byte[] decrypted = decryptCipher.doFinal(encrypted);
System.out.println(new String(decrypted));

数字签名

// 使用 RSA 私钥签名
Signature signature = Signature.getInstance("SHA256withRSA");
signature.initSign(keyPair.getPrivate());
signature.update("重要文件内容".getBytes());
byte[] digitalSignature = signature.sign();

// 使用 RSA 公钥验证签名
Signature verifySig = Signature.getInstance("SHA256withRSA");
verifySig.initVerify(keyPair.getPublic());
verifySig.update("重要文件内容".getBytes());
boolean isValid = verifySig.verify(digitalSignature);
System.out.println("签名验证结果: " + isValid);

常见场景

BCrypt 密码存储

// 使用 BCrypt 安全存储密码(推荐方式)
import org.mindrot.jbcrypt.BCrypt;

// 注册时:哈希密码
String hashedPassword = BCrypt.hashpw("userPassword123", BCrypt.gensalt(12));

// 登录时:验证密码
boolean isMatch = BCrypt.checkpw("userPassword123", hashedPassword);
System.out.println("密码匹配: " + isMatch);

JWT Token 生成与验证

// 使用 JJWT 库生成和验证 JWT
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.security.Keys;

// 生成密钥
SecretKey key = Keys.secretKeyFor(SignatureAlgorithm.HS256);

// 生成 Token
String token = Jwts.builder()
    .setSubject("user123")
    .claim("role", "admin")
    .setIssuedAt(new Date())
    .setExpiration(new Date(System.currentTimeMillis() + 3600000)) // 1小时过期
    .signWith(key)
    .compact();

// 验证并解析 Token
Claims claims = Jwts.parserBuilder()
    .setSigningKey(key)
    .build()
    .parseClaimsJws(token)
    .getBody();
String userId = claims.getSubject();
String role = claims.get("role", String.class);

注意事项

  • 永远不要自己实现加密算法,使用标准库提供的实现
  • AES 推荐使用 GCM 模式,避免使用 ECB 模式(ECB 不安全
  • 密码存储必须使用 BCrypt/Argon2 等慢哈希算法,不要使用 MD5/SHA
  • RSA 加密有长限制(密钥长减去填充开销),大数据应使用 AES 加密后用 RSA 加密 AES 密钥
  • 随机生成应使用 SecureRandom,不要使用 Math.random()
  • 生产环境中密钥应通过密钥管理系统(KMS)管理,不要硬编码在代码中

进阶用法

SSL/TLS 配置

// 配置 HTTPS 客户端,自定义信任策略
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, new TrustManager[]{
    new X509TrustManager() {
        public void checkClientTrusted(X509Certificate[] chain, String authType) {}
        public void checkServerTrusted(X509Certificate[] chain, String authType) {
            // 生产环境应验证证书链
        }
        public X509Certificate[] getAcceptedIssuers() { return new X509Certificate[0]; }
    }
}, new SecureRandom());

HttpsURLConnection connection = (HttpsURLConnection) url.openConnection();
connection.setSSLSocketFactory(sslContext.getSocketFactory());

Spring Security 基础配置

// Spring Security 安全配置示例
@Configuration
@EnableWebSecurity
public class SecurityConfig {

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http
            .csrf(csrf -> csrf.disable()) // REST API 可禁用 CSRF
            .authorizeHttpRequests(auth -> auth
                .requestMatchers("/api/public/**").permitAll()
                .requestMatchers("/api/admin/**").hasRole("ADMIN")
                .anyRequest().authenticated()
            )
            .oauth2ResourceServer(oauth2 -> oauth2.jwt(Customizer.withDefaults()));
        return http.build();
    }

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder(12); // 使用 BCrypt,强度因子 12
    }
}

知识检测

学习进度

-- 已学文档
--% 知识覆盖率

学习推荐

专注模式