EncJDBC adalah driver JDBC yang memungkinkan aplikasi Java terhubung ke database always-confidential dan mendekripsi data kolom terenkripsi secara transparan—tanpa mengubah logika kueri Anda.
Dengan kunci enkripsi utama (MEK) yang telah dikonfigurasi, EncJDBC secara otomatis mendekripsi ciphertext dan mengembalikan teks biasa ke aplikasi Anda. Proses enkripsi dan dekripsi tidak terlihat oleh kode aplikasi Anda.
Cara kerja
EncJDBC menggunakan proses dua langkah:
-
Saat koneksi, EncJDBC mendistribusikan MEK Anda ke server menggunakan Enkripsi amplop, memastikan kunci tidak pernah dikirim dalam bentuk teks biasa.
-
Untuk setiap kueri, EncJDBC secara otomatis mengenkripsi parameter yang ditujukan ke kolom terenkripsi dan mendekripsi hasilnya sebelum mengembalikannya ke aplikasi Anda.
Kode aplikasi Anda tetap bekerja dengan nilai teks biasa—tidak diperlukan perubahan pada logika kueri.
Prasyarat
Sebelum memulai, pastikan Anda telah memiliki:
-
Fitur always-confidential database diaktifkan pada instans ApsaraDB RDS for MySQL Anda. Lihat Aktifkan fitur always-confidential database.
-
Detail koneksi untuk instans: hostname, port, nama database, username, dan password.
-
Aturan perlindungan data yang telah dikonfigurasi. Lihat Konfigurasikan aturan perlindungan data.
-
JDK 1.8 atau versi yang lebih baru.
Contoh dalam topik ini menggunakan Maven 3.9.2 dan IntelliJ IDEA Community Edition 2022.3.2.
Simpan MEK Anda secara aman dan jangan pernah mengeksposnya. Jika hilang, data terenkripsi akan menjadi tidak dapat diakses selamanya. Instans RDS Anda tidak pernah menghasilkan, menyimpan, atau membuat backup MEK Anda.
Tambahkan dependensi Maven
Tambahkan dependensi berikut ke file pom.xml proyek Anda:
<dependencies>
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>aliyun-encdb-mysql-jdbc</artifactId>
<version>1.0.9-1</version>
</dependency>
</dependencies>
Konfigurasi dan koneksi
EncJDBC menggunakan format URL JDBC jdbc:mysql:encdb://{hostname}:{port}/{dbname} dan kelas driver com.aliyun.encdb.mysql.jdbc.EncDriver.
Sebelum melakukan koneksi, konfigurasikan dua parameter yang diperlukan:
| Parameter | Nilai contoh | Deskripsi |
|---|---|---|
MEK |
00112233445566778899aabbccddeeff |
Kunci enkripsi utama (MEK) yang Anda hasilkan dan kelola. Nilai valid: string heksadesimal 32 karakter (16 byte). Hasilkan menggunakan openssl rand -hex 16, fungsi acak bahasa pemrograman, atau Key Management Service (KMS). |
ENC_ALGO |
SM4_128_CBC |
Algoritma enkripsi. Default: SM4_128_GCM. |
Algoritma enkripsi yang didukung:
| Kategori | Algoritma |
|---|---|
| AES (diterima secara internasional) | AES_128_GCM, AES_128_CTR, AES_128_CBC, AES_128_ECB (tidak direkomendasikan) |
| SM4 (standar nasional Tiongkok) | SM4_128_GCM (default), SM4_128_CTR, SM4_128_CBC, SM4_128_ECB (tidak direkomendasikan) |
HindariAES_128_ECBdanSM4_128_ECB—mode ini tidak memberikan jaminan keamanan yang kuat.
Teruskan konfigurasi ke EncJDBC
Terdapat tiga metode yang tersedia. Jika Anda ingin menggunakan lebih dari dua metode untuk mengonfigurasi parameter di JDBC, prioritasnya adalah sebagai berikut: JDBC properties > configuration file > URL parameter.
Anda dapat menggabungkan beberapa parameter menggunakan &.
Opsi 1: JDBC properties
Tetapkan MEK dan ENC_ALGO langsung di objek Properties sebelum membuka koneksi:
// Ganti placeholder dengan detail koneksi instans Anda.
String hostname = "<hostname>";
String port = "<port>";
String dbname = "<dbname>";
String username = "<username>";
String password = "<password>";
String mek = "<your-mek>"; // string heksadesimal 32 karakter
String encAlgo = "<enc-algo>"; // contoh: SM4_128_GCM
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);
Opsi 2: File konfigurasi
Buat file konfigurasi dengan konten berikut:
MEK=<your-mek>
ENC_ALGO=<enc-algo>
Letakkan file tersebut di salah satu lokasi berikut:
-
Direktori
resourcesproyek Anda. -
Direktori root proyek Anda (direktori kerja saat waktu proses).
Nama file default adalah encjdbc.conf. Untuk menggunakan path kustom, tetapkan properti sistem encJdbcConfigFile ke direktori file konfigurasi tersebut.
Setelah menempatkan file, lakukan koneksi tanpa menentukan MEK atau ENC_ALGO dalam kode:
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);
Opsi 3: Parameter URL
Tambahkan MEK dan ENC_ALGO langsung ke URL JDBC:
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);
Contoh lengkap
Contoh berikut menggunakan JDBC properties untuk terhubung, memasukkan baris ke tabel, dan mengambil hasil teks biasa.
// Ganti placeholder dengan detail koneksi instans Anda.
String hostname = "hostname";
String port = "port";
String dbname = "db";
String username = "user";
String password = "password";
// Gunakan MEK yang kuat dan dihasilkan secara acak di lingkungan produksi.
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"};
// Buat tabel.
connection.createStatement().executeUpdate("drop table if exists test");
connection.createStatement().executeUpdate("create table test (a int, b text)");
// Masukkan baris menggunakan PreparedStatement.
// EncJDBC secara otomatis mengenkripsi nilai yang ditujukan ke kolom terenkripsi.
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();
}
// Ambil baris. EncJDBC secara otomatis mendekripsi hasil sebelum mengembalikannya.
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");
}
Output yang diharapkan:
1 abc
2 bcd
3 cde
4 def
5 efg
6 fgi
Perhatikan hal berikut:
-
Semua operasi baca dan tulis ke kolom terenkripsi dilakukan melalui
PreparedStatement. Driver secara otomatis mengenkripsi parameter dan mendekripsi hasil—tidak diperlukan perubahan pada logika kueri Anda. -
Nilai yang diteruskan ke kolom yang tidak terenkripsi tidak terpengaruh.
Pemecahan masalah
IllegalAccessError: cannot access class com.sun.crypto.provider.SunJCE
Galat ini terjadi karena versi JDK yang lebih baru membatasi akses lintas modul secara default. Tambahkan opsi VM berikut saat menjalankan program Anda:
--add-exports=java.base/com.sun.crypto.provider=ALL-UNNAMED
failed in mek provision: gcmEncrypt error
Ini adalah isu yang diketahui pada Oracle JDK. Gunakan salah satu solusi berikut:
-
Beralih ke Amazon Corretto — distribusi OpenJDK drop-in yang tidak memiliki isu ini.
-
Tambahkan penyedia keamanan BouncyCastle ke Oracle JDK:
-
Temukan direktori instalasi JDK Anda.
-
Buka
<jdk-path>/conf/security/java.security. -
Pada bagian
List of providers and their preference orders, tambahkan: ``security.provider.14=org.bouncycastle.jce.provider.BouncyCastleProvider``.
-