2012-05-14 17 views
7

Używam Hibernate/Java do utrzymywania jednostki w bazie danych. Podmiot ma pole hasło, które jest String. Rejestrując użytkownika w mojej aplikacji, hash hasło za pomocą SHA-1 (uznaję, że jest to trochę słabe). W ten sposób powstaje byte [] które następnie przekonwertować do String użyciu new String(byte[] arr); Ilekroć chcę zalogować użytkownika w, po prostu odzyskać zaszyfrowany hasło z bazy danych (jak String) i porównaj go z trawienia z hasła wejściowego przy logowaniu z użyciem hashedPasswordFromDatabase.equals(SHA1_HASH(inputPassword));Jak odwzorować właściwość bajtów [] przy użyciu trybu hibernacji?

To działało idealnie w moim systemie rozwoju (Windows 7, JDK 1.6.0_23/JDK 1.7, MySQL 5.5, Tomcat 6.0.26), ale po wdrożeniu go na naszym serwerze (z JDK 1.6 na Linuksie), równa się metoda nev er ocenia PRAWDA nawet dla równych haseł. Szybko konfiguruję nowy system programistyczny (Ubuntu 12.04, MySQL 5.5, JDK 1.7.0_03, Tomcat 7.0.22) i tam też nie działa.

Jestem świadomy możliwych problemów z kodowaniem podanych w dokumentacji interfejsu API języka Java dla klasy String, a także podanych w kilku miejscach na stronie SO. Próbowałem kilka kodowań sugerowanych na tym forum (np. Base64, Latin-1) i skończyło się na UnsupportedEncodingException. Myślę, że lepiej będzie, jeśli uniknę konwersji na String. Jak więc zaprojektować moją bazę danych tak, aby klasa jednostek generowanych przez Hibernate pojawiła się z bajtem [] dla pola 01 zamiast String?

+1

+1, bardzo dobre pytanie. Na marginesie, który nie jest odpowiedzią na twoje pytanie, miałem bardzo dużo szczęścia przy korzystaniu z narzędzi Commons Base64 wchodzących i wychodzących z bazy danych. –

+2

Dlaczego miałbyś zapisywać ciąg reprezentujący liczbę zamiast przechowywania samej liczby? – m0skit0

+0

Nie używaj jednej rundy mieszania w celu ochrony haseł. Użyj czegoś takiego jak PBKDF2 lub bcrypt z 10s tysięcy rund --- nawet 100k nie jest nierozsądne. Przechowywanie "bajtów []" o stałej długości powinno być proste dla większej ilości baz danych, ale zawsze możesz utworzyć "BigInteger" z tablicy bajtów i zapisać je jako typ numeryczny. – erickson

Odpowiedz

5

Tak, najprawdopodobniej problem występuje w konwersji byte[] na String. Musisz wiedzieć, że SHA produkuje surową macierz byte i nie ma żadnej gwarancji, że arbitralne byte[] będzie produkować ważne String, niezależnie od kodowania. W ten sposób Twój kod działał tylko przez przypadek.

uniknąć problemu całkowicie przez:

  • przechowywania surowego byte[] w blob - najbezpieczniejszym i najbardziej efektywny sposób przechowywania. W Hibernuj wystarczy użyć właściwości byte[] w swoim POJO.

  • kodowanie byte[] przy użyciu (sprawdź pod numerem Decode Base64 data in Java) i zapisz jako ciąg.

BTW remember about salting!

+0

Wielkie dzięki. Czy masz na myśli, że BLOB rzeczywiście sprawi, że Hibernate wygeneruje pole w jednostce jako 'byte []'? –

+0

@ SayoStealth-virusOladeji: Jeśli użyjesz 'byte []', hbm2ddl powinno wygenerować obiekt BLOB. I odwrotnie - jeśli w bazie danych znajduje się obiekt BLOB, można go bezpiecznie zamapować na "bajt []". –

+0

Świetnie! Przechodzę obecnie przez udostępnioną stronę Base64; warto ją przeczytać. –

0

można przekonwertować bajt do szesnastkowym reprezentacji tak:

public String encryptPassword(String passwordInClear) { 
      // Salt all you want here. 
      MessageDigest sha256 = MessageDigest.getInstance("SHA-256"); 
    byte[] digest = sha256.digest(passwordInClear.getBytes()); 
    return digestToString(digest); 
} 

private String digestToString(byte[] digest) { 
    StringBuilder hashString = new StringBuilder(); 
    for (int i = 0; i < digest.length; i++) { 
     String hex = Integer.toHexString(digest[i]); 
     if (hex.length() == 1) { 
      hashString.append('0'); 
      hashString.append(hex.charAt(hex.length() - 1)); 
     } else { 
      hashString.append(hex.substring(hex.length() - 2)); 
     } 
    } 
    return hashString.toString(); 
} 
+0

Jak to wpływa na siłę hashowanego hasła? Czy to podejście osłabia to? –

+0

@ SayoStealth-virusOladeji Nie, nie osłabia go ani nie wzmacnia. Jest to prosta rzecz, która odwzorowuje bajt na jego "równoważną" wartość ciągu, reprezentując każdy bajt według jego wartości liczbowej (0 oznacza "00", 16 staje się "10", 255 staje się "FF", itd ...). Przejście od jednego do drugiego jest dwukierunkowe, ale prawdziwa "siła" lub "słabość" jest w trakcie trawienia hasła. –

+0

Świetnie! Wielkie dzięki. Myślę, że zastosuję to podejście, ponieważ nie będę musiał dotykać bazy danych ani żadnych innych rzeczy w pobliżu :) –

1

W moim przypadku, złe projektowanie baz danych wcisnąć mi użyć Blob w przypadku Clob. Rozwiązaniem było Mapowanie w hibernacji właściwości z adnotacją Lob i wstawienie innej właściwości w typie String.

Na innym poziomie kodu, gdy wywołuję get lub zestaw, używam właściwości String i tej, pobierz lub ustaw wartość tablicy bajtowej.

@Entity 
@Table(name = "CMUN_TAGS") 
@SequenceGenerator(name = "idSeqTag", sequenceName = "SEQ_CMUN_TAGS") 
public class CmunTagsDO implements java.io.Serializable { 
    private BigDecimal lngIdTag; 
    private byte[] blobValTag; 
    private String strValTag; 

    @Id 
    @Column(name = "LNG_ID_TAG", unique = true, nullable = false, precision = 20, scale = 0) 
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "idSeqTag") 
    public BigDecimal getLngIdTag() { 
    return this.lngIdTag; 
    } 

    public void setLngIdTag(BigDecimal lngIdTag) { 
    this.lngIdTag = lngIdTag; 
    } 

    @Column(name = "BLOB_VAL_TAG", nullable = false) 
    @Lob 
    public byte[] getBlobValTag() { 
    return this.blobValTag; 
    } 

    public void setBlobValTag(byte[] blobValTag) { 
    this.blobValorTag = blobValorTag; 
    } 

    @Transient 
    public String getStrValTag() { 
    strValTag = new String(getBlobValTag()); 
    return strValTag; 
    } 

    public void setStrValTag(String strValTag) { 
    setBlobValTag(strValTag.getBytes()); 
    this.strValTag = strValTag; 
    } 
} 
Powiązane problemy