Ruby on rails Rails 4加密外键

Ruby on rails Rails 4加密外键,ruby-on-rails,activerecord,encryption,ruby-on-rails-4,attr-encrypted,Ruby On Rails,Activerecord,Encryption,Ruby On Rails 4,Attr Encrypted,我正在构建一个需要符合HIPAA标准的应用程序,这意味着我不能允许在数据库中自由查看某些连接(患者和他们的建议) 这些表是通过我的应用程序中的患者推荐表连接的,在我通过添加加密之前,该表运行良好。为了减少加密和解密的工作量(以及相关的开销),我希望能够简单地加密patients\u recommendations表中的patient\u id。但是,当将数据类型更改为string并将列名更改为encrypted\u patient\u id时,当我尝试重新设置数据库种子时,应用程序会出现以下错误

我正在构建一个需要符合HIPAA标准的应用程序,这意味着我不能允许在数据库中自由查看某些连接(患者和他们的建议)

这些表是通过我的应用程序中的
患者推荐表连接的,在我通过添加加密之前,该表运行良好。为了减少加密和解密的工作量(以及相关的开销),我希望能够简单地加密
patients\u recommendations
表中的
patient\u id
。但是,当将数据类型更改为
string
并将列名更改为
encrypted\u patient\u id
时,当我尝试重新设置数据库种子时,应用程序会出现以下错误:

无法写入未知属性“患者id”

我假设这是因为联接直接查找列,而不是通过模型(有意义,使用模型可能会更慢)。有什么方法可以让Rails通过模型(其中
attr\u encrypted
添加了必要的助手方法)

更新:

为了找到解决方法,我尝试在模型中添加before_save,如下所示:

before_save :encrypt_patient_id

...

private

def encrypt_patient_id
  self.encrypted_patient_id = PatientRecommendation.encrypt(:patient_id, self.patient_id)
  self.patient_id = nil
end

但是,这也不起作用,导致相同的
未知属性错误。这两种解决方案都适用于我(虽然第一种解决了主要问题),你知道为什么通过关联创建时不调用save之前的

不要在
encrypt\u patient\u id
中将
patient\u id
设置为
nil
,因为它不存在,问题可能会消失

此外,使用
nil
false
结束回调将停止回调链,并在方法末尾放置一个明确的
true

计划B,重新考虑你的选择

还有更多的选择—从数据库级透明加密(正式加密磁盘上的数据),到用于存储某些表空间的加密文件系统,再到对列中的数据进行完全加密

加密连接列听起来像是一条通往不快乐之路,原因有很多,从报告问题到需要连接时的性能问题,这可能非常严重

您当前在种子上遇到的问题看起来是这可能是一条糟糕的道路上的第一次碰撞(在这种情况下,activerecord似乎对如何处理您的关联感到困惑,它尝试在初始化和中断时设置
患者id

加密受限数据的开销可能没有您想象的那么高,不确定HIPAA的情况如何,但对于PCI,并不鼓励您在屏幕上呈现受保护的数据,因此加密只会产生很小的开销,因为这种情况发生得相对较少(业务需要了解等)

此外,内存可能被认为是“不在静止和不在传输中”,理论上,您可以在有限的时间段内缓存一些清晰的值,从而节省解密开销

基本上,加密数据可能并没有那个么糟糕,在数据库中加密密钥可能比你们想象的更糟糕

我建议我们直接谈谈,我正在做PCI DSS合规性方面的工作,我对这个话题很感兴趣

选项:主键/外键的单向散列

patientRecomation
将有
patient\u id
的散列-称之为
patient\u hash
patient
将能够从其
id
生成相同的
patient\u散列-但我建议将
patient\u hash
存储在两个表中,对于
患者
而言,它将是join的主键;对于
患者推荐
而言,它将是join的外键

因此,您可以用这些术语定义rails关系,rails将不再对您的关系方案感到困惑

has_many :patient_recommendations, primary_key: :patient_hash, foreign_key: :patient_hash
其结果是在加密方面更加健壮,并且数据库易于处理

如果您坚持不在
patient
中存储
patient\u散列
,您可以使用一个简单的SQL语句来实现这种关系—虽然不太方便,但可行—在以下伪SQL行中:

加入生成散列(patient.id)=患者建议。患者散列

例如,Oracle有一个使函数索引(想想
create index generate_hash(patient.id)
)的选项,因此根据您对数据库的选择,这种方法可能非常有效

然而,即使使用这些方法,玩连接键也会使你的生活复杂很多



稍后我将通过附加选项对此文章进行扩展

您可能应该将PII数据和PHI数据存储在单独的数据库中。加密PII数据(包括与提供商或提供商位置的任何关联),然后散列所有PHI数据以使其更容易。只要两者之间没有直接关联,就可以接受不加密PHI数据,因为它是匿名的

单向散列能代替双向加密吗?您可以使用
SHA512(密钥+患者id)
作为外键,这样做相对简单。大字符会产生昂贵的索引,尽管双向加密如果有固定的IV,通常经不起密码审查,乍一看似乎只有固定的IV加密才适合用作外键,但散列仍然有效。。您是否可以链接HIPAA规范中为您规定的部分?在HIPAA下,您需要在传输和休息期间保护个人健康信息(PHI)和个人身份信息(PII)。由于我的应用程序将允许重复使用和编辑推荐,因此会对这些字段中的所有数据进行加密(这样你就无法说出所有推荐信息)