2015-12-17 5 views
0

Я прочитал несколько мест, которые в основном советуют не хранить пароль в исходном коде, и я понимаю причины.Сохранение пароля в источнике

У меня есть два приложения: один для шифрования и один для расшифровки. Данные шифруются в файл на сервере; этот файл загружается и дешифруется на компьютере клиента, а затем обрабатывается проприетарным приложением (не мое). Данные чувствительны и, в идеале, предназначены только для приложения обработки. В своем роде я использую алгоритм симметричного ключа, так как данные достаточно велики. Пароль жестко закодирован в исходный код в виде строки - я знаю, плохо по нескольким причинам.

Что я хотел бы знать, так это как лучше всего хранить пароль? Моя мысль заключается в использовании алгоритма асимметричного ключа, например. RSA, просто для пароля, но не могу окунуться в голову, как это сделать, и если это даже имеет смысл в моем сценарии. Я бы предпочел не вводить другой файл для распространения. Я не очень разбираюсь в декомпиляции, но я решил, что внедрение PBKD в клиентское приложение создаст ту же проблему. Криптография для меня новая, как вы можете сказать, и используя этот отличный форум.

+0

Итак, вы хотите, чтобы ваша программа имела данные, но пользователь не так ли? Затем не отправляйте данные клиенту. Выполняйте обработку на сервере. – deviantfan

+0

openSSL будет хорошим вариантом библиотеки для криптографии ..https: //www.openssl.org/docs/manmaster/crypto/crypto.html – basav

+0

Посмотрите на этот учебник о том, как реализовать openssl https://www.ibm .com/developerworks/library/l-openssl/ – silvergasp

ответ

-2

Вместо хранения открытого текста в источнике и проверки на него вы можете хранить зашифрованный пароль в источнике (жестко закодированный).

Затем пользователь может ввести пароль, код шифрует пароль и сравнивает результат шифрования с сохраненным зашифрованным значением, чтобы узнать, совпадает ли пароль. Введенный пароль (а не зашифрованный пароль) затем используется для шифрования/дешифрования данных.

Используемое шифрование должно прилагать усилия к тому, чтобы перекрыть зашифрованный пароль на пароль открытого текста трудно/невозможно.

Пример:

  1. Вы выбираете пароль шифрования/дешифрования быть This is my password1 (тот, который в настоящее время в источниках).
  2. Вы шифруете пароль с помощью, например, SHA-256 и жестко кодируете его в источнике: 9845735b525fa70b2651975022a44be268af1d4defadba9ab2a0301e0579534c.
  3. Зашифровать/дешифровать приложение для ввода пароля.
  4. Пользователь вводит пароль.
  5. App вычисляет SHA-256 введенного пароля и сравнить результат 9845735b525fa70b2651975022a44be268af1d4defadba9ab2a0301e0579534c
  6. Если он совпадает данные шифруются/расшифровываются введенный пароль This is my password1 используя код уже на месте.
  7. Если он не совпадает, сообщите об ошибке.

Хакер получает ваши источники и имеет доступ к хэшу 9845735b525fa70b2651975022a44be268af1d4defadba9ab2a0301e0579534c и алгоритм, который вы использовали. Но для дешифрования данных ему нужен пароль This is my password1. Он может отменить или наложить грубую силу на хэш, но это требует усилий и времени.

Можно использовать семена и т. Д., Но сохранить их в тайне - это опять та же проблема.

Это, вероятно, не самый безопасный, я не эксперт, но он лучше, чем наличие This is my password1 в источниках.

+1

a) RSA не является хешем. b) MD5 не является безопасным вообще. c) Никакая хеш-память не должна быть отменена, если все находится на клиентском устройстве. Это намного проще. d) Если хэш зашифрован, а ключ тоже находится в программе, зачем вообще шифровать? – deviantfan

+0

@deviantfan Я понимаю, что вы имеете в виду, и обновил мой ответ, чтобы сделать его более ясным, что я хотел сказать, это помогает? –

+0

Не так, потому что а) шифрование, как вы описали в последнем предложении, не существует, б) ключ должен быть где-то, если это шифрование, и в) как уже сказано, это вообще не помогает, потому что злоумышленнику не нужно отменять что-то необратимое. – deviantfan

0

Пожалуйста, не используйте симметричные ключи в исходных файлах. Вы можете использовать RSA, не вводя другой файл.В отличие от симметричных ключей, открытый ключ может быть жестко закодирован в исходном коде без каких-либо проблем с безопасностью, если вы можете гарантировать целостность исходного файла. Опять же, если кому-то удастся его изменить, дешифрование не будет работать или произойдет атака «человек-в-середине» (MITM) (и вы не узнаете об этом).

ПРЕДОСТЕРЕЖЕНИЯ

  • Этот подход страдает от восприимчивости атаки MITM. Соответствующая контрмера должна заключаться в подписи данных, но тогда вы застряли в обращении с ключами, и это действительно отдельный вопрос.
  • Ключи не навсегда, генерируемая вами пара ключей должна время от времени поворачиваться.
  • Сделайте ключи достаточно большими (не менее 2048 бит).
  • Отмена должна быть выполнена вами вручную. Если вам нужно более автоматическое решение, подумайте о PKI и OSCP Responders (с или без сшивания).
  • Если данные, которые вы отправляете, являются большими, операции RSA будут длинными.

Хорошо, с этим из пути, давайте копать. Пример кода написан полностью с JDK 8.

Во-первых, генерировать пары ключей. Это должно быть сделано один раз или каждый раз, когда вам нужно повернуть:

KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA"); 
KeyPair keyPair = kpg.generateKeyPair(); 
PublicKey publicKey = keyPair.getPublic(); 
PrivateKey privateKey = keyPair.getPrivate(); 

byte[] pubEnc = publicKey.getEncoded(); 
byte[] privKeyEnc = privateKey.getEncoded(); 

System.out.println(Base64.getEncoder().encodeToString(pubEnc)); 
System.out.println(Base64.getEncoder().encodeToString(privKeyEnc)); 

Скажем, открытый ключ был (это фактические ключи я сгенерированные, не использовать эти):

private static final String PUBLIC_KEY_BASE64 = 
"MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCGue 
5TCdPJt08w7crbvWjfcSUy/xXjzjjjjPDP7D8PNSnn 
CUeNcGWsR/Pd3eoBjmrAy/4Rl8JlHylRry8pX7Zpcz 
iQB8wWQdpkSoArjeu4taeFn/45+eg4J5mzmIzFG9F5 
wF7N+SeSvtq3E3Q0mtJRRZZJYgNkFmeDuOQjljJVZw 
IDAQAB"; 

и закрытый ключ был:

private static final String PRIVATE_KEY_BASE64 = 
"MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAg 
EAAoGBAIa57lMJ08m3TzDtytu9aN9xJTL/FePOOOOM 
8M/sPw81KecJR41wZaxH893d6gGOasDL/hGXwmUfKV 
GvLylftmlzOJAHzBZB2mRKgCuN67i1p4Wf/jn56Dgn 
mbOYjMUb0XnAXs35J5K+2rcTdDSa0lFFlkliA2QWZ4 
O45COWMlVnAgMBAAECgYBAWTIRi1ISuHEkh48qoS8j 
+eCwmNGVuvvFA55JUSdVVikrZm08iwCk5sD9qW6JS8 
KFT2mMcZWxws5za171PffbeHoIFaNI5n5OXJa4meZA 
cgl4ae5su89BjvfzDF2gsnBHwLpgsT0aVdIDQ5BGtL 
WzRwZCogY6lZhBOQZAaNFYIQJBALr2+kT+pkSlxrrR 
tMxK7WL+hNO7qOIl/CTBuAa6/zTtoEjFMFQBY//jH+ 
6iabHDfKpaFwh6ynZTXZsb7qIKOM8CQQC4eRAH1VEo 
iofZNnX3VjiI5mLtV8rc8Jg+wznN+WFnwdNoLK8y9t 
EcuKxg3neIJAM70D6l0IhBfza1QAqQh4/pAkA5vyLZ 
wJV2SoWxGihvmQztMJOyGho1j2nrqHHAkm1U2bhSAa 
XFrJBIbsxkFoHyx+BvdVf75IE4PtOAnwX7wpB9AkBQ 
7CKBHS2N+D8hpQdYqcUBIPdyoFmIVC6lEaTw2x3Ekz 
027KsqUyVmUQilMdIDsbCNc4uX14N+H90S43X+8sjJ 
AkAKsvRbZ0Au9JytSRKSB7vYl37283zHoQ5jyYUE7x 
g7C6nWSl1GEa6khZ47hFAj9C2bdLJ6GtjTleFsVCsR 
LUoG"; 

клавиши выше, линия завернуты по причинам форматирования.

Скажем args[0] был "attack at dawn!" и ваш клиент выглядит следующим образом:

public static void main(String[] args) throws Exception { 
    byte[] pubKey = Base64.getDecoder().decode(PUBLIC_KEY_BASE64); 
    PublicKey publicKey = KeyFactory.getInstance("RSA").generatePublic(new X509EncodedKeySpec(pubKey)); 

    Cipher cipher = Cipher.getInstance("RSA"); 
    Cipher.init(Cipher.ENCRYPT_MODE, publicKey); 
    String encryptedData = Base64.getEncoder().encodeToString(cipher.doFinal(args[0].getBytes("UTF-8"))); 
    System.out.println("Encrypted data is: " + encryptedData); 
} 

Выход: Зашифрованные данные: cDoPpQYc6qibrBl5jdENcV + g6HslQDlo9potca5rQxecnxR3Bd/e1T0njqUMACl7x7AG3foGxqZyyUIMrOVXcnw/ux7BgQcg + RDZhSVFQAd5kUGI96pw8WtDVo1N1 + WEfaaPhK9CpwUKUxtwR0t27n + W0vhFCqNTEGhofLt8u9o =

Сервер:

public static void main(String[] args) throws Exception { 
    byte[] privKey = Base64.getDecoder().decode(PRIVATE_KEY_BASE64); 
    PrivateKey privateKey = KeyFactory.getInstance("RSA").generatePrivate(new PKCS8EncodedKeySpec(privKey)); 

    Cipher cipher = Cipher.getInstance("RSA"); 
    cipher.init(Cipher.DECRYPT_MODE, privateKey); 
    byte[] encryptedData = Base64.getDecoder().decode(args[0]); 
    byte[] decryptedData = cipher.doFinal(encryptedData); 
    System.out.println("Decrypted message was: " + new String(decryptedData, "UTF-8")); 

} 

Выход: Расшифрованное сообщение было: атака на рассвете!

Одна классная вещь о реализации RSA в JDK является то, что он использует Optimal Asymmetric Encryption Padding (OAEP) с PKCS # 1, который имеет эффект, что даже идентичные сообщения будут отличаться от каждого шифрования.

Как и предыдущие комментаторы упомянули, не видя полную картину, могут возникнуть другие проблемы с безопасностью. Но для чего это стоит, я думаю, что этот подход лучше, чем использование симметричных ключей, которые все еще могут использоваться с этой схемой шифрования.Затем вы получите так называемую гибридную криптосистему , но есть API, которые делают это за вас.

+0

Отличный пример, и спасибо за совет! Я думаю, в моем случае, хотя это обратный сценарий: сервер только шифрует, а клиент только расшифровывает, нет другого сообщения. Дешифрованные данные обрабатываются на их локальной машине из другого процесса (а не моего). Учитывая это, не будет ли частный ключ с клиентом? Это нормально, за исключением рук не того человека, я хочу ограничить доступ только к этому открытому тексту. – aeh

+0

Хм. Из-за обычной неотъемлемой асимметрии в клиент-серверной модели (многие клиенты и несколько серверов), только шифрование данных, предназначенных для клиента, звучит как плохая идея.Частный ключ должен быть распределен в среде (клиенте), которую вы обычно не контролируете. И если вы поместите его в исходный код, есть только один ключ, который делает его очень уязвимым. Если это так, я бы рассмотрел использование Диффи-Хеллмана вместо RSA. Вы все равно были бы восприимчивы к атакам MITM, но, с другой стороны, вы получили бы PFS (Perfect Forward Secrecy). – Daniel

+0

Сладкий, я посмотрю на это. – aeh

Смежные вопросы