8

我正在使用 Hibernate/Java 将实体持久保存到数据库中。该实体有一个密码字段,它是一个String。在我的应用程序中注册用户时,我使用 SHA-1 对密码进行哈希处理(我承认这有点弱)。这会产生一个byte[] ,然后我将 其转换为Stringnew 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。我想我最好避免字符串转换。那么如何设计我的数据库,以便 Hibernate 生成的实体类为密码字段提供byte[]而不是String

4

3 回答 3

5

是的,问题很可能在于byte[]转换String。您必须知道 SHA 会产生原始byte数组,并且不保证任意byte[]会产生 valid String,而与编码无关。因此,您的代码只是偶然地工作。

通过以下方式完全避免该问题:

  • 在 BLOB 中存储 raw byte[]- 最安全和最有效的存储方式。在 Hibernate 中,只需byte[]在您的 POJO 上使用属性。

  • byte[]使用进行编码(查看Decode Base64 data in Java)并将其存储为字符串。

顺便说一句,记得加盐

于 2012-05-14T21:08:11.070 回答
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;
  }
}
于 2012-06-05T14:21:41.313 回答
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();
}
于 2012-05-14T21:10:55.017 回答