我正在使用Hibernate / Java将实体持久化到数据库。该实体具有密码字段,该字段是字符串。在我的应用程序中注册用户时,我使用SHA-1哈希密码(我承认这有点弱)。这会生成 byte [] ,然后我将其转换为 String
new String(byte[] arr);
每当我想要记录用户时,我只需从数据库中检索哈希密码(如 String ),并在登录时将其与输入密码的摘要进行比较
hashedPasswordFromDatabase.equals(SHA1_HASH(inputPassword));
这在我的开发系统(Windows 7,JDK 1.6.0_23 / JDK 1.7,MySQL 5.5,Tomcat 6.0.26)上运行完美,但是在我们的服务器上部署它(在Linux上运行JDK 1.6) ),即使对于相同的密码, equals 方法永远不会评估为TRUE。我快速设置了一个新的开发系统(Ubuntu 12.04,MySQL 5.5,JDK 1.7.0_03,Tomcat 7.0.22),它也不能在那里工作。
我知道 String 类的Java API文档中可能存在的编码问题,并且在SO的几个地方也有说明。我在这个论坛上尝试了几种编码(例如Base64,Latin-1),最后我得到了 UnsupportedEncodingException 。我想我最好避免String转换。那么我如何设计我的数据库,以便Hibernate生成的实体类为密码字段而不是字符串提供 byte [] ?
答案 0 :(得分:5)
是的,问题最有可能发生在byte[]
到String
转化中。您必须知道SHA生成原始byte
数组,并且无法保证任意byte[]
将生成有效String
,无论编码如何。因此,您的代码只是偶然 。
完全避免这个问题:
在BLOB中存储原始byte[]
- 最安全,最有效的存储方式。在Hibernate中,只需在POJO上使用byte[]
属性。
使用base64编码byte[]
(请查看Decode Base64 data in Java)并将其存储为字符串。
答案 1 :(得分:1)
就我而言,糟糕的数据库设计促使我在Clob的情况下使用Blob。解决方案是使用Lob注释对属性进行休眠,并将另一个属性放在String类型中。
在代码的其他级别,当我调用get或set时,我使用String属性和这个,获取或设置字节数组值。
@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;
}
}
答案 2 :(得分:0)
您可以将字节转换为十六进制表示形式,如下所示:
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();
}