API接口脫敏:如何安全地處理敏感數(shù)據(jù)?
環(huán)境:SpringBoot2.6.12
API接口脫敏是一種保護(hù)敏感數(shù)據(jù)的重要方法。它涉及到在數(shù)據(jù)傳輸和存儲(chǔ)過(guò)程中,將敏感數(shù)據(jù)替換為無(wú)意義或偽裝的數(shù)據(jù),以防止未經(jīng)授權(quán)的訪問(wèn)和泄露。下面是一些關(guān)于如何安全地處理敏感數(shù)據(jù)的方法:
- 數(shù)據(jù)加密:使用加密算法對(duì)敏感數(shù)據(jù)進(jìn)行加密,以確保即使數(shù)據(jù)在傳輸過(guò)程中被截獲,也無(wú)法被解密。常見(jiàn)的加密算法包括對(duì)稱加密算法(如AES)和非對(duì)稱加密算法(如RSA)。
- 數(shù)據(jù)脫敏:使用數(shù)據(jù)脫敏技術(shù),將敏感數(shù)據(jù)替換為無(wú)意義或偽裝的數(shù)據(jù)。例如,將真實(shí)的手機(jī)號(hào)碼替換為隨機(jī)生成的虛假號(hào)碼,或?qū)⒄鎸?shí)的姓名替換為隨機(jī)生成的虛假姓名。
- 訪問(wèn)控制:對(duì)API接口進(jìn)行訪問(wèn)控制,只允許經(jīng)過(guò)身份驗(yàn)證和授權(quán)的用戶訪問(wèn)。使用身份驗(yàn)證令牌(如JWT)或OAuth等協(xié)議對(duì)用戶進(jìn)行身份驗(yàn)證和授權(quán)。
- 日志記錄:對(duì)API接口的訪問(wèn)和使用情況進(jìn)行詳細(xì)的日志記錄,以便在發(fā)生安全事件時(shí)能夠迅速發(fā)現(xiàn)和應(yīng)對(duì)。
- 數(shù)據(jù)傳輸安全:使用HTTPS協(xié)議進(jìn)行數(shù)據(jù)傳輸,以確保數(shù)據(jù)傳輸過(guò)程中的安全性。
- 數(shù)據(jù)存儲(chǔ)安全:將敏感數(shù)據(jù)存儲(chǔ)在加密的數(shù)據(jù)庫(kù)中,并使用訪問(wèn)控制列表(ACL)等技術(shù)對(duì)數(shù)據(jù)庫(kù)進(jìn)行訪問(wèn)控制。
項(xiàng)目中開(kāi)發(fā)的API接口,可能有些接口返回的字段信息不能以明文的形式傳輸,這時(shí)候我們?cè)撊绾芜M(jìn)行處理呢?以下給出3中方式:
數(shù)據(jù)庫(kù)層面處理
在SQL查詢的時(shí)候進(jìn)行處理,但這種效率不高,一般不會(huì)這樣處理。如下:
SELECT
CONCAT(LEFT( idNo, 6), '********', RIGHT (idNo, 4)) as idNo
FROM
users where id = 7;
查詢結(jié)果:
以掩碼的方式處理部分?jǐn)?shù)據(jù)
數(shù)據(jù)加密處理
該種方式就是將你需要處理的字段完全通過(guò)對(duì)稱加密或者HASH算法進(jìn)行處理。在寫(xiě)入或者查詢數(shù)據(jù)的時(shí)候?qū)γ舾袛?shù)據(jù)進(jìn)行加密/解密處理。示例如下:
import java.sql.*;
public class JdbcSensitiveDataProcess {
public static void main(String[] args) {
try {
// 連接數(shù)據(jù)庫(kù)
Connection conn = DataSourceUtils.getConnection() ;
// 創(chuàng)建Statement對(duì)象
Statement stmt = conn.createStatement();
// 執(zhí)行查詢語(yǔ)句
ResultSet rs = stmt.executeQuery("SELECT id, name, encrypted_data FROM t_xxx");
// 遍歷結(jié)果集
while (rs.next()) {
int id = rs.getInt("id");
String name = rs.getString("name");
String encryptedData = rs.getString("encrypted_data");
// 對(duì)加密數(shù)據(jù)進(jìn)行解密處理
String decryptedData = decryptData(encryptedData);
// 輸出解密后的數(shù)據(jù)
System.out.println("ID: " + id + ", Name: " + name + ", Decrypted Data: " + decryptedData);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
// 關(guān)閉數(shù)據(jù)庫(kù)相關(guān)資源
}
}
// 解密數(shù)據(jù)的方法,這里只是示例,實(shí)際需要根據(jù)具體的加密算法來(lái)實(shí)現(xiàn)
private static String decryptData(String encryptedData) {
// 解密邏輯...
// Cipher cipher = Cipher.getInsance(...) ;
return decryptedData;
}
}
JSON序列化時(shí)處理
API接口在生成JSON字符串的時(shí)候(序列化時(shí))將敏感信息進(jìn)行掩碼處理或者加密處理,接下來(lái)將詳細(xì)介紹第三種方式"JSON序列化時(shí)處理"。
JSON序列化處理脫敏
使用jackson時(shí)在對(duì)對(duì)象序列化時(shí)進(jìn)行敏感字段的處理,為了簡(jiǎn)單我們通過(guò)自定義注解的方式來(lái)實(shí)現(xiàn)該功能。
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
// 該注解必須,不然jackson不會(huì)識(shí)別該注解
@JacksonAnnotationsInside
// 指定我們需要序列化字段的實(shí)現(xiàn)
@JsonSerialize(using = SensitiveSerializer.class)
public @interface Sensitive {
/**
* 正則表達(dá)式
* @return
*/
String pattern() default "" ;
/**
* 正則表達(dá)式的第幾個(gè)分組;該分組將被替換為掩碼mask
* @return
*/
int group() default 0 ;
/**
* 掩碼
* @return
*/
String mask() default "*" ;
public interface Pattern {
/**身份證*/
String ID = "(\\w{5})(\\w+)(\\w{3})" ;
/**電話*/
String PHONE = "(\\w){3}(\\w+)(\\w{2})" ;
/**私密*/
String KEY = "(\\w+)" ;
}
}
上面的注釋類(lèi)都有詳細(xì)的說(shuō)明,不再做過(guò)多的說(shuō)明。
自定義序列化實(shí)現(xiàn)
public class SensitiveSerializer extends JsonSerializer<String> implements ContextualSerializer {
private Sensitive sensitive ;
@Override
public void serialize(String value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
String val = value ;
if (sensitive != null) {
String pattern = sensitive.pattern() ;
int groupIndex = sensitive.group() ;
String mask = sensitive.mask() ;
if (pattern.length() > 0) {
Pattern pa = Pattern.compile(pattern) ;
Matcher matcher = pa.matcher(value) ;
if (matcher.matches()) {
String group = matcher.group(groupIndex) ;
if (mask.length() > 0 && group.length() > 0) {
val = val.replace(group, String.join("", Collections.nCopies(group.length(), mask))) ;
}
}
}
}
gen.writeObject(val) ;
}
@Override
public JsonSerializer<?> createContextual(SerializerProvider prov, BeanProperty property)
throws JsonMappingException {
sensitive = property.getAnnotation(Sensitive.class) ;
return this ;
}
}
該類(lèi)實(shí)現(xiàn)了ContextualSerializer通過(guò)該類(lèi)的回調(diào)方法能夠用來(lái)讀取當(dāng)前字段上的注解信息。
public class Users {
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+10")
private Date birthday ;
private Integer age ;
private String name ;
// 在需要處理的字段上加入上面定義的注解,這里我們也可以自定義表達(dá)式
@Sensitive(pattern = Sensitive.Pattern.ID)
private String idNo
}
運(yùn)行效果:
idNo按照指定的規(guī)則進(jìn)行了掩碼處理
完畢?。?!