本文中含有需要您注意的重要提示信息,忽略該信息可能對您的業務造成影響,請務必仔細閱讀。
本文介紹如何通過客戶端使用全密態數據庫功能。
前提條件
已開通全密態數據庫。更多信息,請參見開通全密態數據庫。
已定義敏感數據。具體操作,請參見定義敏感數據。
price
,miles
,secret
為敏感數據列CREATE TABLE example ( id INTEGER, name VARCHAR, price enc_int4, miles enc_float4, secret enc_text, PRIMARY KEY (id) );
獲取加密數據庫連接信息。您首先需要獲取加密數據庫的連接信息,如域名(host)、端口(port)、數據庫實例名(dbname)、用戶名(username)、密碼(password)等。實例內外網地址獲取方式請參見查看或修改連接地址和端口。
本文中介紹的應用程序使用的開發語言為Java,請確保已具備Java開發環境,建議使用Java版本為
1.8
及以上,Maven版本為3.9.2
,使用的開發工具為IntelliJ IDEA Community Edition 2022.3.2
。
注意事項
請保存好您設置的主密鑰MEK
。
客戶端使用示例
全密態數據庫對查詢結果中的目標敏感數據進行加密。為了讓應用能夠使用全密態功能,全密態支持以下客戶端接入:
接入方式 | 說明 | 是否需要改動業務代碼 | |
應用程序 | EncJDBC | 自動識別加密數據類型并對數據進行加密解密。 | (推薦使用)基本不需要改動業務代碼。 |
EncDB SDK | 在客戶端調用EncDB SDK提供的加解密函數,對明文數據進行加密或者對密文數據進行解密。 | 需要。 | |
psql命令行工具 | 直接連接數據庫查詢,只顯示密文數據。 | 僅用于查詢,不進行業務開發,無需改動業務代碼。 | |
DMS控制臺等可視化交互工具 |
EncJDBC
下載驅動程序及依賴配置
下載EncJDBC驅動。
EncJDBC
依賴于社區提供的PostgreSQL驅動工作。RDS PostgreSQL小版本
服務端encdb插件版本號
客戶端EncDB依賴包
20230830或以上版本
1.1.13或以上版本
Maven依賴配置。
說明本示例以Maven構建Java項目為例。
通過如下命令將
EncJDBC
依賴包安裝至您的本地倉庫:mvn install:install-file -DgroupId=com.alibaba.encdb -DartifactId=<安裝的Jar包名> -Dversion=<安裝的Jar版本> -Dpackaging=jar -Dfile=<安裝的Jar包文件名>
示例:
mvn install:install-file -DgroupId=com.alibaba.encdb -DartifactId=encjdbc -Dversion=1.0.6 -Dpackaging=jar -Dfile=D:\encdb\libs\encjdbc-1.0.6.jar
說明此示例中EncDB依賴包在
D:\encdb\libs
路徑下。此示例使用的Maven版本為
3.9.2
,如果您安裝報錯,請升級Maven版本后再試。
在本地倉庫安裝
EncJDBC
依賴包的基礎上,您需要在自己的Maven項目pom.xml配置文件中加入以下依賴項。<dependencies> ... <dependency> <groupId>com.alibaba.encdb</groupId> <artifactId>encjdbc</artifactId> <version>1.0.6</version> </dependency> <!-- https://mvnrepository.com/artifact/org.bouncycastle/bcprov-jdk15on --> <dependency> <groupId>org.bouncycastle</groupId> <artifactId>bcprov-jdk15on</artifactId> <version>1.62</version> </dependency> <!-- https://mvnrepository.com/artifact/org.bouncycastle/bcpkix-jdk15on --> <dependency> <groupId>org.bouncycastle</groupId> <artifactId>bcpkix-jdk15on</artifactId> <version>1.62</version> </dependency> <dependency> <groupId>com.alibaba.fastjson2</groupId> <artifactId>fastjson2</artifactId> <version>2.0.2</version> </dependency> <!-- https://mvnrepository.com/artifact/org.postgresql/postgresql --> <dependency> <groupId>org.postgresql</groupId> <artifactId>postgresql</artifactId> <version>42.2.23</version> </dependency> <dependency> <groupId>com.google.guava</groupId> <artifactId>guava</artifactId> <version>24.1.1-jre</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.2.4</version> </dependency> <dependency> <groupId>org.jgrapht</groupId> <artifactId>jgrapht-core</artifactId> <!-- jgrapht does not support java 1.8 since 1.5.0 --> <version>1.4.0</version> </dependency> ... </dependencies>
通過全密態客戶端查詢(代碼示例)
本示例所展示的代碼僅用于演示配置方式,請勿在實際業務代碼中將password
、mek
以明文方式設置在代碼中,建議使用外部配置文件或環境變量等其他方式進行處理后,再在代碼中引用。
URL配置說明
您可以像使用任意一個JDBC一樣使用
EncJDBC
。但是您需要預先在EncJDBC
中配置和您數據安全相關的如下信息。// 準備好域名(hostname)、端口(port)、數據庫名稱(dbname)、用戶名(username)、密碼(password)等連接信息 // 詳見數據安全相關參數 String mek=...; String encAlgo=...; String dbUrl = String.format("encjdbc:postgresql://%s:%s/%s?mek=%s&enc_algo=%s", hostname, port, dbname, mek, encAlgo); Class.forName("com.alibaba.encdb.encjdbc.EncDriver"); Connection dbConnection = DriverManager.getConnection(dbUrl, username, password); // ... 發起查詢 ...
參數
取值示例(字符串類型)
說明
mek
0x00112233445566778899aabbccddeeff
用戶主密鑰,由用戶自定義指定。
常見的生成方法有:密碼生成工具(如openssl, openssl rand -hex 16)、編程語言中的random函數、或者從第三方密鑰管理服務(KMS)獲取。
取值范圍:十六進制字符串,長度為32個字符。
警告用戶主密鑰是您訪問加密數據的根憑據,出于安全考慮,全密態數據庫不持有并管理您的主密鑰,也不提供用戶主密鑰的生成和備份服務,您需要自行生成用戶主密鑰。一旦您丟失密鑰,將無法再訪問已有的數據。因此我們建議您妥善備份用戶主密鑰。
enc_algo
SM4_128_CBC
加密算法。取值范圍:
國際算法:
AES_128_GCM
AES_128_CBC
AES_128_ECB
國密算法:
SM4_128_GCM
SM4_128_CBC(默認值)
SM4_128_ECB
說明CTR加密算法暫不支持。
AES_128_ECB和SM4_128_ECB加密算法安全性較弱,請謹慎使用,推薦適用其他安全性更高的加密算法。
enc_scheme
RND
加密方案。取值范圍:
RND(默認值):隨機加密。
DET:確定性加密。
說明當
enc_algo
取值為AES_128_ECB或SM4_128_ECB時,該參數取值無效。dek_gen_mode
ENCLAVE
生成數據密鑰的方式。取值范圍:
ENCLAVE(默認值):由數據庫服務端在可信Enclave內生成數據密鑰DEK。
LOCAL:由客戶端生成數據密鑰DEK。
stateless
true
加密數據庫Stateless模式。取值范圍:
true(默認值):MEK在鏈接斷開后不會失效。
false:MEK在鏈接斷開后失效。
說明URL配置方式中,多個參數可以用
&
進行拼接。mek
及其他參數均在客戶端本地進行處理、并以安全方式進行分發(信封加密)到服務端,始終保證mek
不泄露。
完整代碼示例
// 以下域名(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"; String dbUrl = String.format("encjdbc:postgresql://%s:%d/%s?mek=%s&enc_algo=%s", hostname, port, dbname, mek, encAlgo); Class.forName("com.alibaba.encdb.encjdbc.EncDriver"); Connection dbConnection = DriverManager.getConnection(dbUrl, username, password); // create table dbConnection.createStatement().executeUpdate("DROP TABLE IF EXISTS example"); dbConnection.createStatement().executeUpdate("CREATE TABLE example (id INTEGER, name VARCHAR, price enc_int4, miles enc_float4, secret enc_text, PRIMARY KEY (id))"); // insert data PreparedStatement stmt = dbConnection.prepareStatement("INSERT INTO example (id, name, price, miles, secret) VALUES(?,?,?,?,?)"); int price = 1234; float miles = 12.34f; String secret = "aliyun"; stmt.setInt(1, 1); stmt.setString(2, "name"); stmt.setInt(3, price); stmt.setFloat(4, miles); stmt.setString(5, secret); stmt.execute(); // check plaintext data String sqlCmd = "SELECT * FROM example WHERE price > ?"; PreparedStatement stmt = dbConnection.prepareStatement(sqlCmd); stmt.setInt(1, 100); ResultSet rs = stmt.executeQuery(); while (rs.next()){ int id = rs.getInt(1); String name = rs.getString(2); int price = rs.getInt(3); float miles = rs.getFloat(4); String secret = rs.getString(5); System.out.println(id + ", " + name + ", " + price + ", " + miles + ", " + secret); }
輸出結果示例:
1, name, 1234, 12.34, aliyun
通過上述EncJDBC
代碼示例,可以看到,以上過程僅修改了驅動加載以及URL配置部分,其他過程與普通數據庫訪問完全一致。您不需要修改任何業務相關代碼。
EncDB SDK
下載驅動程序及依賴配置
下載EncDB SDK驅動。
EncDB SDK
依賴于社區提供的PostgreSQL驅動工作。RDS PostgreSQL小版本
服務端encdb插件版本號
客戶端EncDB依賴包
20230830或以上版本
1.1.13或以上版本
Maven依賴配置。
說明本示例以Maven構建Java項目為例。
通過如下命令將
EncDB SDK
依賴包安裝至您的本地倉庫:mvn install:install-file -DgroupId=com.alibaba.encdb -DartifactId=<安裝的Jar包名> -Dversion=<安裝的Jar版本> -Dpackaging=jar -Dfile=<安裝的Jar包文件名>
示例:
mvn install:install-file -DgroupId=com.alibaba.encdb -DartifactId=libencdb -Dversion=1.2.12 -Dpackaging=jar -Dfile=D:\encdb\libs\libencdb-1.2.12.jar
說明此示例中EncDB依賴包在
D:\encdb\libs
路徑下。此示例使用的Maven版本為
3.9.2
,如果您安裝報錯,請升級Maven版本后再試。
在本地倉庫安裝
EncDB SDK
依賴包的基礎上,您需要在自己的Maven項目pom.xml配置文件中加入以下依賴項。<dependencies> ... <dependency> <groupId>com.alibaba.encdb</groupId> <artifactId>libencdb</artifactId> <version>1.2.12</version> </dependency> <!-- https://mvnrepository.com/artifact/org.bouncycastle/bcprov-jdk15on --> <dependency> <groupId>org.bouncycastle</groupId> <artifactId>bcprov-jdk15on</artifactId> <version>1.70</version> </dependency> <!-- https://mvnrepository.com/artifact/org.bouncycastle/bcpkix-jdk15on --> <dependency> <groupId>org.bouncycastle</groupId> <artifactId>bcpkix-jdk15on</artifactId> <version>1.70</version> </dependency> <dependency> <groupId>com.google.code.gson</groupId> <artifactId>gson</artifactId> <version>2.10.1</version> </dependency> <!-- https://mvnrepository.com/artifact/org.postgresql/postgresql --> <dependency> <groupId>org.postgresql</groupId> <artifactId>postgresql</artifactId> <version>42.2.23</version> </dependency> <dependency> <groupId>com.google.guava</groupId> <artifactId>guava</artifactId> <version>31.1-jre</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>1.7.30</version> </dependency> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-collections4</artifactId> <version>4.4</version> </dependency> ... </dependencies>
通過全密態客戶端查詢(代碼示例)
本示例所展示的代碼僅用于演示配置方式,請勿在實際業務代碼中將password
、mek
以明文方式設置在代碼中,建議使用外部配置文件或環境變量等其他方式進行處理后,再在代碼中引用。
SDK配置說明
您需要在處理收發密文數據前,使用
EncDB SDK
對數據進行加解密。EncDB SDK
提供了對應的接口,用于您初始化SDK對象時配置和您數據安全相關的參數。通常您只需要配置主密鑰(setMek)以及期望的加密算法(setEncAlgo),其他參數建議您使用默認缺省配置。// 準備好域名(hostname)、端口(port)、數據庫實例名(dbname)、用戶名(username)、密碼(password)等連接信息 // 建立數據庫連接,任意JDBC版本均可 String dbUrl = String.format("jdbc:postgresql://%s:%s/%s?binaryTransfer=true", hostname, port, dbname); Class.forName("org.postgresql.Driver"); Connection dbConnection = DriverManager.getConnection(dbUrl, username, password); // 初始化SDK String mek=...; Constants.EncAlgo encAlgo=...; EncdbSDK sdk = EncdbSDKBuilder.newInstance() .setDbConnection(dbConnection) .setMek(mek) .setEncAlgo(encAlgo) .build(); Cryptor cryptor = sdk.getCryptor(); // 調用加解密接口 // byte[] cipherBytes = cryptor.encrypt(...); // XXX value = cryptor.decryptXXX(...): // ... 發起查詢 ...
參數
取值示例(字符串類型)
說明
Mek
0x00112233445566778899aabbccddeeff
用戶主密鑰,由用戶自定義指定。
常見的生成方法有:密碼生成工具(如openssl, openssl rand -hex 16)、編程語言中的random函數、或者從第三方密鑰管理服務(KMS)獲取。
取值范圍:十六進制字符串,長度為32個字符,或者長度為16字節的二進制數。
警告用戶主密鑰是您訪問加密數據的根憑據,出于安全考慮,全密態數據庫不持有并管理您的主密鑰,也不提供用戶主密鑰的生成和備份服務,您需要自行生成用戶主密鑰。一旦您丟失密鑰,將無法再訪問已有的數據。因此我們建議您妥善備份用戶主密鑰。
EncAlgo
SM4_128_CBC
加密算法。取值范圍:
國際算法:
AES_128_GCM
AES_128_CBC
AES_128_ECB
國密算法:
SM4_128_GCM
SM4_128_CBC(默認值)
SM4_128_ECB
說明CTR加密算法暫不支持。
AES_128_ECB和SM4_128_ECB加密算法安全性較弱,請謹慎使用,推薦適用其他安全性更高的加密算法。
EncScheme
RND
加密方案。取值范圍:
RND(默認值):隨機加密。
DET:確定性加密。
說明當
EncAlgo
取值為AES_128_ECB或SM4_128_ECB時,該參數取值無效。DekGenMode
ENCLAVE
生成數據密鑰的方式。取值范圍:
ENCLAVE(默認值):由數據庫服務端在可信Enclave內生成數據密鑰DEK。
LOCAL:由客戶端生成數據密鑰DEK。
SdkMode
Default
SDK模式。取值范圍:
Default(默認值):可以支持全密態基礎版以及硬件加固版提供的所有密文數據類型。
Stateless
true
加密數據庫Stateless模式。取值范圍:
true(默認值):MEK在鏈接斷開后不會失效。
false:MEK在鏈接斷開后失效。
說明mek
及其他參數均在客戶端本地進行處理、并以安全方式進行分發(信封加密)到服務端,始終保證mek
不泄露。完整代碼示例
// 以下域名(hostname)、端口(port)、數據庫實例名(dbname)、用戶名(username)、密碼(password)等連接信息需要更新為您的實例信息 String hostname = "hostname"; String port = "port"; String dbname = "db"; String username = "user"; String password = "password"; // 建立數據庫連接 String dbUrl = String.format("jdbc:postgresql://%s:%s/%s?binaryTransfer=true", hostname, port, dbname); Class.forName("org.postgresql.Driver"); Connection dbConnection = DriverManager.getConnection(dbUrl, username, password); // 初始化SDK String mek="00112233445566778899aabbccddeeff"; // 只是示例,建議用更復雜的密鑰 Constants.EncAlgo encAlgo=Constants.EncAlgo.SM4_128_CBC; EncdbSDK sdk = EncdbSDKBuilder.newInstance() .setDbConnection(dbConnection) .setMek(mek) .setEncAlgo(encAlgo) .build(); Cryptor cryptor = sdk.getCryptor(); // create table dbConnection.createStatement().executeUpdate("DROP TABLE IF EXISTS example"); dbConnection.createStatement().executeUpdate("CREATE TABLE example (id INTEGER, name VARCHAR, price enc_int4, miles enc_float4, secret enc_text, PRIMARY KEY (id))"); // insert data PreparedStatement stmt = dbConnection.prepareStatement("INSERT INTO example (id, name, price, miles, secret) VALUES(?,?,?,?,?)"); int price = 1234; float miles = 12.34f; String secret = "aliyun"; stmt.setInt(1, 1); stmt.setString(2, "name"); stmt.setBytes(3, cryptor.encrypt("example", "price", price)); stmt.setBytes(4, cryptor.encrypt("example", "miles", miles)); stmt.setBytes(5, cryptor.encrypt("example", "secret", secret)); stmt.execute(); // check plaintext data String sqlCmd = "SELECT * FROM example WHERE price > ?"; stmt = dbConnection.prepareStatement(sqlCmd); stmt.setBytes(1, cryptor.encrypt("example", "price", 100)); ResultSet rs = stmt.executeQuery(); while (rs.next()) { int id = rs.getInt(1); String name = rs.getString(2); price = cryptor.decryptInt(rs.getBytes(3)); miles = cryptor.decryptFloat(rs.getBytes(4)); String text = cryptor.decryptString(rs.getBytes(5)); System.out.println(id +", " + name + ", " + price + ", " + miles + ", " + text); }
輸出結果示例:
1, name, 1234, 12.34, aliyun
相關參考
Java SDK模塊介紹
EncDB SDK
主要包含以下幾個Java功能模塊:
該模塊為EncDB SDK的構造類。提供如下API:
// 獲取一個新的EncdbSDKBuilder實例。您總是應該用這個方法來構造EncdbSDKBuilder。
EncdbSDKBuilder newInstance();
// (必選)設置一個數據庫連接,用于libencdb相關的密鑰管理動作。這個數據庫連接可以獨立于業務中實際用到的數據庫連接。
EncdbSDKBuilder setDbConnection(java.sql.Connection dbConnection);
// (必選)設置libencdb對接的客戶端類型。對于全密態MySQL,您應該設置MYSQL_PROXY選項
EncdbSDKBuilder setKeyMgmtType(KeyMgmtType kmType);
// (必選)設置用戶主密鑰。這里我們要求16字節的byte[]對象,或者長度為32個字符的十六進制串
EncdbSDKBuilder setMek(byte[] mek);
EncdbSDKBuilder setMek(String mekStr);
// (可選)設置加密算法。可選項有AES_128_GCM、AES_128_CBC、AES_128_ECB、SM4_128_CBC、SM4_128_ECB、SM4_128_GCM。不設置的話默認為SM4_128_CBC。
EncdbSDKBuilder setEncAlgo(EncAlgo encAlgo);
// 在完成上述設置之后,構造一個EncdbSDK對象
EncdbSDK build();
該模塊提供可信密鑰管理、端到端安全通信功能。提供如下API:
// 獲取一個Cryptor對象,用于操作密文/明文。
Cryptor getCryptor();
該模塊提供密碼計算功能。提供如下API:
/**
* @brief Encrypt interface
*
* @param schemaName schema name, used together with table name and column name to look up user's data encryption key from the given database connection.
*
* @param tblName table name, used together with column name to look up user's data encryption key from the given database connection.
*
* @param colName column name, used together with table name. To use user's default data encryption key, set tblName = "default", colName="default"
*
* @param type a valid encdb Type
* @param val value
* @return encrypted bytes
*/
byte[] encrypt(String schemaName, String tblName, String colName, EncType type, byte[] val);
byte[] encrypt(String schemaName, String tblName, String colName, byte[] val);
byte[] encrypt(String tblName, String colName, EncType type, byte[] val);
byte[] encrypt(String tblName, String colName, byte[] val);
// for int
byte[] encrypt(String schemaName, String tblName, String colName, EncType type, int val);
byte[] encrypt(String schemaName, String tblName, String colName, int val);
byte[] encrypt(String tblName, String colName, EncType type, int val);
byte[] encrypt(String tblName, String colName, int val);
// for long
byte[] encrypt(String schemaName, String tblName, String colName, EncType type, long val);
byte[] encrypt(String schemaName, String tblName, String colName, long val);
byte[] encrypt(String tblName, String colName, EncType type, long val);
byte[] encrypt(String tblName, String colName, long val);
// for float
byte[] encrypt(String schemaName, String tblName, String colName, EncType type, float val);
byte[] encrypt(String schemaName, String tblName, String colName, float val);
byte[] encrypt(String tblName, String colName, EncType type, float val);
byte[] encrypt(String tblName, String colName, float val);
// for double
byte[] encrypt(String schemaName, String tblName, String colName, EncType type, double val);
byte[] encrypt(String schemaName, String tblName, String colName, double val);
byte[] encrypt(String tblName, String colName, EncType type, double val);
byte[] encrypt(String tblName, String colName, double val);
// for String
byte[] encrypt(String schemaName, String tblName, String colName, EncType type, String val);
byte[] encrypt(String schemaName, String tblName, String colName, String val);
byte[] encrypt(String tblName, String colName, EncType type, String val);
byte[] encrypt(String tblName, String colName, String val);
// for BigDecimal
byte[] encrypt(String schemaName, String tblName, String colName, EncType type, BigDecimal val);
byte[] encrypt(String schemaName, String tblName, String colName, BigDecimal val);
byte[] encrypt(String tblName, String colName, EncType type, BigDecimal val);
byte[] encrypt(String tblName, String colName, BigDecimal val);
// for Timestamp
byte[] encrypt(String schemaName, String tblName, String colName, EncType type, Timestamp val);
byte[] encrypt(String schemaName, String tblName, String colName, Timestamp val);
byte[] encrypt(String tblName, String colName, EncType type, Timestamp val);
byte[] encrypt(String tblName, String colName, Timestamp val);
/**
* @brief Decrypt interface
*
* @param schemaName schema name, used together with table name and column name to look up user's data encryption key from the given database connection.
*
* @param tblName table name, used together with column name to look up user's data encryption key.
*
* @param colName column name, used together with table name. To use user's default data encryption key,
* set tblName = "default", colName="default"
*
* @param val val can be in either hex binary format or pg bytea bytes, e.g., \\x00621c14
* @return decrypted value is in hex binary format or given type format
*/
byte[] decrypt(String schemaName, String tblName, String colName, byte[] val);
byte[] decrypt(String tblName, String colName, byte[] val);
byte[] decrypt(byte[] val);
// Decrypt interface for `int`
int decryptInt(byte[] val);
// Decrypt interface for `long`
long decryptLong(byte[] val);
// Decrypt interface for `float`
float decryptFloat(byte[] val);
// Decrypt interface for `double`
double decryptDouble(byte[] val);
// Decrypt interface for `String`
String decryptString(byte[] val);
// Decrypt interface for `BigDecimal`
BigDecimal decryptDecimal(byte[] val);
// Decrypt interface for `TimeStamp`
Timestamp decryptTimestamp(byte[] val);
psql命令行
全密態數據庫支持命令行直接查詢,例如psql命令行執行SELECT * FROM example;
。
可以看到,id
、name
列是明文,price
、miles
、secret
列是密文。已被加密的數據在服務器端無法查看,能夠有效防御來自云平臺外部和內部的安全威脅,時刻保護用戶數據。
DMS控制臺
全密態數據庫支持通過DMS等可視化交互工具直接查詢,例如DMS。
可以看到,id
、name
列是明文,price
、miles
、secret
列是密文。
常見問題
Q:連接數據庫提示報錯
org.postgresql.util.PSQLException: ERROR: db_process_msg_api: process message failure - returned 0xf7070000
。A:錯誤碼0xf7070000表示MEK密鑰導入失敗。可能原因為同一個賬號在連接同一個加密數據庫時,使用了不同的MEK,更換主密鑰會導致原密鑰加密的數據無法訪問,請使用原密鑰連接數據庫。
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模塊,以解決訪問權限問題。