Hibernate Encryption of Database Completely Transparent to Application

前端 未结 7 1015
春和景丽
春和景丽 2021-02-03 12:59

I\'m working on a Grails 1.0.4 project that has to be released in less than 2 weeks, and the customer just came up with a requirement that all data in the database should be enc

7条回答
  •  情深已故
    2021-02-03 13:48

    Well it has been a long time since I've asked the question. In the meantime, thanks for all the answers. They were great when dealing with the original idea of encrypting the entire database, but the requirement changed to only encrypting sensitive user info, like name and address. So the solution was something like the code down below.

    We've implemented an Encrypter which reads the encryption method from the record ( so there can be different encryption per record) and use it to connect transient duplicate fields to the ones encrypted in the database. The added bonus/drawbacks are:

    • The data is also encrypted in memory, so every access to the method getFirstName descrypts the data (I guess there is a way to cache decrypted data, but I dont need it in this case)
    • Encrypted fields cannot be used with default grails/hibernate methods for search through database, we've made custom methods in services that get data, encrypt it and then use the encrypted data in the where clause of a query. It's easy when using User.withCriteria

      class User {

      byte[] encryptedFirstName
      byte[] encryptedLastName
      byte[] encryptedAddress
      
      Date dateCreated // automatically set date/time when created
      Date lastUpdated // automatically set date/time when last updated
      
      EncryptionMethod encryptionMethod = ConfigurationHolder.config.encryption.method
      
      def encrypter = Util.encrypter
      
      static transients = [ 
      'firstName', 
      'lastName', 
      'address',
      'encrypter'
      ]
      
      static final Integer BLOB_SIZE = 1024
      
      static constraints = {
      
          encryptedFirstName maxSize: BLOB_SIZE, nullable: false
          encryptedLastName maxSize: BLOB_SIZE, nullable: false
      
          encryptedAddress maxSize: BLOB_SIZE, nullable: true
      
          encryptionMethod nullable: false
      
      } // constraints
      
      String getFirstName(){
          decrypt('encryptedFirstName')
      }
      
      void setFirstName(String item){     
          encrypt('encryptedFirstName',item)
      }
      
      String getLastName(){
          decrypt('encryptedLastName')
      }
      
      void setLastName(String item){
          encrypt('encryptedLastName',item)       
      }
      
      String getAddress(){
          decrypt('encryptedAddress')
      }
      
      void setAddress(String item){
          encrypt('encryptedAddress',item)        
      }
      
      byte[] encrypt(String name, String value) {
      
          if( null == value ) {
              log.debug "null string to encrypt for '$name', returning null"
              this.@"$name" = null
              return
          }
      
          def bytes = value.getBytes(encrypter.ENCODING_CHARSET)
          def method = getEncryptionMethod()
      
      
          byte[] res 
      
          try {
              res = encrypter.encrypt( bytes, method )            
          } catch(e) {
              log.warn "Problem encrypting '$name' data: '$string'", e
          }
      
          log.trace "Encrypting '$name' with '$method' -> '${res?.size()}' bytes"
      
          this.@"$name" = res
      
      }
      
      String decrypt(String name) {
      
          if(null == this.@"$name") {
              log.debug "null bytes to decrypt for '$name', returning null"
              return null
          }
      
          def res 
          def method = getEncryptionMethod()
      
          try {
              res = new String(encrypter.decrypt(this.@"$name", method), encrypter.ENCODING_CHARSET )
          } catch(e) {
              log.error "Problem decrypting '$name'", e
          }
      
          log.trace "Decrypting '$name' with '$method' -> '${res?.size()}' bytes"
      
          return res
      }
      

      }

提交回复
热议问题