2015-02-09 4 views
0

Я пытаюсь защитить пароли веб-приложения, которое я создаю. Я довольно новичок в криптографии. Я использую Java и Sha-1 Hash для хранения пароля в Db.Защита паролей SHA-1 Java

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

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

Большое вам спасибо!

@Entity 
@Table(name="USERS") 
public class User implements BasePersistentEntity<Long> { 

/** 
* 
*/ 
private static final long serialVersionUID = 1L; 


@Id 
@GeneratedValue(strategy=GenerationType.IDENTITY) 
@Column(name="ID") 
private Long id; 

@Column(name="EMAIL",nullable=false,length=50,insertable=true,updatable=true) 
private String email; 

@Column(name="PASSWORD",nullable=false,length=40,insertable=true,updatable=true) 
private String password; 

@Column(name="SALT",nullable=false,length=40,insertable=true,updatable=true) 
private String passwordSalt; 


public Long getId() { 
    return id; 
} 

public void setId(Long id) { 
    this.id = id; 
} 

public String getEmail() { 
    return email; 
} 

public void setEmail(String email) { 
    this.email=email; 
} 

public String getPassword() { 
    return password; 
} 

public void setPassword(String password) { 
    if (password.equals(this.password)) 
    { 
     return; 
    } 

    if (passwordSalt == null || passwordSalt.equals("")) 
    { 
     passwordSalt = RandomStringUtils.randomAscii(20); 
    } 

    this.password = DigestUtils.sha1Hex(password + passwordSalt); 
} 

/** 
* Check if a given password is correct. 
* 
* @param givenPassword 
* @return True is correct, else false. 
*/ 
public boolean checkPassword(String givenPassword) 
{ 
    return (password.equals(DigestUtils.sha1Hex(givenPassword + passwordSalt))); 
} 


public String getPasswordSalt() { 
    return passwordSalt; 
} 

public void setPasswordSalt(String passwordSalt) { 
    this.passwordSalt = passwordSalt; 
} 
} 
+4

SHA1 не является надежным. Используйте scrypt или bcrypt или PBKDFv2. – SLaks

+1

Релевантно: http: //security.stackexchange.com/questions/51959/why-are-salted-hashes-more-secure – immibis

+0

Также у вас есть как минимум два разных вопроса: «Если кто-то украдет мою базу данных солями, они могут прочитать пароли?» (возможно, лучше подходит для security.se) и «Должен ли я добавить новый столбец или сохранить две вещи в одном столбце, разделенные символом' | '?" – immibis

ответ

1

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

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

То, что вам не хватает, это какой-то коэффициент работы или счетчик итераций. Это обеспечивается функциями детекции ключа пароля, такими как PBKDF2 (входит в Java) или bcrypt. Это обеспечит некоторую дополнительную защиту от нападений с использованием грубой силы (пытается использовать всевозможные пароли и посмотреть, совпадают ли они). Это добавит некоторую безопасность, поскольку паролям обычно не хватает энтропии.

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


Пример без перца:

import java.security.NoSuchAlgorithmException; 
import java.security.SecureRandom; 
import java.security.spec.InvalidKeySpecException; 
import java.security.spec.KeySpec; 

import javax.crypto.SecretKey; 
import javax.crypto.SecretKeyFactory; 
import javax.crypto.spec.PBEKeySpec; 

public class PBKDF2ForPasswordHash { 

    private static final String PBKDF_ALGORITHM = "PBKDF2WithHmacSHA1"; 
    private static final int ITERATION_COUNT = 10_000; 
    // should be less than the size of the underlying hash 
    private static final int PASSWORD_HASH_SIZE_BYTES = 16; 
    private static final int SALT_SIZE_BYTES = 16; 

    public static byte[] generateRandomSalt(final int saltSizeBytes) { 
     final SecureRandom rng = new SecureRandom(); 
     final byte[] salt = new byte[saltSizeBytes]; 
     rng.nextBytes(salt); 
     return salt; 
    } 

    public static byte[] generatePasswordHash(final char[] password, 
      final byte[] salt) { 
     SecretKeyFactory f; 
     try { 
      f = SecretKeyFactory.getInstance(PBKDF_ALGORITHM); 
     } catch (final NoSuchAlgorithmException e) { 
      throw new IllegalStateException("PBKDF algorithm " 
        + PBKDF_ALGORITHM + " not available", e); 
     } 
     final KeySpec ks = new PBEKeySpec(password, salt, ITERATION_COUNT, 
       PASSWORD_HASH_SIZE_BYTES * Byte.SIZE); 
     SecretKey s; 
     try { 
      s = f.generateSecret(ks); 
     } catch (final InvalidKeySpecException e) { 
      throw new IllegalArgumentException(
        "PBEKeySpec should always be valid for " + PBKDF_ALGORITHM, 
        e); 
     } 
     return s.getEncoded(); 
    } 

    public static final String toHex(final byte[] data) { 
     final StringBuilder sb = new StringBuilder(data.length * 2); 
     for (int i = 0; i < data.length; i++) { 
      sb.append(String.format("%02x", data[i])); 
     } 
     return sb.toString(); 
    } 

    public static void main(final String[] args) throws Exception { 
     final char[] password = { 'o', 'w', 'l' }; 
     final byte[] salt = generateRandomSalt(SALT_SIZE_BYTES); 
     System.out.println(toHex(salt)); 
     final byte[] hash = generatePasswordHash(password, salt); 
     System.out.println(toHex(hash)); 
    } 
} 
+0

ummm plz не сохраняет пароль в ящике. Вы имеете в виду хеш пароля? – stringy05

+0

@ stringy05 Необходимо опоздать :) –

+0

ха-ха. это рано, где я! – stringy05

0

Хранение соли рядом с хэш в открытом порядке, потому что пароль является безопасным (предоставить вам справиться с должным вниманием на приложение - журнал DonT это и т. д.). Точка соли должна иметь уникальный вход для хэша для пользователя, поэтому вы не можете просто использовать таблицу радуги или угадывать пароль (например, у многих пользователей одинаковый хэш, тогда они используют один и тот же пароль. md5 хэша «password01» наизусть из-за дерьмового приложения wep, к которому я имел возможность посмотреть)

Чтобы узнать, как правильно это сделать, выполните следующие действия: https://crypto.stackexchange.com/questions/760/webapp-password-storage-salting-a-hash-vs-multiple-hashes, поскольку вам необходимо убедиться, что вы не подвержены таким вещам, как сроки нападения (среди плота других серьезных проблем)

EDIT

для более подробной информации о безопасном хранении паролей, обратитесь к этому из защитные ниндзя на матасано http://chargen.matasano.com/chargen/2015/3/26/enough-with-the-salts-updates-on-secure-password-schemes.html

0

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

+0

Хотя я рад, что вас беспокоит безопасность, я должен отметить, что это комментарий, а не ответ. –

+0

Да, ты прав :) –

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