全部產品
Search
文件中心

ApsaraDB RDS:EncJDBC

更新時間:Jul 20, 2024

如果您希望使用全密態功能對資料庫表中的被保護資料列進行加密,並且使用Java應用程式訪問資料庫,可以使用全密態用戶端驅動程式EncJDBC接入全密態資料庫,接入操作便捷,能夠降低使用全密態功能的成本。本文介紹如何通過EncJDBC訪問全密態資料庫。

在持有使用者密鑰的情況下,EncJDBC能夠自動完成密文資料的解密並返回明文資料,過程對應用透明,應用程式只需配置幾行代碼就可以接入全密態資料庫,降低了使用全密態功能的成本。

前提條件

  • 已開通全密態功能,詳情請參見開通全密態功能

  • 已擷取加密資料庫串連資訊。您首先需要擷取加密資料庫的串連資訊,如網域名稱(host)、連接埠(port)、資料庫執行個體名(dbname)、使用者名稱(username)、密碼(password)等。

  • 已配置資料保護規則。具體操作請參見配置資料保護規則

注意事項

  • 請儲存好您設定的主要金鑰MEK

  • Java使用JDK 1.8或以上版本。

    說明

    本文中使用的Maven版本為3.9.2,使用的開發工具為IntelliJ IDEA Community Edition 2022.3.2

操作步驟

步驟一:Maven依賴配置

您需要在自己的Maven專案設定檔pom.xml中加入以下依賴項。

<dependencies>
  <dependency>
    <groupId>com.aliyun</groupId>
    <artifactId>aliyun-encdb-mysql-jdbc</artifactId>
    <version>1.0.9-1</version>
  </dependency>
</dependencies>

步驟二:通過全密態用戶端查詢(程式碼範例)

您可以像使用任意一個JDBC一樣使用我們的EncJDBC。但是您需要預先在EncJDBC中配置和您資料安全息息相關的參數,包括MEK(主要金鑰)、ENC_ALGO(密碼編譯演算法)。

具體參數解釋及取值樣本如下:

參數

取值樣本(字串類型)

說明

MEK

00112233445566778899aabbccddeeff

使用者主要金鑰,由使用者自訂指定。

常見的產生方法有:密碼產生工具(如openssl, openssl rand -hex 16)、程式設計語言中的random函數、或者從第三方Key Management Service(KMS)擷取。

取值範圍:長度為16位元組的16進位字串,且長度為32個字元。

警告

使用者主要金鑰是您訪問加密資料的根憑據,出於安全考慮,全密態資料庫不持有並管理您的主要金鑰,也不提供使用者主要金鑰的產生和備份服務,您需要自行產生使用者主要金鑰。一旦您丟失密鑰,將無法再訪問已有的資料。因此我們建議您妥善備份使用者主要金鑰。

ENC_ALGO

SM4_128_CBC

指明被保護資料將要使用的密碼編譯演算法。

取值範圍:

  • 國際演算法:

    • AES_128_GCM

    • AES_128_CTR

    • AES_128_CBC

    • AES_128_ECB(不推薦)

  • 國密演算法:

    • SM4_128_GCM(預設)

    • SM4_128_CTR

    • SM4_128_CBC

    • SM4_128_ECB(不推薦)

說明
  • AES_128_ECB和SM4_128_ECB密碼編譯演算法安全性較弱,請謹慎使用,推薦適用其他安全性更高的密碼編譯演算法。

  • 可選,預設為SM4_128_GCM。

配置MEK和ENC_ALGO

下面介紹三種配置MEKENC_ALGO的方法。如果您的JDBC配置了兩種以上的方法,優先順序順序為:JDBC properties配置 > 檔案配置 > URL配置。

說明
  • URL配置方式中,多個參數可以用&進行拼接。

  • 以下三種串連方式,MEK均在用戶端本地進行處理、並以安全方式分發(信封加密)到服務端,始終保證MEK不泄露。

JDBC properties配置

標準的JDBC在串連時,可以通過Properties設定使用者自訂屬性。以下是一個通過這種方式配置JDBC屬性並運行JDBC的例子:

// 準備好網域名稱(hostname)、連接埠(port)、資料庫執行個體名(dbname)、使用者名稱(username)、密碼(password)等串連資訊
// ...

String mek=...;
String encAlgo=...;

Properties props = new Properties();
props.setProperty("user", username);
props.setProperty("password", password);
props.setProperty("MEK", mek);
props.setProperty("ENC_ALGO", encAlgo);

String dbUrl = String.format("jdbc:mysql:encdb://%s:%s/%s", hostname, port, dbname);
Class.forName("com.aliyun.encdb.mysql.jdbc.EncDriver");
Connection connection = DriverManager.getConnection(dbUrl, props);

// ... 發起查詢 ...
檔案配置

支援通過設定檔來匯入參數方式,配置需要的MEK等參數。您可以在專案中設定一個名為encJdbcConfigFile的property,將值設定為設定檔路徑即可(預設時,預設使用encjdbc.conf的檔案)。

設定檔的內容如下:

MEK=
ENC_ALGO=

您可以通過以下兩種方式放置設定檔的位置:

  • 將檔案放入專案中的resources目錄下,如下圖所示:image.png

  • 將檔案放入專案根目錄,即程式的運行時目錄。

通過檔案配置方式,在做完檔案配置後,您可以不用在程式中做額外的配置,如下面所示:

// 準備好網域名稱(hostname)、連接埠(port)、資料庫執行個體名(dbname)、使用者名稱(username)、密碼(password)等串連資訊
// ...

String dbUrl = String.format("jdbc:mysql:encdb://%s:%s/%s", hostname, port, dbname);
Class.forName("com.aliyun.encdb.mysql.jdbc.EncDriver");
Connection connection = DriverManager.getConnection(dbUrl, username, password);

// ... 發起查詢 ...
URL配置

支援通過URL連結中嵌入MEKENC_ALGO等參數。如下面所示:

// 準備好網域名稱(hostname)、連接埠(port)、資料庫執行個體名(dbname)、使用者名稱(username)、密碼(password)等串連資訊
// ...

String mek=...;
String encAlgo=...;

String dbUrl = String.format("jdbc:mysql:encdb://%s:%s/%s?MEK=%s&ENC_ALGO=%s", hostname, port, dbname, mek, encAlgo);
Class.forName("com.aliyun.encdb.mysql.jdbc.EncDriver");
Connection connection = DriverManager.getConnection(dbUrl, username, password);

// ... 發起查詢 ...

完整程式碼範例(以JDBC properties配置為例)

// 以下網域名稱(hostname)、連接埠(port)、資料庫執行個體名(dbname)、使用者名稱(username)、密碼(password)等串連資訊需要更新為您的執行個體資訊
String hostname = "hostname";
String port = "port";
String dbname = "db";
String username = "user";
String password = "password";

String mek="00112233445566778899aabbccddeeff";  // 只是樣本,建議用更複雜的密鑰
String encAlgo="SM4_128_CBC";

Properties props = new Properties();
props.setProperty("user", username);
props.setProperty("password", password);
props.setProperty("MEK", mek);
props.setProperty("ENC_ALGO", encAlgo);

String dbUrl = String.format("jdbc:mysql:encdb://%s:%s/%s", hostname, port, dbname);
Class.forName("com.aliyun.encdb.mysql.jdbc.EncDriver");
Connection connection = DriverManager.getConnection(dbUrl, props);

int[] intData = {1, 2, 3, 4, 5, 6};
String[] strData = {"abc", "bcd", "1", "def", "efg", "fgi"};

// create table
connection.createStatement().executeUpdate("drop table if exists test");
connection.createStatement().executeUpdate("create table test (a int, b text)");

// insert data
for (int i = 0; i < 6; i++) {
    PreparedStatement pstmt = connection.prepareStatement("insert into test values (?,?)");
    pstmt.setInt(1, intData[i]);
    pstmt.setString(2, strData[i]);
    pstmt.executeUpdate();
}

// check plaintext data
ResultSet rs = connection.createStatement().executeQuery("select * from test");
while (rs.next()) {
    for (int i = 0; i < rs.getMetaData().getColumnCount(); i++) {
        System.out.print(rs.getString(i + 1));
        System.out.print("\t");
    }
    System.out.print("\n");
}

輸出結果:

1	abc	
2	bcd	
3	cde	
4	def	
5	efg	
6	fgi	

常見問題

  • Q:運行程式時報錯Exception in thread "main" java.lang.IllegalAccessError: class com.alibaba.encdb.common.SymCrypto (in unnamed module @0x5c0369c4) cannot access class com.sun.crypto.provider.SunJCE (in module java.base) because module java.base does not export com.sun.crypto.provider to unnamed module @0x5c0369c4,如何處理?

    A: 該報錯可能是因為您的JDK版本較高導致的模組間許可權問題,請在運行時添加VM option參數--add-exports=java.base/com.sun.crypto.provider=ALL-UNNAMED將com.sun.crypto.provider匯出給Unnamed模組,以解決存取權限問題。

  • Q:運行程式時報錯failed in mek provision: you might have an incorrect mek setting. Detail:gcmEncrypt error,如何處理?

    A:該問題常見於Oracle系列的JDK,如需解決此問題,您可以任選如下兩種方式之一:

    • 使用Amazon Correto系列的JDK。

    • 仍然使用Oracle系列的JDK,但需要手動設定Security provider。具體步驟如下:

      1. 找到JDK的安裝路徑。

      2. 安裝路徑/conf/security/路徑下,找到java.security檔案。

      3. 編輯java.security檔案,在List of providers and their preference orders (see above):地區,補充如下內容:

        security.provider.14=org.bouncycastle.jce.provider.BouncyCastleProvider