Spring Boot 安全 API 構(gòu)建之加密解密功能的實(shí)踐記錄
一、描述
在當(dāng)前的數(shù)字化時(shí)代背景下,數(shù)據(jù)安全已成為企業(yè)絕不可忽視的關(guān)鍵領(lǐng)域。為了確保數(shù)據(jù)傳輸?shù)睦喂贪踩?,對API接口實(shí)施加密處理成為了必不可少的一環(huán)。本文將闡述如何在Spring Boot 3.3環(huán)境中迅速落實(shí)API加密的最佳方案,具體采用RSA非對稱加密算法進(jìn)行說明。
1、選擇合適的加密算法
- 對稱加密:如 AES(Advanced Encryption Standard),適用于大量數(shù)據(jù)的快速加密和解密,但需要安全地管理密鑰。
- 非對稱加密:如 RSA(Rivest-Shamir-Adleman),使用公鑰和私鑰對,公鑰用于加密,私鑰用于解密,適合加密少量數(shù)據(jù)和密鑰交換。
2、密鑰管理
- 生成強(qiáng)密鑰:使用安全的隨機(jī)數(shù)生成器來生成密鑰,確保密鑰的隨機(jī)性和強(qiáng)度。
- 安全存儲:將密鑰存儲在安全的地方,如密鑰管理系統(tǒng)或加密的配置文件中。避免將密鑰硬編碼在代碼中。
- 密鑰更新:定期更新密鑰,以降低密鑰被破解的風(fēng)險(xiǎn)。
3、數(shù)據(jù)加密
- 對敏感數(shù)據(jù)加密:如用戶密碼、個(gè)人信息等,在存儲和傳輸過程中進(jìn)行加密。
- 端到端加密:如果可能,實(shí)現(xiàn)端到端加密,確保數(shù)據(jù)在整個(gè)傳輸過程中都是加密的,只有發(fā)送方和接收方能夠解密。
- 加密傳輸:使用 HTTPS 確保數(shù)據(jù)在網(wǎng)絡(luò)傳輸過程中的安全。Spring Boot 3 可以很容易地配置 HTTPS。
4、防止加密漏洞
- 避免弱加密算法:不要使用已被破解或不安全的加密算法。
- 防止加密錯誤配置:仔細(xì)配置加密庫和框架,避免錯誤的配置導(dǎo)致安全漏洞。
- 輸入驗(yàn)證:對加密輸入進(jìn)行嚴(yán)格的驗(yàn)證,防止惡意輸入導(dǎo)致加密失敗或安全漏洞。
5、安全日志記錄
- 記錄加密相關(guān)事件:如密鑰生成、加密和解密操作等,以便進(jìn)行審計(jì)和故障排除。
- 保護(hù)日志安全:確保日志文件的安全存儲,防止敏感信息泄露。
6、測試和監(jiān)控
- 安全測試:進(jìn)行安全測試,包括加密功能的測試,以確保加密的正確性和安全性。
- 監(jiān)控異常:監(jiān)控加密相關(guān)的異常情況,如加密失敗、密鑰泄露等,并及時(shí)采取措施。
二、RSA加密解密實(shí)現(xiàn)步驟
第一種寫法
1. 配置Spring Boot的依賴
以下是一個(gè)基本的pom.xml文件:
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>spring-boot-rsa</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>spring-boot-rsa</name>
<description>Demo project for Spring Boot RSA encryption and decryption</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.0.0</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- 其他依賴項(xiàng)可以根據(jù)需要添加 -->
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>2. 配置RSA密鑰
首先,在application.yml文件中配置RSA公鑰和私鑰。注意,由于密鑰可能很長,你可能需要適當(dāng)?shù)負(fù)Q行或使用YAML的多行字符串語法。
rsa:
open: true # 是否開啟加密
showLog: true # 是否打印加解密日志
publicKey: '你的RSA公鑰' # RSA公鑰,軟件生成
privateKey: '你的RSA私鑰' # RSA私鑰,軟件生成注意:在實(shí)際應(yīng)用中,請不要將密鑰硬編碼在配置文件中,特別是私鑰。應(yīng)該使用更安全的方式來管理密鑰,比如環(huán)境變量、密鑰管理服務(wù)(KMS)或安全的配置文件存儲。
3. 讀取配置并初始化密鑰
接下來,在Spring Boot應(yīng)用中讀取這些配置,并初始化RSA密鑰。
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;
@Configuration
public class RsaConfig {
@Value("${rsa.publicKey}")
private String publicKey;
@Value("${rsa.privateKey}")
private String privateKey;
@Bean
public PublicKey rsaPublicKey() throws Exception {
byte[] keyBytes = Base64.getDecoder().decode(publicKey.getBytes());
X509EncodedKeySpec spec = new X509EncodedKeySpec(keyBytes);
KeyFactory kf = KeyFactory.getInstance("RSA");
return kf.generatePublic(spec);
}
@Bean
public PrivateKey rsaPrivateKey() throws Exception {
byte[] keyBytes = Base64.getDecoder().decode(privateKey.getBytes());
PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(keyBytes);
KeyFactory kf = KeyFactory.getInstance("RSA");
return kf.generatePrivate(spec);
}
}4. 使用RSA密鑰進(jìn)行加密和解密
現(xiàn)在,你可以在服務(wù)類中使用這些密鑰進(jìn)行加密和解密操作。
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import javax.crypto.Cipher;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.util.Base64;
@Service
public class RsaService {
private final PublicKey publicKey;
private final PrivateKey privateKey;
@Autowired
public RsaService(PublicKey publicKey, PrivateKey privateKey) {
this.publicKey = publicKey;
this.privateKey = privateKey;
}
public String encrypt(String data) throws Exception {
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
byte[] encryptedBytes = cipher.doFinal(data.getBytes());
return Base64.getEncoder().encodeToString(encryptedBytes);
}
public String decrypt(String encryptedData) throws Exception {
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.DECRYPT_MODE, privateKey);
byte[] decryptedBytes = cipher.doFinal(Base64.getDecoder().decode(encryptedData));
return new String(decryptedBytes);
}
}5. 測試加密和解密
最后,你可以編寫一個(gè)簡單的控制器或測試類來驗(yàn)證加密和解密功能是否正常工作。
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class RsaController {
private final RsaService rsaService;
@Autowired
public RsaController(RsaService rsaService) {
this.rsaService = rsaService;
}
@GetMapping("/encrypt")
public String encrypt(@RequestParam String data) throws Exception {
return rsaService.encrypt(data);
}
@GetMapping("/decrypt")
public String decrypt(@RequestParam String encryptedData) throws Exception {
return rsaService.decrypt(encryptedData);
}
}現(xiàn)在,你可以啟動Spring Boot應(yīng)用,并通過訪問/encrypt和/decrypt端點(diǎn)來測試RSA加密和解密功能。請確保在測試過程中使用合適的密鑰對,并且不要在生產(chǎn)環(huán)境中暴露私鑰。
第二種寫法
1、創(chuàng)建RSA工具類
創(chuàng)建一個(gè)RSA工具類來處理加密和解密操作。這個(gè)類將包含生成密鑰對、加密和解密的方法。
package com.example.springbootrsa.util;
import javax.crypto.Cipher;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;
public class RSAUtil {
// 生成密鑰對
public static KeyPair generateKeyPair() throws Exception {
KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
keyGen.initialize(2048);
return keyGen.generateKeyPair();
}
// 公鑰加密
public static String encrypt(String data, PublicKey publicKey) throws Exception {
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
byte[] encryptedBytes = cipher.doFinal(data.getBytes("UTF-8"));
return Base64.getEncoder().encodeToString(encryptedBytes);
}
// 私鑰解密
public static String decrypt(String encryptedData, PrivateKey privateKey) throws Exception {
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.DECRYPT_MODE, privateKey);
byte[] decryptedBytes = cipher.doFinal(Base64.getDecoder().decode(encryptedData));
return new String(decryptedBytes, "UTF-8");
}
// 公鑰字符串表示
public static String getPublicKeyString(PublicKey publicKey) {
return Base64.getEncoder().encodeToString(publicKey.getEncoded());
}
// 私鑰字符串表示
public static String getPrivateKeyString(PrivateKey privateKey) {
return Base64.getEncoder().encodeToString(privateKey.getEncoded());
}
// 從字符串重建公鑰
public static PublicKey getPublicKeyFromString(String key) throws Exception {
byte[] keyBytes = Base64.getDecoder().decode(key);
X509EncodedKeySpec spec = new X509EncodedKeySpec(keyBytes);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
return keyFactory.generatePublic(spec);
}
// 從字符串重建私鑰
public static PrivateKey getPrivateKeyFromString(String key) throws Exception {
byte[] keyBytes = Base64.getDecoder().decode(key);
PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(keyBytes);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
return keyFactory.generatePrivate(spec);
}
}2、創(chuàng)建Spring Boot控制器
創(chuàng)建一個(gè)簡單的Spring Boot控制器來演示如何使用RSA加密和解密
package com.example.springbootrsa.controller;
import com.example.springbootrsa.util.RSAUtil;
import org.springframework.web.bind.annotation.*;
import java.security.KeyPair;
@RestController
@RequestMapping("/api")
public class RSAController {
private KeyPair keyPair;
public RSAController() throws Exception {
this.keyPair = RSAUtil.generateKeyPair();
}
@GetMapping("/encrypt")
public String encrypt(@RequestParam String data) throws Exception {
return RSAUtil.encrypt(data, keyPair.getPublic());
}
@GetMapping("/decrypt")
public String decrypt(@RequestParam String encryptedData) throws Exception {
return RSAUtil.decrypt(encryptedData, keyPair.getPrivate());
}
@GetMapping("/publicKey")
public String getPublicKey() {
try {
return RSAUtil.getPublicKeyString(keyPair.getPublic());
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
@GetMapping("/privateKey")
public String getPrivateKey() {
try {
return RSAUtil.getPrivateKeyString(keyPair.getPrivate());
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
}3、測試RSA加密和解密
現(xiàn)在,您可以運(yùn)行Spring Boot應(yīng)用程序,并通過訪問以下端點(diǎn)來測試RSA加密和解密:
- 獲取公鑰:
GET /api/publicKey - 獲取私鑰:
GET /api/privateKey(請注意,在生產(chǎn)環(huán)境中,私鑰應(yīng)該保密) - 加密數(shù)據(jù):
GET /api/encrypt?data=yourData - 解密數(shù)據(jù):
GET /api/decrypt?encryptedData=yourEncryptedData
三、AES加密解密實(shí)現(xiàn)步驟
1. 創(chuàng)建Spring Boot項(xiàng)目
你可以使用Spring Initializr創(chuàng)建一個(gè)新的Spring Boot項(xiàng)目,選擇以下依賴項(xiàng):
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>spring-boot-rsa</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>spring-boot-rsa</name>
<description>Demo project for Spring Boot RSA encryption and decryption</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.0.0</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- 其他依賴項(xiàng)可以根據(jù)需要添加 -->
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>2. 添加AES加密解密工具類
首先,我們需要一個(gè)工具類來處理AES加密和解密操作。
package com.example.demo.util;
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.util.Base64;
public class AESUtil {
// 生成AES密鑰
public static SecretKey generateKey(int n) throws Exception {
KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
keyGenerator.init(n);
SecretKey secretKey = keyGenerator.generateKey();
return secretKey;
}
// 將密鑰轉(zhuǎn)換為字符串
public static String encodeKey(SecretKey key) {
return Base64.getEncoder().encodeToString(key.getEncoded());
}
// 將字符串轉(zhuǎn)換為密鑰
public static SecretKey decodeKey(String encodedKey) {
byte[] decodedKey = Base64.getDecoder().decode(encodedKey);
return new SecretKeySpec(decodedKey, 0, decodedKey.length, "AES");
}
// 加密
public static String encrypt(String data, SecretKey key) throws Exception {
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.ENCRYPT_MODE, key);
byte[] encryptedData = cipher.doFinal(data.getBytes("UTF-8"));
return Base64.getEncoder().encodeToString(encryptedData);
}
// 解密
public static String decrypt(String encryptedData, SecretKey key) throws Exception {
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.DECRYPT_MODE, key);
byte[] decodedData = Base64.getDecoder().decode(encryptedData);
byte[] decryptedData = cipher.doFinal(decodedData);
return new String(decryptedData, "UTF-8");
}
}3. 創(chuàng)建控制器來處理加密和解密請求
接下來,我們創(chuàng)建一個(gè)Spring Boot控制器來處理加密和解密請求。
package com.example.demo.controller;
import com.example.demo.util.AESUtil;
import org.springframework.web.bind.annotation.*;
import javax.crypto.SecretKey;
import java.util.HashMap;
import java.util.Map;
@RestController
@RequestMapping("/api")
public class AESController {
// 用于存儲密鑰的變量(在實(shí)際應(yīng)用中,密鑰應(yīng)該安全存儲)
private static SecretKey secretKey;
static {
try {
secretKey = AESUtil.generateKey(256); // 256位AES密鑰
} catch (Exception e) {
e.printStackTrace();
}
}
@GetMapping("/encrypt")
public Map<String, String> encrypt(@RequestParam String data) {
Map<String, String> response = new HashMap<>();
try {
String encryptedData = AESUtil.encrypt(data, secretKey);
response.put("encryptedData", encryptedData);
} catch (Exception e) {
response.put("error", e.getMessage());
}
return response;
}
@GetMapping("/decrypt")
public Map<String, String> decrypt(@RequestParam String encryptedData) {
Map<String, String> response = new HashMap<>();
try {
String decryptedData = AESUtil.decrypt(encryptedData, secretKey);
response.put("decryptedData", decryptedData);
} catch (Exception e) {
response.put("error", e.getMessage());
}
return response;
}
@GetMapping("/key")
public Map<String, String> getKey() {
Map<String, String> response = new HashMap<>();
try {
String encodedKey = AESUtil.encodeKey(secretKey);
response.put("encodedKey", encodedKey);
} catch (Exception e) {
response.put("error", e.getMessage());
}
return response;
}
}4. 啟動Spring Boot應(yīng)用程序
確保你的application.properties或application.yml文件配置正確,然后運(yùn)行Spring Boot應(yīng)用程序。
5. 測試API
你可以使用瀏覽器或工具(如Postman)來測試這些API。
- 獲取密鑰:GET http://localhost:8080/api/key
- 加密數(shù)據(jù):GET http://localhost:8080/api/encrypt?data=HelloWorld
- 解密數(shù)據(jù):GET http://localhost:8080/api/decrypt?encryptedData=<Base64EncodedEncryptedData>
注意事項(xiàng)
- 密鑰管理:在實(shí)際應(yīng)用中,密鑰應(yīng)該安全存儲和管理,不要硬編碼在代碼中。
- 異常處理:在生產(chǎn)代碼中,應(yīng)該有更完善的異常處理機(jī)制。
- HTTPS:確保你的API通過HTTPS進(jìn)行通信,以保護(hù)傳輸中的數(shù)據(jù)。
到此這篇關(guān)于Spring Boot 安全 API 構(gòu)建:加密解密功能的卓越實(shí)踐的文章就介紹到這了,更多相關(guān)Spring Boot API 加密解密內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
springboot 如何重定向redirect 并隱藏參數(shù)
這篇文章主要介紹了springboot 如何重定向redirect 并隱藏參數(shù)的操作,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-09-09
java 數(shù)值類型分秒時(shí)間格式化的實(shí)例代碼
這篇文章主要介紹了java 數(shù)值類型分秒時(shí)間格式化的實(shí)例代碼的相關(guān)資料,將秒或分鐘的值轉(zhuǎn)換為xx天xx小時(shí)xx分鐘xx秒 如果 “xx” 為0 自動缺省,需要的朋友可以參考下2017-07-07
Spring BeanFactory和FactoryBean有哪些區(qū)別
這篇文章主要介紹了Spring BeanFactory 與 FactoryBean 的區(qū)別詳情,BeanFactory 和 FactoryBean 的區(qū)別卻是一個(gè)很重要的知識點(diǎn),在本文中將結(jié)合源碼進(jìn)行分析講解,需要的小伙伴可以參考一下2023-02-02
Spring使用Configuration注解管理bean的方式詳解
在Spring的世界里,Configuration注解就像是一位細(xì)心的園丁,它的主要職責(zé)是在這個(gè)繁花似錦的園子里,幫助我們聲明和管理各種各樣的bean,本文給大家介紹了在Spring中如何優(yōu)雅地管理你的bean,需要的朋友可以參考下2024-05-05
細(xì)致解讀希爾排序算法與相關(guān)的Java代碼實(shí)現(xiàn)
這篇文章主要介紹了希爾排序算法與相關(guān)的Java代碼實(shí)現(xiàn),希爾排序的時(shí)間復(fù)雜度根據(jù)步長序列的不同而不同,需要的朋友可以參考下2016-05-05
Java中synchronized實(shí)現(xiàn)原理詳解
這篇文章主要介紹了Java中synchronized實(shí)現(xiàn)原理詳解,涉及synchronized實(shí)現(xiàn)同步的基礎(chǔ),Java對象頭,Monitor,Mark Word,鎖優(yōu)化,自旋鎖等相關(guān)內(nèi)容,具有一定借鑒價(jià)值,需要的朋友可以參考下。2017-11-11
關(guān)于Filter中獲取請求體body后再次讀取的問題
這篇文章主要介紹了關(guān)于Filter中獲取請求體body后再次讀取的問題,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-03-03

