JWE:安全传输敏感数据的最佳实践 (上)

最近工作需求,提供几个API,但是数据是敏感数据,最好是不要暴露出来(PS: 本来接口就已经是HTTPS,也足够安全)

好吧,老板注重数据安全,通过网上一顿操作,发现 JSON Web Encryption(JWE),貌似可以拿来用用(PS: 复制粘贴大法)

JWE是"JSON Web Encryption"的缩写,是一种基于JSON的加密规范,用于在网络上传输加密的数据。它定义了一种将JSON数据加密为JWE格式的方法,以确保安全传输。JWE规范使用一种称为"JWE Compact Serialization"的格式来序列化加密后的数据,以便它可以轻松地在不同的系统之间传输。

JWE使用加密算法来保护数据的机密性,同时使用消息认证码(MAC)算法来验证数据的完整性,以防止数据在传输过程中被篡改。JWE还支持多种密钥管理方法,例如将密钥嵌入到JWE中,或者通过密钥交换协议来获取密钥。

JWE通常用于保护敏感的网络数据,例如用户凭证、支付信息等等。它是JSON Web Token(JWT)规范的一部分,JWT使用JWE来提供安全性。

好了,上面搬来了八股文,还不如直接通过代码操作

首先引入maven依赖,nimbus-jose-jwt 是JWT的一种实现,相信大家也不陌生


		com.nimbusds
		nimbus-jose-jwt
		9.8.1
public class JweRSADemo {

    public static String encrypt(String payload, RSAPublicKey publicKey) throws Exception {
        // 创建加密器
        JWEHeader header = new JWEHeader.Builder(JWEAlgorithm.RSA_OAEP_256, EncryptionMethod.A256GCM).build();
        JWEEncrypter jweEncrypter = new RSAEncrypter(publicKey);
        // 加密JSON数据
        Payload jwePayload = new Payload(payload);
        JWEObject jweObject = new JWEObject(header, jwePayload);
        jweObject.encrypt(jweEncrypter);
        // 将JWE对象转换为JWE字符串
        return jweObject.serialize();
    }

    public static String decrypt(String jwe, RSAPrivateKey privateKey) throws Exception {
        // 创建解密器
        JWEDecrypter jweDecrypter = new RSADecrypter(privateKey);
        // 解密JWE字符串
        JWEObject jweObject = JWEObject.parse(jwe);
        jweObject.decrypt(jweDecrypter);
        // 将解密后的JSON数据转换为JSONObject对象
        Payload payload = jweObject.getPayload();
        return payload.toString();
    }

    public static void main(String[] args) throws Exception {
        // 创建一个JSON对象
        JSONObject payload = new JSONObject();
        payload.put("name", "Alice");
        payload.put("age", 30);
        String jsonString = payload.toJSONString();
        // 生成RSA密钥对
        KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
        keyPairGenerator.initialize(2048);
        KeyPair keyPair = keyPairGenerator.generateKeyPair();
        RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
        RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
        // 加密JSON对象
        String jwe = encrypt(jsonString, publicKey);
        System.out.println("JWE: " + jwe);
        // 解密JWE字符串
        String decryptedPayload = decrypt(jwe, privateKey);
        System.out.println("Decrypted payload: " + decryptedPayload);
    }
    
}

成功进行加解密


先生成一对公钥和私钥

// 生成RSA密钥对
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
keyPairGenerator.initialize(2048);
KeyPair keyPair = keyPairGenerator.generateKeyPair();
RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();

System.out.println("Base64.encode(publicKey.getEncoded()) = " + Base64.encode(publicKey.getEncoded()));
System.out.println("Base64.encode(privateKey.getEncoded()) = " + Base64.encode(privateKey.getEncoded()));


用生成出来的公钥加密数据,加密出来的内容等下作为参数调用,通常公钥都是分发给调用端

String publicKeyStr = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsqBTYOqBU5rdpdRX9/owxi0nHsxsyGr/8PWQZ8GtPQilXfNuQEFWO01o0ZU8Agn+wzatpGCOwIgSaEF4p6uI4tyhC8BlnkQZN/GcjbryljzIrRlu8NKsLu40SQO3CYa+p7DA36pdX/nMQ9QceSeGW9e7E5YWuiMhUDgqWVEdmRxX+bxfoNYpBtNlvyxeL0MKEIUVlikYKe+UxKhiPRcwjBIiHKfsY2PszP4h485UjcIWveyJjBu8nEpUgHUqUHdA1nm32WmUMcOhTU41tX6ZoYK6qUBeNX4xnfOG7jnE76Vz2QcsVTnnTqTQ/93nxEIrZsSfQ/vdzi8LryY2xS0EmQIDAQAB";
PublicKey publicKey = getPublicKey(publicKeyStr);
//playload 可以是json串,也可以是普通字符串
String encrypt = encrypt("jwe 测试", publicKey);
System.out.println(encrypt);


我们再写一个Controller来接受参数并用私钥解密

@RestController
public class JWEController {

    private static final Logger LOGGER = LoggerFactory.getLogger(JWEController.class);

    private final PrivateKey privateKey;
		
		
		/**
     * 在构造方法里初始化刚刚生成的私钥
     * @throws NoSuchAlgorithmException
     * @throws InvalidKeySpecException
     */
    public JWEController() throws NoSuchAlgorithmException, InvalidKeySpecException {
        String privateKeyBase64 = "MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCyoFNg6oFTmt2l1Ff3+jDGLScezGzIav/w9ZBnwa09CKVd825AQVY7TWjRlTwCCf7DNq2kYI7AiBJoQXinq4ji3KELwGWeRBk38ZyNuvKWPMitGW7w0qwu7jRJA7cJhr6nsMDfql1f+cxD1Bx5J4Zb17sTlha6IyFQOCpZUR2ZHFf5vF+g1ikG02W/LF4vQwoQhRWWKRgp75TEqGI9FzCMEiIcp+xjY+zM/iHjzlSNwha97ImMG7ycSlSAdSpQd0DWebfZaZQxw6FNTjW1fpmhgrqpQF41fjGd84buOcTvpXPZByxVOedOpND/3efEQitmxJ9D+93OLwuvJjbFLQSZAgMBAAECggEAJHg4XcazPeMWEufuR/pkX+nTHWYmZar283bnk0+HM7lirfJoFaVhWj09Q+EgvdfVlHzC6hcuvh9qBrArVqxeh9b86H3RIYWM0o+5Y3SCV+s0G6dgL7oLno9SzH9+LOs+XNVpI6FQbCp/qm+RmqjXtUOv9dlEbZ+DizHUb6TwkpRPMo3BHPUKGpajmP0pgSkQz8x4MWJ0a6SVST+/E7ZbwF8PobzOQCxND2yZQah/TY1EvCCyOM6chGm0loCyC4HGTBmDm/0LcWRqgiI8GiglEijGu2Iha6UR11JaEStHoc1Sy38Orj377bhndm2l19HNOQIslp9m0VP4WUSG3GJDKwKBgQC55+HY29F0H2jy7p94+snPCKVG0uJHu0IKhFN09fChP/1q0PLJuz3Vj07YUjGneSL3RHM1D+HbMYAGnZ+7GFmwIi8FLKBVZDx4L7ENhcPMUM2q0rsBphZuHfD14Hf9I0xUiNrpyTLuVPJfK3kzx2NYQmRGo6tY+INDuI5L2HEELwKBgQD1+c4ilEQtTRvoIa+BfZ/oOBeFaYsQGlLL+8yVbsPsfH+0MMoiIY++my5rDhT//8QXNhnOI1cs7CFKELA/99Mk7y9G/4o+cMb1kAyZJU6zNoSe9Eitdyo0qQQ20NVAW+YWX0zAuAm5bttk1RvVGz/wiuOotVw6oCSR0uUYUWCptwKBgB2psy6f/G6z6FIC4y0xjuva7Ew9r99UMLhu3sYly+xewne9uU+Y8cfWovT/QG8BdCPSJzPLQfVwk4X6tpbqzry855XCxh557PAcY/rNYi2Cox5jm3Uq5B9T5bPFyj9412ARqiRtdxPyN+4ZiLBLWz2k8k0XJmr+1CsFEqdldLr/AoGAEjyqLuAlSeKMriJJO+WPhI0cGVUg7Vm2R89sdKvYtODqKvbvFaa9XJlu0JsjrXNOG5Z0RVdTcE41jaM9HhEGw5dEPxRVMJn19mDuvjAI7LqfDJX6CXprU6owWMwU84ecwI3iR+udNPVmKMywGpXBoNj7VhfUNbiH3ZPwTmRCMXMCgYBi5I1KJ7kyaHKTilJEAhiYv6XBwsJScJkdAXWuA/SdG3aWQAEc4SOrRwqmqbHWYOm827tb20kG09rHnVS+tVSShvCkv4OcAr2X0L04IX9OfvUqI5pPWiQd/VzCQrTPcelixgkUkG4Sc2dRr6gvvFOKFAAVTQrePh9clk8kd3bg+g==";
        PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(privateKeyBase64.getBytes(StandardCharsets.UTF_8));
        KeyFactory keyFactory;
        keyFactory = KeyFactory.getInstance("RSA");
        privateKey = keyFactory.generatePrivate(keySpec);
    }


    @GetMapping("/jwe")
    public void jwe(@RequestParam String encrypt) throws Exception {
        LOGGER.info("接受到的密文:{}", encrypt);
        String decrypt = decrypt(encrypt, (RSAPrivateKey) privateKey);
        LOGGER.info("解密后的内容:{}", decrypt);
    }


    public String decrypt(String jwe, RSAPrivateKey privateKey) throws Exception {
        // 创建解密器
        JWEDecrypter jweDecrypter = new RSADecrypter(privateKey);
        // 解密JWE字符串
        JWEObject jweObject = JWEObject.parse(jwe);
        jweObject.decrypt(jweDecrypter);
        // 将解密后的JSON数据转换为JSONObject对象
        Payload payload = jweObject.getPayload();
        return payload.toString();
    }

}

接下来用刚刚公钥生成的加密数据作为参数,调用接口


我们看控制台输出,接口调用成功,并成功解密


展开阅读全文

页面更新:2024-04-15

标签:密钥   字符串   接口   对象   参数   操作   格式   方法   内容   数据

1 2 3 4 5

上滑加载更多 ↓
推荐阅读:
友情链接:
更多:

本站资料均由网友自行发布提供,仅用于学习交流。如有版权问题,请与我联系,QQ:4156828  

© CopyRight 2008-2024 All Rights Reserved. Powered By bs178.com 闽ICP备11008920号-3
闽公网安备35020302034844号

Top