【问题标题】:Hibernate - Store a column as encrypted, and decrypt only on runtimeHibernate - 将列存储为加密,并仅在运行时解密
【发布时间】:2013-06-04 13:13:17
【问题描述】:

当从支持休眠的 web 应用程序传递时,我有一个需要加密的数据库列。 webapp 在 tomcat 6、Hibernate 4 和 Mysql 上作为后备存储。

但问题是加密/解密此字段的密码仅在程序运行时可用。最初我希望使用 AES_ENCRYPT/DECRYPT 方法,这里概述得很好:

DataBase encryption in Hibernate

这里:

http://docs.jboss.org/hibernate/core/3.6/reference/en-US/html/mapping.html#mapping-column-read-and-write

(虽然这里指的是hibernate的3.6版本,但我相信4.0应该也是一样的)。

但是,由于它使用以下符号:

@Column(columnDefinition= "LONGBLOB", name="encryptedBody") 
@ColumnTransformer(
  read="AES_DECRYPT(encryptedBody, 'password')", 
  write="AES_ENCRYPT(?, 'password')")
public byte[]  getEncryptedBody() {
    return encryptedBody;
}

public void setEncryptedBody(byte[]  encryptedBody) {
    this.encryptedBody = encryptedBody;
}

这要求在注解本身中指定密码,并且不能是变量。

有没有办法以这种方式通过hibernate使用数据库方法,但将密码作为变量?有更好的方法吗?

【问题讨论】:

标签: java mysql hibernate security encryption


【解决方案1】:

目前没有办法参数化读/写片段的片段。它们更多地是作为通用解决方案。我们已经讨论了在 Hibernate 中添加对 @Encrypted 的支持,这大致就像您建议的那样。 @Encrypted 将提供更大的灵活性,例如 in-vm 加密与 in-db 加密、参数化等。

JPA 2.1 还有一个你可以使用的特性,称为属性转换器。然而,他们只能应用 in-vm 加密。

【讨论】:

    【解决方案2】:

    您可以使用 Hibernate @Type 属性,根据您的要求,您可以自定义注释并应用在字段之上。喜欢:

      public class PhoneNumberType implements UserType {
      @Override
      public int[] sqlTypes() {
    return new int[]{Types.INTEGER, Types.INTEGER, Types.INTEGER};
      }
    
      @Override
      public Class returnedClass() {
          return PhoneNumber.class;
      }
    
      // other methods
      }   
    

    一、空SafeGet方法:

      @Override
      public Object nullSafeGet(ResultSet rs, String[] names, 
      SharedSessionContractImplementor session, Object owner) throws HibernateException,                   
        SQLException {
      int countryCode = rs.getInt(names[0]);
       if (rs.wasNull())
          return null;
       int cityCode = rs.getInt(names[1]);
      int number = rs.getInt(names[2]);
      PhoneNumber employeeNumber = new PhoneNumber(countryCode, cityCode, number);
       return employeeNumber;
       }
    

    接下来,null SafeSet 方法:

      @Override
       public void nullSafeSet(PreparedStatement st, Object value, 
        int index, SharedSessionContractImplementor session) 
         throws HibernateException, SQLException {
          if (Objects.isNull(value)) {
          st.setNull(index, Types.INTEGER);
          } else {
          PhoneNumber employeeNumber = (PhoneNumber) value;
          st.setInt(index,employeeNumber.getCountryCode());
          st.setInt(index+1,employeeNumber.getCityCode());
          st.setInt(index+2,employeeNumber.getNumber());
        }
       }
    

    最后,我们可以在我们的 OfficeEmployee 实体类中声明我们自定义的 PhoneNumberType:

      @Entity
      @Table(name = "OfficeEmployee")
       public class OfficeEmployee {
    
        @Columns(columns = { @Column(name = "country_code"), 
        @Column(name = "city_code"), @Column(name = "number") })
        @Type(type = "com.baeldung.hibernate.customtypes.PhoneNumberType")
         private PhoneNumber employeeNumber;
    
       // other fields and methods
        }
    

    这可能会解决您的问题,这将适用于所有数据库。如果您想了解更多信息,请参考 :: https://www.baeldung.com/hibernate-custom-types
    同样,您必须进行 UTF-8 编码/解码和 ISO-8859-1 解码/编码

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-07-07
      • 1970-01-01
      • 1970-01-01
      • 2017-02-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-06-05
      相关资源
      最近更新 更多