使用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.pswp.cn/news/371132.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/371132.shtml
英文地址,請注明出處:http://en.pswp.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…