Chỉ trong một vài năm, các nền tảng và các dịch vụ điện toán đám mây đã thay đổi đáng kể bối cảnh về phát triển ứng dụng Java™. Chúng đã hạ thấp các rào cản liên quan đến bảo trì và cấu hình hệ thống và đồng thời đã làm giảm chi phí và tăng tốc độ đưa phần mềm ra thị trường. Về mặt khái niệm, điện toán đám mây có ý nghĩa là: các nhà quản lý kinh doanh thích lợi nhuận do đầu tư mang lại còn các nhà phát triển thích thoát khỏi mã cơ sở hạ tầng. Tuy nhiên, nhiều cơ sở vẫn đang phải vật lộn với việc nên hay không chuyển sang nền tảng đám mây.
An toàn dữ liệu là một trong những mối quan tâm chính đối với một tổ chức đang xem xét việc di chuyển hệ thống phần mềm của mình lên một cơ sở hạ tầng đám mây. Dữ liệu càng nhạy cảm thì càng có nhiều lý do để quan tâm. Là các nhà phát triển phần mềm, điều quan trọng là chúng ta hiểu các rủi ro an toàn thực sự của điện toán đám mây lẫn các cách tiếp cận thực tế để giải quyết ít nhất một số trong các mối quan tâm này.
Trong bài đăng này về Phát triển Java 2.0, tôi sẽ giải thích điều gì làm cho việc lưu trữ dữ liệu trong đám mây khác với việc lưu trữ nó trên một máy tính trung tâm. Sau đó tôi sẽ giới thiệu cho bạn cách sử dụng các tiêu chuẩn và các tiện ích mã hóa khóa bí mật dựng sẵn của nền tảng Java để giữ an toàn hợp lý cho dữ liệu của bạn, ngay cả khi nó được lưu trữ trên một kho dữ liệu đám mây phân tán. Cuối cùng, tôi sẽ trình bày một cách tiếp cận chiến lược về mã hóa, bằng cách sử dụng các điều kiện truy vấn làm một vạch chuẩn để bạn biết có nên hay không nên mã hóa dữ liệu của mình.
Bảo đảm an toàn dữ liệu đám mây
Điện toán đám mây chính xác không giới thiệu các vấn đề bảo mật dữ liệu mới; trong hầu hết các trường hợp, nó chỉ khuếch trương các vấn đề này thôi. Việc đưa dữ liệu lên đám mây có khả năng trưng nó ra cho một đối tượng người dùng lớn hơn, đó thường là một điều tốt. Nhưng nếu dữ liệu được trưng ra có ý nghĩa riêng tư hoặc chỉ được truy cập khi có quyền, thì việc đưa dữ liệu lên đám mây có thể là thảm họa. Vấn đề cơ bản với điện toán đám mây là nó tách dữ liệu được giao phó khỏi một nhà phát triển hoặc khỏi việc kiểm soát trực tiếp của quản trị viên hệ thống (sys-admin). Thay vì được lưu trữ và quản lý cục bộ, dữ liệu trong các đám mây được lưu trữ trên các thiết bị phân tán, có thể được đặt ở bất kỳ đâu và bất cứ ai đều có thể truy cập được.
Thậm chí nếu trong thực tế công ty của bạn có thể sử dụng kho dữ liệu ở xa, không tập trung, thì bạn cũng muốn các ứng dụng của mình trong đám mây cần bắt đầu có một chút về an toàn dữ liệu. Khi bạn bắt đầu suy nghĩ về an toàn dữ liệu, có hai câu hỏi quan trọng nảy sinh:
- Dữ liệu có an toàn trong quá trình hoạt động không?
- Dữ liệu có an toàn trong lúc không hoạt động không?
Dữ liệu trong quá trình hoạt động liên quan đến cách dữ liệu truyền đi từ một vị trí này tới vị trí khác, đó là công nghệ và cơ sở hạ tầng truyền thông mà bạn đang sử dụng. Dữ liệu không hoạt động liên quan đến việc bạn lưu trữ dữ liệu như thế nào — và tốt ra sao. Ví dụ, nếu bạn lưu trữ các tên và mật khẩu người dùng trong một cơ sở dữ liệu không mã hóa chúng, thì dữ liệu không hoạt động của bạn sẽ không an toàn.
Để bảo vệ dữ liệu trong quá trình chuyển tiếp qua web, hầu hết đều sử dụng HTTPS. Đây là định dạng HTTP có mã hóa dữ liệu chuyển đi từ các trình duyệt đến các khách hàng. Một ưu điểm khác của HTTPS là nó có mặt ở khắp nơi: Hầu hết các nhà phát triển đã cấu hình Apache, Tomcat, Jetty để sử dụng HTTPS.
Mã hóa cũng là cơ chế chung để bảo vệ dữ liệu ở phần còn lại và điện toán đám mây không thay đổi điều đó. Trong khi mã hóa có thể là bí mật, bạn chỉ cần biết một số điều cơ bản về mã hóa để giữ an toàn hợp lý cho dữ liệu của ứng dụng của mình. Và một khi dữ liệu của bạn đã an toàn, thì dù bạn dùng dữ liệu cục bộ hay qua một nền tảng điện toán đám mây hoặc kho dữ liệu đều không thành vấn đề.
Mã hóa là quá trình chuyển đổi văn bản thuần, dễ đọc đơn giản với mọi người thành văn bản khó đọc. Bạn mã hóa bằng một thuật toán mật mã, còn được gọi là cipher. Văn bản đã mã hóa được giải mã trở lại thành văn bản dễ đọc qua một khóa, về cơ bản đó là một dạng mật khẩu. Mã hóa giữ an toàn thông tin bằng cách làm cho thông tin trở nên khó đọc với bất cứ ai không có khóa.
Người ta thường sử dụng hai kiểu mã hóa dựa trên khóa trong điện toán: mã hóa khóa công khai (dùng chung) và mã hóa khóa bí mật (dùng riêng). Mã hóa khóa công khai là kỹ thuật phổ biến nhất để giữ an toàn dữ liệu trong quá trình chuyển tiếp; trên thực tế, đó là kiến trúc bên dưới của tầng bảo mật giao dịch HTTPS. Dạng mã hóa này đòi hỏi phải có hai khóa trong một bộ khóa công khai-bí mật. Khóa công khai mã hóa dữ liệu còn khóa bí mật được sử dụng để giải mã dữ liệu đó. Trong mã hóa khóa công khai, người ta có thể phân phối khóa công khai một cách an toàn, trong khi khóa bí mật phải chịu sự kiểm soát của một quản trị viên. Mã hóa khóa công khai làm cho việc chia sẻ thông tin mã hóa trở nên dễ dàng.
Trong mã hóa khóa bí mật, người ta thường sử dụng một khóa bí mật duy nhất để mã hóa và giải mã dữ liệu. Kiểu mã hóa này làm cho việc chia sẻ dữ liệu mã hóa với một bên thứ ba trở nên khó khăn vì cả người gửi lẫn người nhận đều phải sử dụng chung một khóa. Nếu khóa đó bị lộ, thì tất cả các thông tin được mã hóa cũng bị lộ. Mã hóa khóa bí mật có hiệu quả cao nếu không cần phải chia sẻ dữ liệu mã hóa với các bên khác, sao cho có thể lưu giữ khóa dưới sự kiểm soát chặt chẽ mọi lúc.
Mã hóa khóa bí mật là một phương tiện hiệu quả để bảo đảm an toàn dữ liệu ứng dụng, khi lưu trữ và truyền dữ liệu đó qua một cơ sở hạ tầng điện toán đám mây. Do khóa mã hóa vẫn còn nằm dưới sự kiểm soát của một quản trị viên hoặc người tạo ra ứng dụng, nên các nhà cung cấp đám mây và những kẻ nghe lén tiềm ẩn khác đều không có quyền truy cập tự do vào dữ liệu đó.
Bạn có thể chọn từ một loạt các tùy chọn để bảo đảm an toàn cho các ứng dụng Java, bao gồm các thư viện nền tảng Java tiêu chuẩn. Bạn cũng có một loạt các tiêu chuẩn mã hóa và các gói để lựa chọn. Với các ví dụ sau đây, tôi sẽ sử dụng các thư viện Java lõi và Advanced Encryption Standard (Tiêu chuẩn mã hóa nâng cao) hoặc viết tắt là AES. Tôi sẽ sử dụng một khóa bí mật vừa để mã hóa văn bản thuần vừa để giải mã văn bản mã hóa, là văn bản thuần đã được mã hóa. Tôi thích AES bởi vì nó đã được Cơ quan an ninh quốc gia phê duyệt và được chính phủ Hoa Kỳ tiêu chuẩn hóa.
Để linh hoạt tối đa và dễ dàng kiểm tra, tôi sẽ tạo ra một số giao diện mã hóa và các lớp thực hiện liên quan để chỉ cần bao bọc các lớp Java lõi. Sau đó tôi sẽ hướng dẫn bạn cách sử dụng các lớp này để duy trì một cách an toàn và thậm chí để truy vấn dữ liệu trong các kho dữ liệu đám mây như SimpleDB của Amazon hoặc ngay cả MongoDB của MongoHQ nữa.
Trong Liệt kê 1, tôi định nghĩa một giao diện mã hóa tổng quát đơn giản, định nghĩa hai phương thức để mã hóa và giải mã dữ liệu. Giao diện này sẽ dùng như một bình phong cho các thuật toán khác nhau; có nghĩa là, các lớp thực hiện của tôi sẽ sử dụng một thuật toán mã hóa cụ thể là AES.
Liệt kê 1. Một giao diện mã hóa
package com.b50.crypto;
public interface Cryptographical {
String encrypt(String plaintext);
String decrypt(String ciphertext);
}
|
Với giao diện Cryptographical của mình, tôi có thể hoặc mã
hóa văn bản hoặc giải mã văn bản mã hóa. Tiếp theo trong Liệt kê 2, tôi sẽ sử dụng
API bảo mật Java (Java Security API) để tạo ra một giao diện khác đại diện cho một
khóa:
Liệt kê 2. Một giao diện khóa
package com.b50.crypto;
import java.security.Key;
public interface CryptoKeyable {
Key getKey();
}
|
Như bạn có thể thấy, giao diện CryptoKeyable của tôi chỉ
dùng như một trình bao bọc (wrapper) cho kiểu Key (Khóa)
cốt lõi của nền tảng Java.
Nếu bạn đang sử dụng mã hóa AES, khi bạn mã hóa văn bản thuần bạn sẽ cần mã hóa các ký tự nhị phân được tạo ra theo base-64 — hoặc ít nhất là như vậy nếu bạn muốn sử dụng chúng trong các yêu cầu web (ví dụ, với các miền SimpleDB). Vì vậy, tôi sẽ mã hóa tất cả các chuỗi ký tự cần mã hóa và giải mã bất kỳ chuỗi ký tự nào cần giải mã.
Lớp thực hiện Cryptographical của tôi với AES, được hiển
thị trong Liệt kê 3, không chỉ xử lý mã hóa AES mà còn mã hóa và giải mã theo
base-64:
Liệt kê 3. Thực thi AES trong interface Cryptographical của tôi
package com.b50.crypto;
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;
import javax.crypto.Cipher;
import javax.crypto.NoSuchPaddingException;
import java.security.InvalidKeyException;
import java.security.Key;
import java.security.NoSuchAlgorithmException;
public class AESCryptoImpl implements Cryptographical {
private Key key;
private Cipher ecipher;
private Cipher dcipher;
private AESCryptoImpl(Key key) throws NoSuchAlgorithmException,
NoSuchPaddingException, InvalidKeyException {
this.key = key;
this.ecipher = Cipher.getInstance("AES");
this.dcipher = Cipher.getInstance("AES");
this.ecipher.init(Cipher.ENCRYPT_MODE, key);
this.dcipher.init(Cipher.DECRYPT_MODE, key);
}
public static Cryptographical initialize(CryptoKeyable key) throws CryptoException {
try {
return new AESCryptoImpl(key.getKey());
} catch (NoSuchAlgorithmException e) {
throw new CryptoException(e);
} catch (NoSuchPaddingException e) {
throw new CryptoException(e);
} catch (InvalidKeyException e) {
throw new CryptoException(e);
}
}
public String encrypt(String plaintext) {
try {
return new BASE64Encoder().encode(ecipher.doFinal(plaintext.getBytes("UTF8")));
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public String decrypt(String ciphertext) {
try {
return new String(dcipher.doFinal(new BASE64Decoder().decodeBuffer(ciphertext)),
"UTF8");
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
|
Tiếp theo, chúng ta hãy suy nghĩ về khóa mã hóa. Có thể sử dụng các thư viện lõi của
nền tảng Java để tạo ra các khóa mã hóa mạnh; tuy nhiên, những phương thức này sẽ
luôn sản xuất một khóa mới được tạo ra ngẫu nhiên. Vì vậy, nếu bạn tạo một khóa sử
dụng các lớp KeyGenerator của Java, bạn sẽ cần phải lưu
trữ khóa đó để sử dụng sau này (có nghĩa là, cho đến khi bạn quyết định giải mã văn
bản đã mã hóa bằng khóa đó). Về vấn đề này, bạn có thể sử dụng tiện ích KeyStore của nền tảng Java và các lớp tương ứng.
Tiện ích KeyStore chứa một tập hợp các lớp cho phép bạn
lưu một khóa vào một tệp nhị phân được bảo vệ bằng mật khẩu, được gọi là một
keystore (kho khóa). Tôi có thể kiểm tra các khóa trong Java bằng một
vài trường hợp kiểm tra. Trước tiên, tôi tạo ra hai cá thể của một Key và cho thấy rằng mỗi String
được mã hóa tương ứng của một khóa là khác nhau, như trong Liệt kê 4:
Liệt kê 4. Mã hóa đơn giản bằng cách sử dụng hai khóa khác nhau
@Test
public void testEncryptRandomKey() throws Exception {
SecretKey key = KeyGenerator.getInstance("AES").generateKey();
Cryptographical crypto = AESCryptoImpl.initialize(new AESCryptoKey(key));
String enc = crypto.encrypt("Andy");
Assert.assertEquals("Andy", crypto.decrypt(enc));
SecretKey anotherKey = KeyGenerator.getInstance("AES").generateKey();
Cryptographical anotherInst = AESCryptoImpl.initialize(new AESCryptoKey(anotherKey));
String anotherEncrypt = anotherInst.encrypt("Andy");
Assert.assertEquals("Andy", anotherInst.decrypt(anotherEncrypt));
Assert.assertFalse(anotherEncrypt.equals(enc));
}
|
Tiếp theo, trong Liệt kê 5, tôi chứng minh rằng một cá thể khóa cụ thể luôn mang đến
cùng một văn bản mã hóa chính xác cho một String tương
ứng:
Liệt kê 5. Một khóa bí mật tương ứng với một chuỗi duy nhất
@Test
public void testEncrypt() throws Exception {
SecretKey key = KeyGenerator.getInstance("AES").generateKey();
KeyStore ks = KeyStore.getInstance("JCEKS");
ks.load(null, null);
KeyStore.SecretKeyEntry skEntry = new KeyStore.SecretKeyEntry(key);
ks.setEntry("mykey", skEntry,
new KeyStore.PasswordProtection("mykeypassword".toCharArray()));
FileOutputStream fos = new FileOutputStream("agb50.keystore");
ks.store(fos, "somepassword".toCharArray());
fos.close();
Cryptographical crypto = AESCryptoImpl.initialize(new AESCryptoKey(key));
String enc = crypto.encrypt("Andy");
Assert.assertEquals("Andy", crypto.decrypt(enc));
//alternatively, read the keystore file itself to obtain the key
Cryptographical anotherInst = AESCryptoImpl.initialize(new AESCryptoKey(key));
String anotherEncrypt = anotherInst.encrypt("Andy");
Assert.assertEquals("Andy", anotherInst.decrypt(anotherEncrypt));
Assert.assertTrue(anotherEncrypt.equals(enc));
}
|
Những gì tôi mã hóa bằng một khóa cụ thể, thì tôi cần giải mã bằng đúng khóa đó. Việc
sử dụng tiện ích KeyStore của Java là một cách thuận tiện
và an toàn để lưu trữ các khóa của tôi.
Các mã trong các Liệt kê 4 và 5 là mẫu mã soạn sẵn, nhưng có thể dùng nó để chứng minh một vài điều:
- Keystore có một tên.
- Tệp đã lưu được bảo vệ bằng mật khẩu.
- Keystore có thể lưu trữ nhiều hơn một khóa.
- Mỗi khóa bên trong kho có một mật khẩu kèm theo.
Với trường hợp kiểm tra này, tôi đã quyết định tạo ra một keystore mới mỗi khi tôi chạy bài kiểm tra đó. Tôi đã có thể dễ dàng mở một keystore hiện có với mỗi bài kiểm tra mới. Nếu tôi muốn sử dụng một keystore hiện có, tôi cần phải biết mật khẩu của nó, cũng như mật khẩu để truy cập vào một khóa cụ thể.
Khóa là tất cả khi nói đến mã hóa. Mật mã bên dưới mạnh ra sao không quan trọng; nếu khóa của tôi bị lộ, thì dữ liệu của tôi cũng bị lộ. Điều này cũng có nghĩa là phải bảo đảm keystore và các cụm từ mật khẩu kèm theo keystore luôn an toàn. (Ví dụ, trong một ứng dụng sản xuất, tôi sẽ không mã cố định (hardcode) các mật khẩu như tôi đã làm để minh họa trong các Liệt kê 4 và 5.)
Khi bạn mã hóa dữ liệu, bạn thay đổi các thuộc tính của nó. Về cơ bản, điều này có nghĩa là một số nguyên được mã hóa thì sẽ không so sánh được với số nguyên nữa. Do đó, điều quan trọng cần suy nghĩ thấu đáo xem rốt cuộc bạn sẽ truy vấn dữ liệu đã lưu trữ trong đám mây như thế nào, tại sao và trong hoàn cảnh nào. Tin tức tốt là trong nhiều trường hợp, dữ liệu mà bạn muốn giữ riêng tư sẽ thường có giá trị nghiệp vụ khác so với dữ liệu mà bạn muốn thao tác: mã hóa một tên của một tài khoản hoặc một số thông tin cá nhân về chủ tài khoản có ý nghĩa, nhưng mã hóa một số dư tài khoản có thể không có ý nghĩa gì (vì có ai sẽ quan tâm đến một số dư tài khoản mà không gắn với một người không?).
Người ta có thể dễ dàng tìm kiếm dữ liệu mã hóa khi thực hiện các so khớp chính xác như: "Tìm cho tôi tất cả các tài khoản có tên là 'foo' (ở đây 'foo' được mã hóa)." Nhưng việc tìm kiếm đó vốn dĩ không làm việc với các truy vấn có điều kiện như: "Tìm cho tôi tất cả các tài khoản có số dư quá hạn lớn hơn $ 450 trong đó $ 450 được mã hóa".
Ví dụ, hãy tưởng tượng rằng tôi sử dụng một thuật toán mã hóa đơn giản để đảo ngược
thứ tự ký tự và thêm ký tự i vào cuối cùng của một chuỗi ký tự. Trong
trường hợp này, chuỗi foo sẽ trở thành oofi và 450 sẽ trở
thành 054i. Nếu đã mã hóa giá trị tên trong bảng bằng cách sử dụng thuật
toán mã hóa đơn giản này, tôi có thể dễ dàng truy vấn bằng các so khớp chính xác,
chẳng hạn như "select * from table where name = 'oofi'"
(chọn * từ bảng có name = 'oofi' "). Tuy nhiên, so sánh giá trị mã hóa là 450 sẽ rất
khó khăn: "select * from table where amount > 054i"
hoàn toàn không giống như "select * from table where amount >
450".
Để so sánh dữ liệu trong trường hợp này, tôi có thể thực hiện một số hoạt động giải
mã trong ứng dụng — có nghĩa là, tôi cần phải chọn tất cả dữ liệu của một
bảng, giải mã trường amount rồi thực hiện so sánh. Việc
không thể dựa vào kho dữ liệu bên dưới cho hoạt động này có nghĩa là tôi không thể
lọc nhanh như khi lọc với kho dữ liệu. Do tôi muốn tối đa hóa hiệu quả, nên tôi cần
suy nghĩ thấu đáo xem tôi muốn mã hóa dữ liệu nào và tôi muốn mã hóa nó ra sao. Việc
luôn suy nghĩ mã hóa với các truy vấn sắp tới là một cách tốt để nâng cao hiệu quả
chung của chương trình.
Thật dễ mã hóa một tên tài khoản bằng MongoDB và tìm kiếm theo tên đã mã hóa của nó, như thể hiện trong Liệt kê 6:
Liệt kê 6. Mã hóa với MongoDB
@Test
public void encryptMongoDBRecords() throws Exception {
KeyStore.SecretKeyEntry pkEntry = getKeyStoreEntry();
Cryptographical crypto =
AESCryptoImpl.initialize(new AESCryptoKey(pkEntry.getSecretKey()));
DB db = getMongoConnection();
DBCollection coll = db.getCollection("accounts");
BasicDBObject encryptedDoc = new BasicDBObject();
encryptedDoc.put("name", crypto.encrypt("Acme Life, LLC"));
coll.insert(encryptedDoc);
BasicDBObject encryptedQuery = new BasicDBObject();
encryptedQuery.put("name", crypto.encrypt("Acme Life, LLC"));
DBObject result = coll.findOne(encryptedQuery);
String value = result.get("name").toString();
Assert.assertEquals("Acme Life, LLC", crypto.decrypt(value));
}
|
Trong Listing 6, đầu tiên tôi sử dụng phương thức getKeyStoreEntry để đọc một kho khóa hiện có. Tiếp theo tôi
thu được một kết nối đến một cá thể của MongoDB, trong trường hợp này cá thể đó ngẫu
nhiên lưu trú trong đám mây của MongoHQ. Sau đó tôi cố nắm giữ một liên kết đến bộ
sưu tập các tài khoản (một lập trình viên RDBMS thường gọi nó là bảng các tài
khoản) và tiến hành chèn một bản ghi tài khoản mới có tên tương ứng đã mã
hóa của nó. Cuối cùng, tôi tìm kiếm bản ghi tương tự đó bằng cách mã hóa chuỗi ký tự
tìm kiếm của mình (ở đây name tương ứng với "Acme Life,
LLC" đã mã hóa).
Bản ghi này theo MongoDB sẽ trông đại loại như những gì hiển thị trong Liệt kê 7. (Lưu ý rằng chuỗi "Acme Life, LLC" đã mã hóa của bạn sẽ khác với chuỗi đã mã hóa của tôi vì bạn sẽ có một khóa khác).
Liệt kê 7. Một trường hợp thử nghiệm mã hóa của MongoDB
{
_id : "4ee0c541300484530bf9c6fa",
name : "f0wJxYyVhfH0UkkTLKGZng=="
}
|
Tôi đã quên chưa mã hóa khóa thực tế (name) trong tài
liệu, nhưng cũng có thể tôi đã mã hóa nó rồi. Nếu tôi đã mã hóa, tôi sẽ chỉ cần phản
ánh sự thay đổi trong các truy vấn tương ứng của mình. Tôi cũng có thể đã mã hóa tên
bộ sưu tập. Các so sánh String trực tiếp sẽ hoạt động bất
kể chúng được mã hóa hay không.
Chiến lược này không chỉ dùng riêng cho việc thực hiện của MongoDB. Ví dụ, tôi có thể thực hiện gần đúng một trường hợp kiểm tra tương tự với SimpleDB, như trong Liệt kê 8:
Liệt kê 8. Một trường hợp kiểm tra mã hóa của SimpleDB
@Test
public void testSimpleDBEncryptInsert() throws Exception {
KeyStore.SecretKeyEntry pkEntry = getKeyStoreEntry();
Cryptographical crypto =
AESCryptoImpl.initialize(new AESCryptoKey(pkEntry.getSecretKey()));
AmazonSimpleDB sdb = getSimpleDB();
String domain = "accounts";
sdb.createDomain(new CreateDomainRequest(domain));
List<ReplaceableItem> data = new ArrayList<ReplaceableItem>();
String encryptedName = crypto.encrypt("Acme Life, LLC");
data.add(new ReplaceableItem().withName("account_02").withAttributes(
new ReplaceableAttribute().withName("name").withValue(encryptedName)));
sdb.batchPutAttributes(new BatchPutAttributesRequest(domain, data));
String qry = "select * from " + SimpleDBUtils.quoteName(domain)
+ " where name = '" + encryptedName + "'";
SelectRequest selectRequest = new SelectRequest(qry);
for (Item item : sdb.select(selectRequest).getItems()) {
Assert.assertEquals("account_02", item.getName());
}
}
|
Ở đây tôi đã làm theo các bước tương tự trong ví dụ MongoDB của mình: Tôi đọc từ một
kho khóa hiện có, thu được một kết nối đến SimpleDB của Amazon rồi chèn một bản ghi
tài khoản có thuộc tính name đã được mã hóa. Cuối cùng,
tôi tra tìm tài khoản theo tên, bằng cách sử dụng giá trị mã hóa làm khóa của nó.
Trong khi điện toán đám mây hứa hẹn sẽ làm cho dữ liệu của bạn có thể truy cập tới
một đối tượng người dùng rộng lớn, bạn có thể làm rất nhiều việc để bảo vệ dữ liệu
nhạy cảm. Trong bài viết này, tôi đã giới thiệu cho bạn cách sử dụng các thư viện
nền tảng Java để bảo đảm an toàn cho dữ liệu ở phần còn lại trên một cơ sở hạ tầng
đám mây như MongoDB hoặc SimpleDB. Mã hóa khóa bí mật giữ an toàn dữ liệu trong tay
của người quản trị dữ liệu đó. Và việc bạn lưu trữ các khóa bí mật bằng tiện ích
KeyStore Java sẽ giúp quản lý chúng dễ dàng và an
toàn. Chỉ cần một mật khẩu duy nhất để truy cập một khóa bí mật và bạn không bao giờ
muốn làm một điều là lưu trữ mật khẩu đó dưới dạng văn bản rõ ở bất cứ nơi nào gần
đám mây.
Dữ liệu lưu trữ đã mã hóa vận hành khác với dữ liệu văn bản rõ trong bối cảnh của một số tìm kiếm. Việc so khớp chính xác sẽ hoạt động tốt, nhưng có thể là một vấn đề hóc búa với các truy vấn điều kiện có liên quan đến các so khớp không chính xác. Giải pháp ở đây tùy thuộc vào cách bạn xử lý (hoặc không xử lý) so sánh đó. Luôn suy nghĩ thấu đáo xem bạn sẽ mã hóa cái gì bằng các truy vấn dự kiến của mình trong tâm trí. Việc mã hóa tất cả dữ liệu của bạn có thể là quá nhiều, do đó, hãy cân nhắc xem truy vấn cái gì và truy vấn như thế nào.
Học tập
- Phát triển Java 2.0: Loạt bài trên developerWorks này khám phá
các công nghệ đang định nghĩa lại bối cảnh phát triển Java, chẳng hạn như: Hadoop MapReduce (01.2011), Objectify-Appengine (11.2010), MongoDB (09.2010) và SimpleDB (06.2010).
- "Bảo mật Java:
Bảo mật Java, Phần 1: Những vấn đề cơ bản về mã hóa" (Brad Rubin,
19.07.2002): Nền tảng Java cung cấp một cơ sở tuyệt vời để viết các ứng dụng an
toàn. Hãy tìm hiểu những vấn đề cơ bản về mã hóa và nó được thực hiện trong ngôn ngữ
lập trình Java ra sao.
- "Nâng cao an toàn đám mây với ủy quyền đặc quyền" (Jim Zierick,
developerWorks, 12.2011): Thảo luận về các trường hợp để di trú một trung tâm dữ
liệu lên đám mây, cũng như các vấn đề an toàn và các suy nghĩ về tuân thủ của điện
toán đám mây.
- Con
đường kiến thức: Xây dựng một chính sách đám mây hiệu quả (developerWorks,
11.2011): Bắt đầu học cách viết một chính sách định nghĩa cơ sở hạ tầng, bảo mật,
hiệu năng hoặc các khung công tác tương tác công cộng để chạy bộ sưu tập các ứng
dụng của bạn.
- "Các bài học về
siêu máy tính, Phần 5: Giới thiệu về mã hóa, từ Ai Cập thông qua Enigma"
(Sam Siewert, developerWorks, 07.2005): Hãy vui vẻ trong khi tìm hiểu thêm về mã
hóa, có hướng dẫn này trong tay bạn sẽ xây dựng bộ mã hóa tài liệu bí mật riêng của
mình, rồi xem kỹ nội dung mã nguồn là bản sao hành động của nó.
- Con đường kiến
thức: Sử dụng NoSQL và phân tích dữ liệu lớn (developerWorks, 05.011): Một
bộ sưu tập về tài nguyên của dW cho việc học tập về NoSQL, dữ liệu lớn và khai phá
dữ liệu.
- Duyệt hiệu sách
công nghệ để biết các cuốn sách về các chủ đề kỹ thuật này và các chủ đề
khác.
-
Vùng kỹ thuật Java trên
developerWorks: Tìm hàng trăm bài viết về mọi khía cạnh của lập trình Java.
Thảo luận
- Hãy tham gia vào cộng đồng My developerWorks. Kết nối với
những người sử dụng developerWorks khác trong khi khám phá các blog, các diễn đàn,
các nhóm và các wiki theo hướng nhà phát triển.

Andrew Glover là nhà phát triển, tác giả, diễn giả và nhà doanh nghiệp có niềm đam mê về phát triển theo hành vi, Tích hợp liên tục và phát triển phần mềm Agile. Ông là người sáng lập khung công tác BDD (Behavior-Driven Development - Phát triển theo hành vi) easyb và là đồng tác giả của ba cuốn sách: Continuous Integration (Tích hợp liên tục), Groovy in Action (Thực hành Groovy) và Java Testing Patterns (Các mẫu thử nghiệm Java). Bạn có thể xem blog và theo dõi ông trên Twitter.