Важлива примітка:
Якщо ви розробляєте систему автентифікації в цілому, вам не слід зберігати паролі, навіть якщо вони зашифровані. Ви зберігаєте хеш і перевіряєте, чи відповідають паролі, введені під час входу, тому самому хешу. Таким чином, порушення безпеки вашої бази даних дозволяє уникнути виявлення паролів ваших користувачів.
З огляду на це, з внутрішньо-зовнішнім мисленням, ось кілька кроків для захисту вашого процесу:
Першим кроком, вам слід змінити обробку паролів з Stringна character array.
Причиною цього є те, що a Stringє immutableоб'єктом, і тому його дані не будуть очищені відразу, навіть якщо для об'єкта встановлено значення null; Натомість дані встановлені для збору сміття, і це створює проблеми із безпекою, оскільки шкідливі програми можуть отримати доступ до цих String(парольних) даних перед тим, як їх очистити.
Це основна причина, чому метод JPasswordField SwinggetText() застарілий, і чому getPassword()використовуються масиви символів .
Другий крок - це шифрування ваших облікових даних, лише тимчасове їх розшифрування під час процесу автентифікації. Або хешувати їх на стороні сервера, зберігати цей хеш і "забувати" оригінальний пароль.
Це, подібно до першого кроку, гарантує, що час вразливості є якомога меншим.
Рекомендується, щоб ваші облікові дані не були жорстко закодовані, а замість цього ви зберігали їх у централізованому, конфігуруваному та легко підтримуваному способі, наприклад, у файлі конфігурації чи властивостей або в базі даних.
Перед збереженням файлу слід зашифрувати свої облікові дані, а крім того, ви можете застосувати друге шифрування до самого файлу (2-шарове шифрування до облікових даних та 1-шарове до іншого вмісту файлу).
Зверніть увагу, що кожен із двох згаданих вище процесів шифрування може бути багатошаровим. Кожне шифрування може бути окремим додатком стандарту потрійного шифрування даних (AKA TDES та 3DES) , як концептуальний приклад.
Після того, як ваше локальне середовище буде належним чином захищене (але пам’ятайте, воно ніколи не буде «безпечним»!), Третім кроком є застосування базового захисту до вашого процесу передачі за допомогою TLS (Transport Layer Security) або SSL (Secure Sockets Layer) .
Четвертим кроком є застосування інших методів захисту.
Наприклад, застосовуючи прийоми затухання до вашої компіляції "для використання", щоб уникнути (навіть невдовзі) впливу ваших заходів безпеки у випадку, якщо ваша програма отримана пані Євою, містером Меллорі або кимось іншим (погано хлопці) і декомпілювали.
ОНОВЛЕННЯ 1:
За запитом @ Damien.Bell, ось приклад, який охоплює перший та другий кроки:
private static final Map<String, String> COMMON_ATTRIBUTES = new HashMap<String, String>();
private static final Map<String, char[]> SECURE_ATTRIBUTES = new HashMap<String, char[]>();
private static final char[] PASSWORD = "Unauthorized_Personel_Is_Unauthorized".toCharArray();
private static final byte[] SALT = {
(byte) 0xde, (byte) 0x33, (byte) 0x10, (byte) 0x12,
(byte) 0xde, (byte) 0x33, (byte) 0x10, (byte) 0x12,};
private static final File DESKTOP = new File(System.getProperty("user.home") + "/Desktop");
private static final String NO_ENCRYPTION = "no_layers.txt";
private static final String SINGLE_LAYER = "single_layer.txt";
private static final String DOUBLE_LAYER = "double_layer.txt";
public static void main(String[] args) throws GeneralSecurityException, FileNotFoundException, IOException {
COMMON_ATTRIBUTES.put("Gender", "Male");
COMMON_ATTRIBUTES.put("Age", "21");
COMMON_ATTRIBUTES.put("Name", "Hypot Hetical");
COMMON_ATTRIBUTES.put("Nickname", "HH");
SECURE_ATTRIBUTES.put("Username", "Hypothetical".toCharArray());
SECURE_ATTRIBUTES.put("Password", "LetMePass_Word".toCharArray());
create_EncryptedFile(NO_ENCRYPTION, COMMON_ATTRIBUTES, SECURE_ATTRIBUTES, 0);
create_EncryptedFile(SINGLE_LAYER, COMMON_ATTRIBUTES, SECURE_ATTRIBUTES, 1);
create_EncryptedFile(DOUBLE_LAYER, COMMON_ATTRIBUTES, SECURE_ATTRIBUTES, 2);
System.out.println("NO ENCRYPTION: \n" + readFile_NoDecryption(NO_ENCRYPTION) + "\n\n\n");
System.out.println("SINGLE LAYER ENCRYPTION: \n" + readFile_NoDecryption(SINGLE_LAYER) + "\n\n\n");
System.out.println("DOUBLE LAYER ENCRYPTION: \n" + readFile_NoDecryption(DOUBLE_LAYER) + "\n\n\n");
String decryptedContent = readFile_ApplyDecryption(DOUBLE_LAYER);
System.out.println("READ: [first layer decrypted]\n" + decryptedContent + "\n\n\n");
for (String line : decryptedContent.split("\n")) {
String[] pair = line.split(": ", 2);
if (pair[0].equalsIgnoreCase("Username") || pair[0].equalsIgnoreCase("Password")) {
System.out.println("Decrypted: " + pair[0] + ": " + decrypt(pair[1]));
}
}
}
private static String encrypt(byte[] property) throws GeneralSecurityException {
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("PBEWithMD5AndDES");
SecretKey key = keyFactory.generateSecret(new PBEKeySpec(PASSWORD));
Cipher pbeCipher = Cipher.getInstance("PBEWithMD5AndDES");
pbeCipher.init(Cipher.ENCRYPT_MODE, key, new PBEParameterSpec(SALT, 20));
String encrypted = Base64.encodeBytes(pbeCipher.doFinal(property));
for (int i = 0; i < property.length; i++) {
property[i] = 0;
}
property = null;
System.gc();
return encrypted;
}
private static String encrypt(char[] property) throws GeneralSecurityException {
byte[] bytes = new byte[property.length];
for (int i = 0; i < property.length; i++) {
bytes[i] = (byte) property[i];
}
String encrypted = encrypt(bytes);
return encrypted;
}
private static String encrypt(String property) throws GeneralSecurityException {
String encrypted = encrypt(property.getBytes());
property = null;
return encrypted;
}
private static String decrypt(String property) throws GeneralSecurityException, IOException {
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("PBEWithMD5AndDES");
SecretKey key = keyFactory.generateSecret(new PBEKeySpec(PASSWORD));
Cipher pbeCipher = Cipher.getInstance("PBEWithMD5AndDES");
pbeCipher.init(Cipher.DECRYPT_MODE, key, new PBEParameterSpec(SALT, 20));
return new String(pbeCipher.doFinal(Base64.decode(property)));
}
private static void create_EncryptedFile(
String fileName,
Map<String, String> commonAttributes,
Map<String, char[]> secureAttributes,
int layers)
throws GeneralSecurityException, FileNotFoundException, IOException {
StringBuilder sb = new StringBuilder();
for (String k : commonAttributes.keySet()) {
sb.append(k).append(": ").append(commonAttributes.get(k)).append(System.lineSeparator());
}
for (String k : secureAttributes.keySet()) {
String encryptedValue;
if (layers >= 1) {
encryptedValue = encrypt(secureAttributes.get(k));
} else {
encryptedValue = new String(secureAttributes.get(k));
}
sb.append(k).append(": ").append(encryptedValue).append(System.lineSeparator());
}
File f = new File(DESKTOP, fileName);
if (!f.getParentFile().exists()) {
f.getParentFile().mkdirs();
} else if (f.exists()) {
f.delete();
}
BufferedWriter bw = new BufferedWriter(new FileWriter(f));
if (layers >= 2) {
bw.append(encrypt(sb.toString().trim()));
} else {
bw.append(sb.toString().trim());
}
bw.flush();
bw.close();
}
private static String readFile_NoDecryption(String fileName) throws FileNotFoundException, IOException, GeneralSecurityException {
File f = new File(DESKTOP, fileName);
BufferedReader br = new BufferedReader(new FileReader(f));
StringBuilder sb = new StringBuilder();
while (br.ready()) {
sb.append(br.readLine()).append(System.lineSeparator());
}
return sb.toString();
}
private static String readFile_ApplyDecryption(String fileName) throws FileNotFoundException, IOException, GeneralSecurityException {
File f = new File(DESKTOP, fileName);
BufferedReader br = new BufferedReader(new FileReader(f));
StringBuilder sb = new StringBuilder();
while (br.ready()) {
sb.append(br.readLine()).append(System.lineSeparator());
}
return decrypt(sb.toString());
}
Повний приклад, що стосується кожного кроку захисту, набагато перевищує те, що, на мою думку, є розумним для цього питання, оскільки мова йде про "які етапи" , а не "як їх застосовувати" .
Це могло б значно перевищити мою відповідь (нарешті, вибірку), тоді як інші питання тут, на тему SO, вже спрямовані на те, "як робити" ці кроки, будучи набагато більш доречними, і пропонуючи набагато кращі пояснення та вибірку щодо впровадження кожен окремий крок.