使用JPA侦听器的数据库加密

最近,我不得不将数据库加密添加到几个字段中,并且发现了很多不好的建议。

建筑问题

最大的问题是建筑。 如果持久性管理器悄悄地处理您的加密,那么根据定义,您的体系结构将在持久性和安全性设计之间要求紧密而不必要的绑定。 您不能触摸一个而不接触另一个。

这似乎是不可避免的,但是有一个受人尊敬的想法,那就是最好的架构是您拥有独立的应用程序开发人员和安全开发人员团队的架构。 应用程序开发人员不能草率,但总的来说,他们唯一的重点是功能完成。 安全开发人员负责设计和实现安全性。 唯一考虑这两个方面的地方是建筑和顶层设计。

过去这不是很实用,但是面向方面的编程(AOP)和类似的概念已经改变了这一点。 现在,在服务层和持久层之间注入一个拦截器是完全合理的,这样就可以悄悄地丢弃未授权调用方查看的值。 10个项目的列表可能会减少到7个,或者更新可能会引发异常,而不是修改只读值。 持久保存集合时要复杂一些,但是一般方法应该很明确。

这里的关键是,应用程序开发人员无需查看安全代码。 所有这些都可以通过在部署时通过配置文件添加的AOP注入来处理。 更重要的是,它可以随时更改,而无需修改应用程序本身。 (您可能需要执行一个更新过程,该过程将更改数据库中的值。)

拦截器甚至可以阻止对未记录方法的调用-不用担心流氓程序员。

在实践中,许多站点将有几个开发人员都戴上帽子,而不是拥有专门的安全团队。 只要他们能够牢记自己的职责,这不是问题。

在JPA或Hibernate字段中进行透明加密绝对比在POJO中放入加密/解密代码更好,但是它仍然在安全性和持久性层之间强加了不必要的绑定。 它还存在严重的安全问题。

安全问题

每当您处理加密时,都会遇到一个关键问题–可以将此对象写入磁盘吗? 最明显的威胁是序列化,例如,通过钝化数据以释放内存或将其迁移到其他服务器的应用服务器。

实际上,这意味着您的密钥和纯文本内容必须标记为“ transient”(对于序列化引擎)和“ @Transient”(对于JPA或Hibernate)。 如果您真的很偏执,您甚至会覆盖隐式序列化方法writeObject,因此可以绝对保证这些字段永远不会写入磁盘。

这是可行的……但是它使透明的加密/解密大为失败,因为该代码的全部目的是使这些字段看起来就像另一个字段。 您必须维护两个字段-持久加密值和瞬态未加密值-并具有某种使它们保持同步的方法。 无需在您的pojo中添加任何密码即可完成所有操作。

一个更微妙的问题是,如果攻击者可以通过使应用服务器崩溃而触发核心转储,则您的对象仍可能写入磁盘。 细心的站点管理员将禁用核心转储,但许多人忽略了它。 解决这个问题比较困难,但是如果AOP可以在需要解密值的方法周围立即解密/加密值,则有可能。 您的应用程序不关心解密在哪里发生,只要它在需要时就被解密即可。 这是应该留给安全团队的决策类型。

可以通过操作系统交换文件将对象写入磁盘的第三种方式,但这应该不是问题,因为交换文件现在通常已加密。

JPA实体侦听器

一个解决方案是JPA EntityListeners或相应的Hibernate类。 这些是侦听器类,可以提供在数据库对象创建,删除或修改之前或之后调用的方法。

样例代码

使用一些示例代码最容易看到这一点。 考虑一种情况,我们必须保留第三方站点的用户密码。 在这种情况下,我们必须使用加密,而不是哈希。

(注意:我怀疑这是Twitter第三方应用程序所需的实际信息–仅用于说明目的。)

实体

/*** Conventional POJO. Following other conventions the sensitive* information is written to a secondary table in addition to being* encrypted.*/
@Entity
@Table(name='twitter')
@SecondaryTable(name='twitter_pw', pkJoinColumns=@PrimaryKeyJoinColumn(name='twitter_id'))
@EntityListeners(TwitterUserPasswordListener.class)
public class TwitterUser {private Integer id;private String twitterUserprivate String encryptedPassword;transient private String password;@Id@GeneratedValue(strategy = GenerationType.IDENTITY)public Integer getId() { return id; }@Column(name = 'twitter_user')public String getTwitterUser() { return twitterUser; }@Column(name = 'twitter_pw', table = 'twitter_pw')@Lobpublic String getEncryptedPassword() { return encryptedPassword; }@Transientpublic String getPassword() { return password; }// similar definitions for setters....
}


DAO

/*** Conventional DAO to access login information.*/
@LocalBean
@Stateless
public class TwitterDao {@PersistenceContextprivate EntityManager em;/*** Read an object from the database.*/@TransactionAttribute(TransactionAttributeType.SUPPORTS)public TwitterUser getUserById(Integer id) {return em.find(TwitterUser.class, id);}/*** Create a new record in the database.*/@TransactionAttribute(TransactionAttributeType.REQUIRED)public saveTwitterUser(TwitterUser user) {em.persist(user);}/*** Update an existing record in the database.** Note: this method uses JPA semantics. The Hibernate* saveOrUpdate() method uses slightly different semantics* but the required changes are straightforward.*/@TransactionAttribute(TransactionAttributeType.REQUIRED)public updateTwitterUser(TwitterUser user) {TwitterUser tw = em.merge(user);// we need to make one change from the standard method -// during a 'merge' the old data read from the database// will result in the decrypted value overwriting the new// plaintext value - changes won't be persisted! This isn't// a problem when the object is eventually evicted from// the JPA/Hibernate cache so we're fine as long as we// explicitly copy any fields that are hit by the listener.tw.setPassword(user.getPassword());return tw;}


EntityListener

为了在持久层和安全层之间保持清晰的隔离,侦听器除了调用处理加密的服务外什么也不做。 它完全不了解加密细节。

public class TwitterUserPasswordListener {@Injectprivate EncryptorBean encryptor;/*** Decrypt password after loading.*/@PostLoad@PostUpdatepublic void decryptPassword(Object pc) {if (!(pc instanceof TwitterUser)) {return;}TwitterUser user = (TwitterUser) pc;user.setPassword(null);if (user.getEncryptedPassword() != null) {user.setPassword(encryptor.decryptString(user.getEncryptedPassword());}}/*** Decrypt password before persisting*/@PrePersist@PreUpdatepublic void encryptPassword(Object pc) {if (!(pc instanceof TwitterUser)) {return;}TwitterUser user = (TwitterUser) pc;user.setEncryptedPassword(null);if (user.getPassword() != null) {user.setEncryptedPassword(encryptor.encryptString(user.getPassword());}}
}


EncryptorBean

EncryptorBean处理加密,但不知道正在加密什么。 这是一个最小的实现–在实践中,我们可能会希望除了密文/明文之外还传递一个keyId。 这将使我们能够以最小的干扰安静地旋转加密密钥-这是通常的“简单加密”方法绝对不可能实现的。

此类使用OWASP / ESAPI进行加密,因为1)它应已由您的应用程序使用; 2)可移植格式允许其他应用程序使用我们的数据库,只要它们也使用OWASP / ESAPI库即可。

该实现仅涵盖字符串-健壮的解决方案应具有针对所有原始类型以及可能针对特定领域的类(例如信用卡)的方法。

import org.owasp.esapi.ESAPI;
import org.owasp.esapi.Encryptor;
import org.owasp.esapi.codecs.Base64;
import org.owasp.esapi.crypto.CipherText;
import org.owasp.esapi.crypto.PlainText;
import org.owasp.esapi.errors.EncryptionException;
import org.owasp.esapi.reference.crypto.JavaEncryptor;@Stateless
public class EncryptorBean {private static final String PBE_ALGORITHM = 'PBEWITHSHA256AND128BITAES-CBC-BC';private static final String ALGORITHM = 'AES';// hardcoded for demonstration use. In production you might get the// salt from the filesystem and the password from a appserver JNDI value.private static final String SALT = 'WR9bdtN3tMHg75PDK9PoIQ==';private static final char[] PASSWORD = 'password'.toCharArray();// the keyprivate transient SecretKey key;/*** Constructor creates secret key. In production we may want* to avoid keeping the secret key hanging around in memory for* very long.*/public EncryptorBean() {try {// create the PBE keyKeySpec spec = new PBEKeySpec(PASSWORD, Base64.decode(SALT), 1024);SecretKey skey = SecretKeyFactory.getInstance(PBE_ALGORITHM).generateSecret(spec);// recast key as straightforward AES without padding.key = new SecretKeySpec(skey.getEncoded(), ALGORITHM);} catch (SecurityException ex) {// handle appropriately...}}/*** Decrypt String*/public String decryptString(String ciphertext) {String plaintext = null;if (ciphertext != null) {try {Encryptor encryptor = JavaEncryptor.getInstance();CipherText ct = CipherText.from PortableSerializedBytes(Base64.decode(ciphertext));plaintext = encryptor.decrypt(key, ct).toString();} catch (EncryptionException e) {// handle exception. Perhaps set value to null?}}return plaintext;}/*** Encrypt String*/public String encryptString(String plaintext) {String ciphertext= null;if (plaintext!= null) {try {Encryptor encryptor = JavaEncryptor.getInstance();CipherText ct = encryptor.encrypt(key, new PlaintText(plaintext));ciphertext = Base64.encodeBytes(ct.asPortableSerializedByteArray());} catch (EncryptionException e) {// handle exception. Perhaps set value to null?}}return ciphertext;}
}


最后的想法

没有理由为什么未加密字段和加密字段之间必须具有一对一的关系。 将相关字段捆绑为一个值是完全合理的-实际上,最好单独加密每个字段。 这些值可以用CSV,XML,JSON甚至属性文件表示。

参考: Invariant Properties博客中的JCG合作伙伴 Bear Giles 使用JPA侦听器进行数据库加密 。

翻译自: https://www.javacodegeeks.com/2012/11/database-encryption-using-jpa-listeners.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/371132.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Java是先难后易吗_在解决问题的时候,是先难后易还是先易后难?

有家长问,孩子一旦听到不同声音,就沮丧,一旦有难的事情,就逃避,怎么办?回答这个问题之前,我们问一个问题“你给孩子玩穿纽扣游戏,是一开始给孩子玩容易穿的纽扣好呢?还是…

在vue中安装使用vux

最近因为的工作的原因在弄vue,从后端弄到前端之前一直用js,现在第一次接触vue感觉还挺有意思的,就是自己太菜了,这个脑子呀。。。。不太够用。。。。。页面设计用了一个叫vux的东西,vux可以提供一些组件,用…

form表单 获取与赋值

form表单中使用频繁的组件: 文本框、单选框、多选框、下拉框、文本域form通过getValues()获取表单中所有name的值 通过setValues({key:values})给对应的name值进行赋值,其中key对应的name值 在给单选框和多选框赋值时,有几个疑惑的地方:  …

Zabbix全方位告警接入-电话/微信/短信都支持

http://www.cnblogs.com/baidu-gaojing/p/5128035.html 百度告警平台地址: http://gaojing.baidu.com 联系我们: 邮箱:gaojingbaidu.com 电话:13924600771 QQ群:183806029 对于使用zabbix的用户,要接入百度…

Spring MVC定制用户登录注销实现示例

这篇文章描述了如何实现对Spring MVC Web应用程序的自定义用户访问(登录注销)。 作为前提,建议读者阅读这篇文章 ,其中介绍了一些Spring Security概念。 该代码示例可从Spring-MVC-Login-Logout目录中的Github获得。 它从带有注释…

HTML5与CSS3权威指南笔记案例1

第1章 <!DOCTYPE html> <meta charset "UTF-8"> <title> Search </title> <form> <p><label>Search&#xff1a;<input name"search" autofocus></label> </p> </form> <!DOCTYPE&…

java循环的概念_Java数据结构之循环队列简单定义与用法示例

本文实例讲述了Java数据结构之循环队列简单定义与用法。分享给大家供大家参考&#xff0c;具体如下&#xff1a;一、概述&#xff1a;1、原理&#xff1a;与普通队列的区别在于循环队列添加数据时&#xff0c;如果其有效数据end maxSize - 1(最大空间)的话&#xff0c;end指针…

Unrecognized option: -jrockit

weblogic报错&#xff1a; starting weblogic with Java version: Unrecognized option: -jrockit Error: Could not create the Java Virtual Machine. Error: A fatal exception has occurred. Program will exit. Starting WLS with line: /data/jdk1.8.0_45/bin/java -jroc…

51nod 1105 第K大的数

基准时间限制&#xff1a;1 秒 空间限制&#xff1a;131072 KB 分值: 40 难度&#xff1a;4级算法题 数组A和数组B&#xff0c;里面都有n个整数。数组C共有n^2个整数&#xff0c;分别是A[0] * B[0],A[0] * B[1] ......A[1] * B[0],A[1] * B[1]......A[n - 1] * B[n - 1]&#x…

在Tomcat上设置和使用Apache Solr

前一阵子花了一点时间来玩Solr&#xff0c;但立即被我们可以在一些更大的数据集上获得的性能所震撼。 这是我的一些初始设置和配置学习信息&#xff0c;也许可以帮助某人启动它并更快地运行。 首先在Windows上进行设置。 下载并解压缩Apache Tomcat和Solr&#xff0c;然后将其复…

sass变量

sass变量用法 1、sass变量必须以$符开头&#xff0c;后面紧跟着变量名 2、变量值和变量名之间就需要使用冒号(:)分隔开&#xff08;就像CSS属性设置一样&#xff09; 3、如果值后面加上!default则表示默认值 默认变量 sass的默认变量&#xff1a;仅需要在值后面加上!defaul…

西安4年java多少时间_西安学习java一般要多久

线程小n行的任务/任务执的数单个量为间隔执行池大所需时间时间&#xff0c;西安学习的配置&#xff0c;西安学习行定行池务的务执c配在执注置任方法时任上标&#xff0c;下解行调问题务的方度任有以异步决办采用法&#xff1a;上述式执。比如、般要多本名(套接套接5套t地地节点…

js 递归函数的使用及常用函数

1.递归函数的使用&#xff1a; 公园里有一堆桃子&#xff0c;猴子每天吃掉一半&#xff0c;挑出一个坏的扔掉&#xff0c;第6天的时候发现还剩1个桃子&#xff0c;问原来有多少个桃子 var peache;function peaches(n) { if (n 6) { peache 1; } else { …

redis分布式锁-SETNX实现

转自&#xff1a;https://my.oschina.net/u/1995545/blog/366381 Redis有一系列的命令&#xff0c;特点是以NX结尾&#xff0c;NX是Not eXists的缩写&#xff0c;如SETNX命令就应该理解为&#xff1a;SET if Not eXists。这系列的命令非常有用&#xff0c;这里讲使用SETNX来实现…

sql java驱动程序_Microsoft SQL Server JDBC 驱动程序支持矩阵

本页包含 Microsoft SQL Server JDBC 驱动程序的支持矩阵和支持生命周期策略。Microsoft JDBC 驱动程序支持生命周期矩阵和策略Microsoft 支持生命周期 (MSL) 策略提供了与 Microsoft 产品的支持生命周期有关的可预测透明信息。 自驱动程序发布之日起&#xff0c;JDBC 驱动程序…

使用直接内存时可以更快

总览 使用直接内存不能保证提高性能。 考虑到它增加了复杂性&#xff0c;除非有充分的理由使用它&#xff0c;否则应避免使用它。 塞尔吉奥奥利维拉&#xff08;Sergio Oliveira Jr&#xff09;的这篇出色文章表明&#xff0c;这不仅仅是使用直接内存来提高性能的问题&#x…

POJ 3977 折半枚举

链接&#xff1a; http://poj.org/problem?id3977 题意&#xff1a; 给你n个数&#xff0c;n最大35&#xff0c;让你从中选几个数&#xff0c;不能选0个&#xff0c;使它们和的绝对值最小 如果有一样的&#xff0c;取个数最小的 题解&#xff1a; np难题&#xff0c;但是因为…

java踩坑记

1.String 相等 稍微有点经验的程序员都会用equals比较而不是用 &#xff0c;但用equals就真的安全了吗&#xff0c;看下面的代码 user.getName().equals("xiaoming"); 有经验的老司机很快就能看到问题&#xff0c;如果user.getName()为null,就会抛出空指针异常&#…

java taken_java-是否有正确的方法在slf4j中传递参数?

第三变种是最好的。实际上&#xff0c;第一种情况是通过StringBuilder进行的字符串连接。第二和第三种情况相同。他们需要将整数值装箱到Integer(或其他Object)&#xff0c;然后创建一个数组来打包它们。在我的机器上进行的简单测试表明&#xff0c;如果不执行日志记录&#xf…

html常用小知识

请求重定向&#xff1a;加载页面之后&#xff0c;除了用js做重定向之外&#xff0c;我们还可以直接用<meta>标签做重定向。 1 <meta http-equiv"refresh" content"5;urlhttp://www.baidu.com" /> 5秒后跳转 超链接&#xff1a;在当前的iframe…