我需要建议开发敏感数据传输/存储/加密系统

介绍

我目前正在开展一个项目,该项目涉及从VisualFox Pro数据库中每日提取数据(药房记录),并将其中的一些上传到WordPress网站,药房的客户可以安全地查看它。 我想在我的软件的一般方法方面提出一些建议 – 我能够对其进行编码,但需要知道我是否采用了正确的方法。 我正在编写PC软件(在C#/ .NET 4.5中)和PHP WordPress插件。

问题1:加密

我计划使用的加密数据服务器端的当前进程基于本文 。 总而言之,它主张用存储在服务器上的自己的公钥非对称地加密每个单独的用户数据。 然后,用于解密该数据的私钥本身使用用户的密码对称加密并存储。 这样,即使数据库被盗,也需要破坏用户的密码哈希,即使这样,也需要为每个用户的数据重复该过程。

作者本人指出的唯一弱点,以及我的问题的主要观点是,当用户登录时,解密的密钥存储在会话存储中。 文章建议处理它的方式是仅限制用户登录的时间。我认为更好的解决方案是将该密钥存储在短期安全cookie中(当然整个过程通过HTTPS进行) 。 这样,如果攻击者可以控制用户的计算机并且可以读取他们的cookie,他们可能只需键入密码并登录,无需窃取数据库,而即使攻击者获得对服务器的访问权限,他们也无法解密HTTPS流量(或者可以吗?我不确定。)

我应该使用安全cookie或会话存储来临时存储解密密钥吗?

问题2:存储

我还想解决的第二件事是如何存储数据 – 这更像是一个效率问题。 由于每个用户都有自己的加密密钥,因此每个用户的记录必须单独存储。 我不知道是否应该为每个用户存储一个“块”数据,包含带有表示记录的对象数组的加密JSON,或者我是否应该将记录存储在具有实际数据结构的表中,并加密每个数据字段与钥匙分开。

我倾向于将数据存储为一个块 – 在我看来,一次解密一个大块数据比使用数千个单独的字段更有效。 此外,即使我以正确的结构存储数据,我仍然无法使用MySQL的WHERE,ORDERBY等,因为数据都是BLOB。

我应该将数据存储为每个用户的大块,还是分成不同的字段?

问题3:转移

我从DBF文件中提取数据,并基本上形成一个“差异”,从而比较当前提取的数据和最后一天的数据,并只上传已更改的用户的块(我不仅可以上传记录,因为我可能最终将用户的数据存储在块中)。 我还为已被删除的用户添加了“删除”说明。 这是因为数据库中有数十万条记录,总计超过200mb,并且每天都会增加大小。

我目前的计划是将所有这些数据写入JSON文件,gzip并将其上传到服务器。 我的问题是,如何在确保数据安全的同时做到这一点? 当然,上传将通过HTTPS进行,我有一个API密码,只允许授权上传,但我主要担心的是如果服务器受到损害,如何保护数据。 我不希望攻击者只是在处理服务器时从服务器获取JSON文件。 我的一个想法是让服务器向我发送用户的公钥列表,并在上传之前在我的软件中执行加密。 在我看来,这是保护数据的唯一方法。 我可以加密整个JSON文件,可能使用API​​密钥或特殊密码,但如果攻击者可以在服务器上处理解密文件时只是访问解密文件,那就没有实际意义了。 这是一个好的解决方案吗?

我应该在客户端单独加密数据,还是有办法将其安全地传输到服务器并在那里加密?

在此先感谢任何答案,我很想听到之前处理过这类问题的人。

注意: 交叉发布给程序员 ,请参阅注释。

问题1

加密

碰巧的是,我正在开发一个类似的系统来加密Wordpress评论中的个人详细信息(电子邮件,IP),这样如果服务器遭到入侵,数据库中的敏感数据仍然会被加密。 在会话中存储一个不对称的解密密钥对我来说是不合适的,因为这可能会让服务器上的密钥让攻击者在攻击它的同时抓住它。

因此,通过SSL证书的cookie是更好的方法 – 至少攻击者必须等待用户登录才能窃取他们的密钥。 与此同时,某种类型的tripwire系统将是一个好主意,因此一旦受到攻击,用户就无法登录系统(从而为等待攻击者提供密钥)。

正如您所说,加密记录(根据我的设计使用一个密钥,或者根据您的设计使用许多密钥)意味着搜索记录成为您必须远离数据库服务器的过程,这反过来意味着它将显着慢点。

您可以通过在速度和安全性之间进行权衡来减轻这种影响:某些字段可以被模糊化然后以未加密的方式存储。 例如,如果您想搜索患者所在的位置,从他们的地址获取他们的(纬度,长度),对其进行随机移位(在任一方向的两个轴上最多3英里),然后存储生成的坐标用纯文本。 然后可以在没有解密的情况下完成与位置有关的近似计数查询。

减轻对客户端计算机的攻击

上面介绍了如何减轻对服务器的攻击,这是您最大的风险,因为您已将所有记录存储在那里。 正如您正确指出的那样,对客户端计算机的攻击也是一个问题,如果他们是公众成员,则可以认为他们的安全流程不存在。

在此基础上,您可以使用密码加强单个密码(完整地给出),客户端需要从密码中选择三个随机字母(即,特别是不完整地给出)。 这有两种方式优雅地防范键盘记录器:首先使用下拉菜单,这些菜单更难以窃听,即使用户使用键盘快捷键,他们也没有提供完整的短语。 在每次成功登录时,记录随机字母的索引(例如1,4和5),并且不再长时间询问。 显然,太多错误的答案会导致帐户被锁定,并需要通过电话或蜗牛邮件重置代码重新授权。

您可以使用的其他身份validation方法:每次输入正确的密码时向用户发送一个附加密码,或者(可能过于昂贵)根据网上银行使用身份validation设备。

存储很少/没有识别信息

另一个安全提示是尽可能少地存储个人信息。 如果你无法通过电子邮件立即重置密码,那么名字,地址,电话号码和电子邮件 – 所有个人识别数据 – 可能都是不必要的。 该个人信息可以单独存储在另一台服务器上的断开连接的数据库上,使用公共主键将它们链接在一起。 (事实上​​,如果用户希望重置他们的密码,您只需在他们的匿名用户记录上存储一个标志,并且药剂师可以在他们下次访问管理面板时在他们的防火墙机器上手动运行重置过程)。

问题2

您应该加密一个blob中的表格数据还是将其留在每列中? 我在我的应用程序中也看过这个。 对我来说,我将它存储在一个blob中,因为我的用例是搜索密集型的,并且每行有N个解密而不是一个使得决策变得容易。 也就是说,你可能更喜欢单独加密列的整洁,有人可能会说,如果腐败蔓延,将它们分开会让你有更好的机会让一些行存活下来。

如果你决定存储在一个blob中,我使用的格式与此类似(在非对称加密之前用换行分隔的行):

1.2 <-- version of this format, so I can add things in the future key1=value1 key2=value2 ... 

如果您有多个进程写入列,请确保在读取和写入之间锁定行,否则(如上所述)您可能会丢失一些数据。

正如你所说,如果这种格式更适合你,这同样可以是JSON。

问题3

我对这个问题的理解是:如果你不能自己解密用户记录,你如何复制到未加密的离线副本? 我想知道您是否可以放松一点安全约束,并在服务器上存储公共公钥,并保留使用公共密钥加密的更改的单独记录。 这将填充一个应该定期清空的表(通过在远程安全机器上运行同步例程); 因此,与获得未加密的整个数据库相比,更改表对攻击者的价值会很小。

当然,相应的私钥应该在药剂师的计算机上,再次从互联网上安全地防火墙。

这种设计的风险在于攻击者用他/她自己的一个替换服务器公钥,以便以后可以收集为他们实际加密的信息! 但是,只要您在服务器上安装了trip-wire,就可以合理地防范:如果触发了这一点,Web应用程序的动态部分将不会写任何新的更改(实际上不会起作用)在所有情况下)直到系统被扫描并确定是安全的。