2016-02-13 1 views
1

Я попытался безопасно сохранить пароль в своей БД. Я читал о предмете, и все рекомендуют использовать соль и сохранить ее с паролем.Соль как было изменено после того, как я положил ее на mysql

Итак я нахожу эту реализацию:

private static byte[] setSalt() throws NoSuchAlgorithmException { 
     SecureRandom sr = SecureRandom.getInstance("SHA1PRNG"); 
     byte[] salt = new byte[16]; 
     sr.nextBytes(salt); 
     return salt; 
    } 

Тогда я попытался сохранить его в виде байтов в MySQL

public static void test(byte[] salt) throws Exception{ 
    SQLconnect sql = new SQLconnect(); 
    Object[] prepString = {salt, "admin" }; 
    sql.runQuery("UPDATE orhalimi_cl_db.users set Salt = ? where Username = ?", 
      prepString,ACTION.UPDATE); 
} 

и здесь является обновление:

preparedStatement = connect.prepareStatement(query); 
      for (int i = 0; i < prepString.length; i++) { 
       preparedStatement.setObject(i + 1, prepString[i]); 
      } 
preparedStatement.executeUpdate(); 

И когда я извлекаю соль из БД и проверяю equals, байты разные.

Я сохраняю соль как тип binary(16) в моей БД.

А вот как я его из БД:

List<HashMap<String, Object>> results; 
SQLconnect sql = new SQLconnect(); 
Object[] prepString = {"Salt", "admin" }; 
results = sql.runQuery("SELECT ? from orhalimi_cl_db.users where Username = ?", 
       prepString,ACTION.SELECT); 
     if (results.isEmpty()) { 
      System.out.println("empty"); 
      return null; 
     } 
return ((String) results.get(0).get("Salt")).getBytes(); 

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

Заранее спасибо.

Ответ:

Забавно, моя проблема заключалась в том, что я использовал ? на всех SQL PreparedStatement, а не только на стоимости. Таким образом, он выглядел как SELECT ? from orhalimi_cl_db.users who Username = ?, который превратился в SELECT 'Salt' from orhalimi_cl_db.users where Username = 'admin', и ответ был всегда солидным.

Во всяком случае, я преобразовать его в шестнадцатеричный и base64, и это намного проще

+2

Попробуйте сохранить как blob. Кроме того, на боковой ноте я думаю, что вам нужно хэш-соль с вашим паролем. – anaxin

+0

Пожалуйста, предоставьте 'SHOW CREATE TABLE' –

ответ

3

Вы пытаетесь написать необработанное значение байт в MySQL. Поскольку значения байтов являются 8-битными целыми числами в Java, это суждено пойти не так. У вас есть в основном два варианта: a) использовать тип данных BLOB или b) закодировать значение байта как строку Base64.

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

Я предпочел бы второй вариант. Это намного безопаснее и менее сложно. Тем более, что вам нужно хэш-строку с солью. С кодировкой Base64 вы можете просто конкатенировать пароль и соль, а затем вычислять хэш по строке.

EDIT: Вот пример того, как сгенерировать подсоленной SHA512 хэш:

public String getSalt() { 
    String saltStr = ""; 
    try { 
     final SecureRandom sr = SecureRandom.getInstance("SHA1PRNG"); 
     final byte[] salt = new byte[16]; 
     sr.nextBytes(salt); 
     saltStr = Base64.getEncoder().encodeToString(salt); 
    } catch (NoSuchAlgorithmException ignored) { } 

    return saltStr; 
} 

public String hashPassword(String password, String salt) 
{ 
    try { 
     final MessageDigest md = MessageDigest.getInstance("SHA-512"); 

     // hash password and salt 
     md.update(password.getBytes()); 
     md.update(salt.getBytes()); 
     final byte[] hash = md.digest(); 

     // convert byte array to hex string 
     final StringBuffer sb = new StringBuffer(); 
     for (int i = 0; i < hash.length; ++i) { 
      sb.append(Integer.toString((hash[i] & 0xff) + 0x100, 16).substring(1)); 
     } 

     return sb.toString(); 
    } catch (NoSuchAlgorithmException ignored) { return ""; } 
} 

Таким образом, вы также можете использовать любую другую строку, как соль. Но, конечно, рекомендуется использовать защищенный генератор случайных чисел, как в getSalt().

Одним из больших преимуществ использования этого метода является то, что вы в меньшей степени зависите от внутренней обработки байтов Java в целом. Сгенерированный шестнадцатеричный хэш и базовая соль Base64 вы можете легко пересчитать значение хэша вне Java, например, непосредственно внутри базы данных.

+0

Прошу сохранить, рассчитать его основание на соль и сравнить его. Это действительно работает. Забавно, моя проблема заключалась в том, что я использовал '?' На всех SQL подготовленныхStatement, а не только на значение. Таким образом, он выглядел как 'SELECT 'Salt' от orhalimi_cl_db.users, где Username = 'admin'', и ответ был всегда солидным. Другими словами - я ненавижу подготовленное заявление. В любом случае, вы поможете мне с base64 и шестнадцатеричным кодированием, поэтому мне не нужно будет с ним справляться. Спасибо –

+1

The? является лишь заполнителем ценностей, чтобы убедиться, что они правильно дезинфицированы. Они не используются для обозначения имен таблиц или столбцов. –

1

Это проблема X-Y, где реальный вопрос: Is it difficult to store password hashes properly?. Ответ - да.

Предлагаю разместить столбец с символом (60) в таблице пользователя и использовать bcrypt.

Вы намеренно изобретаете колесо? Возможно, это учебное упражнение, в этом случае go get'em tiger!

+0

Да, это учебное упражнение, но я чувствую, что я во многом с этим справляюсь .. –

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