使用 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"
计算结果为:
MD5("Password") = "DC647EB65E6711E155375218212B3964"
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 方法。
我有一个用户 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"
计算结果为:
MD5("Password") = "DC647EB65E6711E155375218212B3964"
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 方法。