HTML5离线身份验证

时间:2014-04-23 22:28:55

标签: javascript html5 security authentication encryption

我正在寻求有关如何最好地控制对主要使用的离线HTML5应用程序的访问权的建议/批评。

应用程序使用IndexedDB,本地和会话存储的组合来存储数据,以便可以脱机使用它。数据/页面通过HTTPS提供。

目的是最大程度地降低平板电脑/ PC丢失/被盗时数据被查看的风险。

目前,该应用程序使用Stanford Javascript Crypto库加密用户/密码,然后如果用户能够成功向服务器进行身份验证,则将其保存到本地存储。如果应用程序随后脱机,则用户必须对本地存储中的加密用户/密码进行“本地”身份验证。

此外,如果用户能够成功向服务器进行身份验证,则会将未加密的用户/密码存储在会话存储中。使用此方法是为了使应用程序可以定期尝试重新建立与服务器的联系并“无缝地”重新进行身份验证,而无需用户重新输入其凭据。

我知道有很多关于客户端加密错误的帖子/讨论,请参考http://www.matasano.com/articles/javascript-cryptography/http://rdist.root.org/2010/11/29/final-post-on-javascript-crypto/以及.nczonline.net / blog / 2010/04/13 /更多 - 安全客户端数据存储/ +其他。但是我不确定这些参数在这种情况下是如何适用的。

鉴于需要离线存储数据,我正在寻找对这种方法的批评。如果有更好的方法请详细说明。

由于

2 个答案:

答案 0 :(得分:3)

身份验证与安全存储

我将从一个重大的设计问题开始:您似乎处理问题,好像是关于身份验证,其中(可能是恶意的)用户需要向您的应用程序证明她确实是有效的用户。但实际上您遇到了存储问题,因为如果计算设备被盗,整个运行时环境(包含您的应用程序正在使用的所有敏感信息)都在攻击者的手中。在javascript应用程序的情况下,离线数据和代码的分析比仅使用二进制代码的情况更为舒适。

例如,如果我想要攻击您的应用程序,我首先会查看会话存储(cookies?只需使用浏览器界面查找它们),看看我是否可以在那里找到用户名和密码。如果不是,我会遵循用于解密本地存储中的密码的代码(可能使用javascript调试器)。您描述应用程序的方式似乎函数可以在没有用户提供的密钥的情况下解密它。也许我可以通过将if(authenticateUser())更改为if(true)来评论用户的本地身份验证。

所以你真正要做的就是用一个根本没有存储在客户端的密钥来加密所有敏感的本地数据。例如,每次访问您的应用程序时都要求用户提供解密密钥,使用该密钥解密本地存储的数据(并加密您存储的每个新数据),并且在一段时间不活动后将密钥丢弃。或者,您可以在每次访问应用程序时对服务器进行身份验证,并从那里检索解密密钥,并在一段时间不活动后将其丢弃。

此时,javascript环境的选择确实会妨碍您的原因,因为您无法强制运行时环境在您希望它消失时丢弃解密密钥。即使是C应用程序也很困难,因为你必须小心翼翼地将RAM交换到硬盘上。根据您的应用程序使用的信息的敏感程度,可能足以要求用户在完成后关闭浏览器并假设攻击者没有足够的动力在浏览器的交换RAM中查找密钥。 / p>

本地保存登录数据

由于它是您使用的最敏感信息,因此绝不应将用户登录信息存储在客户端上。而是对服务器进行一次身份验证,并从中检索身份验证令牌以供将来进行交互。这基本上与会话cookie相同,并且在一段时间后过期(如果它根本没有过期,则它与密码一样好)。

答案 1 :(得分:2)

我现在已经实现了一个解决方案,我将在下面介绍它以防其他人使用。我明白这不是一个答案'对我的问题,即不提供批评,但鉴于该应用程序必须工作'离线'除了无缝重新验证的要求之外,我无法看到@Perseids的答案是如何实现的,尽管我非常感谢对话(来自@SilverlightFox和@Perseids)。

如果有解决方案,则无需存储用户的凭据'离线'在满足我的问题中提出的要求的同时,我很想听到。


当应用程序在线时,应用程序必须能够对用户进行身份验证。并且'离线'。对于'在线'应用程序通常会采用会话令牌解决方案,即只有会话标识符将存储在客户端上(通常在cookie中),而不是用户的凭证。然而,用户的凭证必须存储在客户端上(可能有人会提出一个聪明的替代方案?)以便在应用程序离线时强制执行安全性,即允许用户在离线时进行身份验证并解密/加密IndexedDB数据。为了使应用程序更安全,用户的用户名和密码以加密形式存储。一些敏感的IndexedDB数据也以加密形式存储。因此,即使恶意用户使用应用程序的缓存实例获取计算机或平板电脑,他们也只能以加密形式查看用户名,密码和数据(前提是用户已注销或关闭其浏览器)。

不幸的是,此时似乎并没有任何标准的'保护HTML5离线应用程序的协议。几乎所有文献都警告不要在客户端上存储用户凭据或任何敏感数据。然而,这是一个悖论,因为此应用程序必须在脱机时工作,因此数据必须脱机存储。

此处实现的安全协议有两个密钥,但是一旦第一个密钥被破解,就很容易获得第二个密钥。在第一级中,用户自己的密码作为密钥加密用户的密码,并将其用户名反转为盐。还有第二个密钥“数据加密密钥”,它在成功验证服务器后从服务器返回。此密钥用于加密用户名和任何IndexedDB数据。这个数据加密密钥'使用用户密码进行加密。因此,如果攻击者能够解密用户的密码,那么他们就可以轻松地使用密码来解密数据加密密钥'然后使用解密的数据加密密钥'解密用户的用户名和任何加密的IndexedDB数据。只有加密形式的用户名,密码和数据才需要永久存储在客户端上,因为使用用户在登录屏幕中输入的用户名和密码,就可以解密任何持久数据。

但是,登录后,用户名和密码以未加密的形式存储在客户端的会话中,以便1)应用程序可以定期与服务器重新进行身份验证,这使得重新身份验证无缝是间歇连接和2)随时检索解密的数据加密密钥,以便能够查询/保存IndexedDB数据并在必要时对其进行解密/加密。如果1)没有要求,则只需要在会话中存储数据加密密钥。如果用户尚未注销或未关闭其浏览器,则这导致可视性,因为恶意用户将能够以其解密形式(使用调试工具)查看用户的密码和用户名。然而,这并不比传统的在线应用程序发生同样的事情,使用户能够更改其密码,尽管传统的在线应用程序通常会有会话超时,因此恶意用户只能在有限的时间内采取行动。此外,如果浏览器崩溃,通常它会让用户选择使用会话信息恢复以前的窗口/标签,因此应该正确关闭浏览器。

上面采用的协议几乎肯定不遵循最佳做法。例如盐不是随机的(用户名反转),很可能是短的,可以对字典攻击,可能适用于密码(密码的强度是服务器的功能),没有键拉伸例如PBKDF2。但是,我无法看到如何遵循最佳做法'并且在给予限制的情况下满足要求。有可能稍微改善散列,例如改进salt,可能是用户名和特定于站点的字符串的组合,但是即使这样也需要javascript中的逻辑可以被确定的攻击者理解。 Javascript可以被混淆,但这也只会使它变得更加困难,但并非不可能,任何能够破解加密密钥的人都不会发现Javascript的混淆是很大的障碍。也许有一些未来聪明的内在支持来自浏览器的显着改进将是可能的。