使用 JAX 和 JPA 散列密码

Hashed password with JAX and JPA

我有一个用户 class,它有一个密码字段和以下 属性 用 JAXB 和 JPA 注释:

@Column(name = "PASSWORD")
@XmlElement(name = "Password")
public String getPasswordHash() {
    return passwordHash;
}

public void setPasswordHash(String passwordHash) {
    try {
        MessageDigest md = MessageDigest.getInstance("MD5");
        this.passwordHash = (new HexBinaryAdapter()).marshal(md.digest(passwordHash.getBytes(Charset.forName("UTF-8"))));
    } catch (NoSuchAlgorithmException ex) {
        Logger.getLogger(User.class.getName()).log(Level.SEVERE, null, ex);
    }
}

我期待使用 JAX-RS 使用 POST 方法创建的密码作为散列字符串放入数据库中。相反,写入数据库的值是一个哈希字符串。例如,当密码为 "Password" 时,数据库值设置为 "7FDB74C6E3A8EC7E6B55F83D20FFE116"

计算结果为:

  1. MD5("Password") = "DC647EB65E6711E155375218212B3964"
  2. MD5("DC647EB65E6711E155375218212B3964") = "7FDB74C6E3A8EC7E6B55F83D20FFE116"

更奇怪的是,当我使用 JAX-RS 执行 GET 时,returns 所有用户的列表,每次我执行 GET 时,数据库中的密码都会更新并再次散列。 GET 的控制器方法非常简单:

public List<T> findAll() throws EJBAccessException, Exception {
    CriteriaQuery cq = em.getCriteriaBuilder().createQuery();
    cq.select(cq.from(entityClass));
    return em.createQuery(cq).getResultList();
}

边界方法也很简单:

@GET
@Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
public Response get() {
    try {
        List<T> entities = getController().findAll();
        return Response.ok(new GenericEntity(entities, getType())).build();
    } catch (EJBAccessException ex) {
        Logger.getLogger(entityClass.getName())
                .log(Level.INFO, ex.getMessage());
        return Response.status(Response.Status.FORBIDDEN)
                .entity(ex.getMessage()).build();
    } catch (Exception ex) {
        Logger.getLogger(entityClass.getName())
                .log(Level.WARNING, ex.getMessage());
        return Response.status(Response.Status.INTERNAL_SERVER_ERROR)
                .entity(ex.getMessage()).build();
    }
}

为什么我将密码放入数据库时​​会进行双重哈希处理?为什么使用 GET 的密码会重新散列?

我在 Java SE 8 上使用 WildFly 8.2 作为我的 Java EE 7 容器 运行。(RestEasy 和 Hibernate)

任何框架都可以调用 setMethod,也许当您从数据库中获取或当您将值转换为 JSON。

我会在 class 之外进行,否则您将需要创建其他方法来加密密码。

问题 1:您的密码似乎由 JSON 序列化程序进行了一次哈希处理,然后由持久层进行了哈希处理,因为哈希处理是在 setter 中实现的。

问题 2:关于 GET 操作,当您从数据库中检索数据时调用 setter 并且返回的实体是 Persistent 和 "dirty"(因为密码值已更改)所以, 在事务结束时 entitymanager 将所有脏对象刷新到数据库。

理想情况下,uaiHebert 已经建议将散列移出 setter 方法。