在阅读此答案之前,请先阅读Joachim的答案。他介绍了客户端漏洞背后的一般原因。现在,对于如何解决此问题的建议...
一种用于客户端-服务器通信的安全方案,而无需在每个请求上手动向服务器进行身份验证:
您仍然让服务器拥有最后发言权,服务器仍然必须验证客户端说的所有内容,但这是透明发生的。
假定使用HTTPS协议来防止中间人攻击(MITMA)。
客户端第一次与服务器握手,服务器使用非对称加密方案为客户端生成一个公共密钥,并保留一个私有密钥。客户端将服务器的“公钥”存储在本地存储中,并使用您不会在任何地方保存的安全密码进行加密。
客户端现在离线。客户端要执行受信任的操作。客户端输入他的密码并获取服务器的公共密钥。
基于其数据的知识,现在客户端进行操作,并在客户端加密每次与服务器的公钥进行操作的客户端。
当客户端在线时,客户端发送其客户端ID,并将客户端执行的所有操作发送到使用服务器的公钥加密的服务器。
服务器对动作进行解密,如果动作格式正确,它会相信动作起源于客户端。
注意:
您不能将客户端的密码存储在任何地方,否则攻击者将能够获取密钥并对其进行签名。该方案的安全性完全取决于服务器为客户端生成的密钥的完整性。要求密钥时,客户端仍需要通过服务器进行身份验证。
实际上,您仍然依靠服务器而不是客户端来确保安全性。客户端执行的每个操作都必须在服务器上进行验证。
可以在Web Worker中运行外部脚本。请记住,您现在拥有的每个 JSONP请求都是一个更大的安全问题。您需要不惜一切代价保护密钥。一旦丢失,攻击者就可以冒充用户。
这可以满足您执行“不对服务器执行ping操作”的要求。如果攻击者不知道密钥,就不能简单地使用伪造数据模仿HTTP请求。
约阿希姆的答案仍然是正确的。实际上,您仍然在服务器上执行所有身份验证。您在这里保存的唯一一件事是每次都需要使用服务器进行密码验证。现在,当您要提交或提取更新的数据时,只需要涉及服务器即可。我们在这里所做的只是在客户端保存一个受信任的密钥,然后让客户端重新验证它。
对于单页应用程序(例如,使用AngularJS),这是一种非常常见的方案。
我将服务器的公钥称为“ public”,因为在RSA之类的方案中这意味着什么,但实际上,它是方案中的敏感信息,应加以保护。
我不会将密码保留在内存中的任何位置。每当用户开始运行脱机代码时,我都会让用户提交“脱机”密码。
不要使用自己的加密技术 -使用Stanford's等已知库进行身份验证。
按原样接受此建议。在实际业务关键型应用程序中进行这种身份验证之前,请咨询安全专家。这是一个既痛苦又容易出错的严重问题。
这是至关重要的,没有其他的脚本访问该页面。这意味着您只允许Web Worker使用外部脚本。您不能相信用户输入密码时可能会截获密码的任何其他外部脚本。
如果不能完全确定并且不延迟其执行,请使用prompt
而不是内联密码字段(也就是说,不应将其保留到事件只能访问同步代码才能访问事件的地步)。并且实际上不要将密码存储在变量中-再次,这仅在您相信用户的计算机没有受到损害时才有效(尽管对于服务器验证也是如此)。
我想再次补充一点,我们仍然不信任客户。您不能单单信任客户,我想Joachim的答案就是如此。我们仅获得了不必在开始工作之前对服务器进行ping操作的便利。
相关资料: