如何加密用户的信息?数据服务器端而不破坏体验?
许多用户(包括我自己)希望他们在网络服务上所做的一切都被加密,从而确保安全。也就是说,他们不会让网络服务中的任何人能够查看他们的:帖子、信息、任务等...
这也是对一项很酷的服务的讨论中的主要抱怨:http://news.ycombinator.com/item?id=1549115
由于此数据需要可恢复,需要某种双向加密。但是,除非您在每次请求时都提示用户输入加密密钥,否则该密钥将需要存储在服务器上,并且基本上失去了加密数据的意义。
有什么方法可以安全地加密用户数据而不降低用户体验(在每个请求上都要求一些密钥)?
--更新--
从@Borealid的回答中,我关注了两种可能性:质询-响应协议,其中没有数据(包括密码)以“明文”形式发送,以及非质询-响应协议,其中数据(包括密码)以“明文”形式发送(尽管通过 HTTPS)。
挑战响应协议(特别是 SRP:http://srp.stanford.edu/)
它的实现需要依赖于完全 AJAX 站点或使用 Web 存储。这样浏览器就可以在加密期间保留质询响应数据以及不同“页面”之间的加密密钥。 (我假设身份验证完成后,我会将加密的加密密钥发回给他们,他们将在客户端解密该密钥以获得真正的加密密钥。)
问题是我要么:
- 完全 AJAX,但我不这样做不喜欢,因为我喜欢 url,并且不会让用户专门生活在单个 url 上,或者
- 我必须将数据加密密钥存储在基于 http://dev.w3.org/html5/webstorage/ 即使在浏览器关闭后也会持续存在,并且可能是一个安全漏洞
此外, SRP 接受多个请求 ( http://srp.stanford.edu/design.html ) ,服务器端需要有一些持久性。这只是另一个困难。
传统上
如果我可以以明文方式传输密码和数据(尽管通过 HTTPS),则不会出现上述客户端问题。
注册时,我将为用户生成一个随机的唯一加密密钥,并使用他们的密码和随机盐对其进行加密。
在数据库中,我将存储用户的密码哈希和盐(通过 bcrypt)、加密的加密密钥、加密密钥盐和加密 iv。
身份验证后,我还需要使用他们的密码来解密加密密钥,以便他们可以查看和输入新数据。我仅临时存储此加密密钥,并在他们明确“注销”时将其删除。
这种方法的问题是(就像 @Borealid 指出的那样)邪恶的系统管理员仍然可以在您登录时查看您的数据。
我也不确定如何在用户登录时存储加密密钥。如果他们在同样的数据存储,被盗的数据库将泄露被盗时登录的所有数据。
是否有更好的内存数据存储来存储这些加密密钥(以及 SRP 身份验证期间的质询数据)? Redis 适合做这件事吗?
Many users – myself included – would like the security of having everything they do on a web service encrypted. That is, they don't won't any one at the web service to be able to look at their: posts, info, tasks, etc...
This is also major complaint in this discussion of an otherwise cool service: http://news.ycombinator.com/item?id=1549115
Since this data needs to be recoverable, some sort of two-way encryption is required. But unless you're prompting the user for the encryption key on every request, this key will need to be stored on the server, and the point of encrypting the data is basically lost.
What is a way to securely encrypt user data without degrading the user experience (asking for some key on every request)?
-- UPDATE --
From @Borealid's answer, I've focused on two possibilities: challenge-response protocols, where no data (password included) is sent in the "clear", and non-challenge-response protocols, where data (password included) is sent in the "clear" (although over HTTPS).
Challenge-response protocols (specifically SRP: http://srp.stanford.edu/)
It seems that its implementation would need to rely on either a fully AJAX site or using web storage. This is so the browser can persist the challenge-response data during encryption and also the encryption key between different "pages". (I'm assuming after authentication is completed I would send them back the encrypted encryption key, which they would decrypt client-side to obtain the real encryption key.)
The problem is that I'm either:
- fully AJAX, which I don't like because I love urls and don't won't a user to live exclusively on a single url, or
- I have to store data encryption keys in web storage, which based on http://dev.w3.org/html5/webstorage/ will persist even after the browser is closed and could be a security vulnerability
In addition, as SRP takes more than one request ( http://srp.stanford.edu/design.html ), there needs to be some persistence on the server-side. This is just another difficulty.
Traditionally
If I'm ok transmitting passwords and data in the clear (although over HTTPS), then the client-side issues above are not present.
On registration, I'll generate a random unique encryption key for the user, and encrypt it using their password and a random salt.
In the database, I'll store the user's password hash and salt (through bcrypt), encrypted encryption key, encryption key salt, and encryption iv.
After an authentication, I'll also need to use their password to decrypt the encryption key so that they may view and enter new data. I store this encryption key only temporarily and delete it when they explicitly "log out".
The problems with this approach is that (like @Borealid points out) evil sysadmins can still look at your data when you are logged in.
I'm also not sure how to store the encryption keys when users are logged in. If they are in the same data store, a stolen database would reveal all data of those who were logged in at the time of theft.
Is there a better in-memory data store for storing these encryption keys (and challenge data during an SRP authentication)? Is this something Redis would be good for?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
如果需要在用户出错时恢复数据,则不能使用 cookie 之类的东西(它可能会被删除)。正如您所指出的,服务器端密钥实际上并不能保护用户免受恶意系统管理员的攻击。他们只帮助解决诸如数据库离线被盗之类的问题。
但是,如果您正在运行普通的 Web 服务,那么您已经非常幸运了 - 为了保持唯一性和非短暂性,用户必须登录。这意味着他们要经过一些身份验证步骤来证明他们的身份。为了证明自己的身份,大多数网站都使用传递的凭据(密码)。
只要您不使用质询-响应身份验证协议(大多数网站不使用这种协议),您就可以使用从服务器端机密和用户密码的组合派生的加密密钥。仅当用户经过身份验证时才存储加密密钥。
如果您这样做,用户在使用服务(或窃取密码)时仍然容易受到系统管理员的窥视。您可能想更进一步。要升级,请根本不要将密码发送到服务器。相反,请使用质询响应协议对您的网站进行身份验证,并在上传任何内容之前通过 JavaScript 使用用户密码的派生加密数据。
这是万无一失的安全性:如果您尝试窃取用户的密码,用户可以看到您在做什么,因为盗窃代码就在您发送给他们的页面中。您的网络服务绝不会接触其未加密的数据。这也不妨碍正常的用户体验。用户只需像平常一样输入密码即可登录。
Lacie的存储云服务就是使用这种方法。做得非常好。
注意:当我说“使用 foo 加密”时,我的真正意思是“使用 foo 加密安全对称密钥,然后使用随机盐进行加密”。了解你的密码学。我只讲秘诀,不讲方法论。
If the data need to be recoverable in the event of user error, you can't use something like a cookie (which could get deleted). And as you point out, server-side keys don't actually secure the user against malicious sysadmins; they only help with things like databases stolen offline.
However, if you're running a normal web service, you've already gotten pretty lucky - the user, in order to be unique and non-ephemeral, must be logged in. This means they go through some authentication step which proves their identity. In order to prove their identity, most web sites use a passed credential (a password).
So long as you don't use a challenge-response authentication protocol, which most web sites don't, you can use an encryption key derived from a combination of a server-side secret and the user's password. Store the encryption key only while the user is authenticated.
If you do this, the users are still vulnerable to sysadmins peeking while they're using the service (or stealing their passwords). You might want to go a step further. To go one up, don't send the password to the server at all. Instead, use a challenge-response protocol for authentication to your website, and encrypt the data with a derivative of the user's password via JavaScript before uploading anything.
This is foolproof security: if you try to steal the user's password, the user can see what you're doing because the code for the theft is right there in the page you sent them. Your web service never touches their data unencrypted. This is also no hindrance to the normal user experience. The user just enters their password to log in, as per normal.
This method is what is used by Lacie's storage cloud service. It's very well done.
Note: when I say "use foo to encrypt", I really mean "use foo to encrypt a secure symmetric key which is then used with a random salt to encrypt". Know your cryptography. I'm only talking about the secret, not the methodology.
这些其他解决方案都不会维护所请求的功能集——特别是想要保留用户体验。如果您查看链接中引用的网站,他们会通过电子邮件向您发送每晚过去的日记条目。你不会通过上面的 JavaScript 欺骗来实现这一点,因为你没有可以依赖的浏览器。所以基本上这一切都会导致你的用户体验下降。
您想要的,或者更准确地说,您将在这个领域找到的最佳解决方案,并不是上面提到的 wuala 所做的那样,而是像 hush.com 这样的东西。用户数据的处理始终需要在客户端完成——这通常是通过完整的客户端 Java(如 Facebook 照片上传器等)完成的,但现在 HTML/JavaScript 可能可以帮助您实现这一点。 JavaScript 加密非常差,所以你最好忽略它。
好的,现在您已经有了运行日记条目加密服务的客户端 Java。下一个功能是每晚通过电子邮件将过去的日记条目发送给用户。嗯,显然你不会在未加密的电子邮件中得到这些信息。这是您需要以某种方式改变用户体验的地方。最简单的解决方案不是通过电子邮件发送条目,而是在 Java 应用程序中提供一个日记条目浏览器,一旦他们访问网站,就会根据每日电子邮件中的链接提醒他们一些旧条目。更复杂的解决方案是使用 JavaScript 加密将条目解密为电子邮件中内嵌的附件。这不是火箭科学,但其中涉及相当多的技巧。这是 IronPort 等多种 Web 电子邮件加密服务使用的通用路径。您可以访问 http://www.ironport.com/securedemo/ 获取演示电子邮件。
尽管我很想看到所有这些的正确加密版本,但我的最终评论是日记条目不是国家机密。考虑到可靠的隐私政策和良好的网站安全语义,我相信 99% 的用户都会感觉良好。要在真正的安全性下正确完成所有这些工作,将需要付出巨大的努力,并且至少需要进行一些设计/UE 更改。
None of those other solutions are going to maintain the feature set requested -- which specifically wants to preserve the user experience. If you look at the site referenced in the link, they email you a nightly past journal entry. You're not going to get that with JavaScript trickery per above because you don't have the browser to depend on. So basically this is all leading you down a path to a degraded user experience.
What you would want, or more precisely the best solution you're going to find in this space, is not so much what wuala does per above, but rather something like hush.com. The handling of user data needs to be done on the client side at all times -- this is generally accomplished via full client-side Java (like the Facebook photo uploader, etc), but HTML/JavaScript might get you there these days. JavaScript encryption is pretty poor, so you may be better off ignoring it.
OK, so now you've got client-side Java running a Journal entry encryption service. The next feature was to email past journal entries to users every night. Well, you're not going to get that in an unencrypted email obviously. This is where you're going to need to change the user experience one way or the other. The simplest solution is not to email the entry and instead to provide for instance a journal entry browser in the Java app that reminds them of some old entry once they get to the website based on a link in the daily email. A much more complex solution would be to use JavaScript encryption to decrypt the entry as an attachment inline in the email. This isn't rocket science but there is a fairly huge amount of trickery involved. This is the general path used by several web email encryption services such as IronPort. You can get a demo email by going to http://www.ironport.com/securedemo/.
As much as I'd love to see a properly encrypted version of all this, my final comment would be that journal entries are not state secrets. Given a solid privacy policy and good site security semantics, I'm sure 99% of your users will feel just fine about things. Doing all this right with true security will take an enormous amount of effort per above and at least some design/UE changes.
您应该查看 MIT 项目 CryptDB,它支持使用 SQL 子集查询加密数据库。 (请参阅福布斯文章,mefi 线程,或维基百科上的同态加密)
有Tahoe-LAFS 云存储项目,可以想象,在遥远的未来有一天,它可以被用于完全匿名的社交网络应用程序。
You should look into the MIT project CryptDB which supports querying an encrypted database using a subset of SQL. (see the forbes article, mefi thread, or Homomorphic encryption on wikipedia)
There is the Tahoe-LAFS project for cloud storage too, which conceivably could be leveraged into a fully anonymous social networking application, one day in the distant future.
如果您想在服务器上执行计算,而服务器甚至无法看到数据,您可能有兴趣了解 完全同态加密。完全同态加密方案允许您对加密数据执行任意计算,即使您无法解密它。然而,这仍然是一个研究课题。
目前,我猜你最好的选择是加密所有帖子并为每个帖子分配无意义的(例如连续的)ID。有关如何使用当今技术加密服务器端数据的更深入讨论,请查找。
If you want to perform computations on a server without even the server being able to see the data, you may be interested in knowing about fully homomorphic encryption. A fully homomorphic encryption scheme lets you perform arbitrary computations on encrypted data, even if you can't decrypt it. However, this is still a topic of research.
For now, I guess your best bet would be to encrypt all posts and assign meaningless (e.g. sequential) IDs to each one. For a more in-depth discussion of how to encrypt server-side data with today's technology, look up.