我目前正在构建JavaScript SPA,并且一直在研究如何保护它。当前有一个通过AJAX与之完全交互的RESTful API。我们也有与该API交互的移动客户端,当前它仅支持基于SSL的HTTP BASIC身份验证。 JavaScript应用程序还将专门通过SSL进行通信,但是BASIC Auth不会削减它,因为这将涉及在客户端上存储密码(或其密码的派生产品)。最后,SPA应用程序将是纯JavaScript和HTML,与RESTful API放在同一服务器上,但没有任何服务器端框架。

目标:


没有用于javascript客户端的服务器端框架(它只是另一个客户端)。
出于典型原因(可伸缩性,容错,简化的部署等),保持RESTful API的无状态性
任何状态应该由客户维护。就此问题而言,这意味着登录凭据。
客户端维护的登录状态必须是安全的,并且可以抵抗会话劫持和类似攻击。

我要提出的内容与是基于我对OAuth和类似方案(亚马逊等)的研究。


用户将使用SSL登录并通过HTTP POST登录。

服务器将按以下方式计算哈希:

HMAC(键,userId +“:” + ipAddress +“:” + userAgent +“:” + todaysDateInMilliseconds)

此令牌将返回给客户端,并随每个后续请求一起提供,以代替userName和密码。它很可能存储在localStorage或cookie中。

这样安全吗?选择userId,ipAddress,todaysDateInMilleseconds的动机是创建一个仅对今天有效的令牌,但不需要为每个请求查找数据库,并且可以安全地存储在客户端上。我不相信该密钥不会被妥协,因此包含IP地址以防止会话劫持。

让我包括StackExchange相关文章中的以下链接,因为我认为它解决了我要解决的许多问题:REST和无状态会话ID

在收到最初的反馈后,我决定仅使用IP地址的前两个八位字节来更好地处理代理后面的客户端和移动客户端。它仍然不是完美的,但是它需要权衡一些额外的安全性。

评论

仅供参考,我们最终基本上实现了上述确切解决方案,除了包括IP地址(这会导致移动设备出现问题)。

感谢您发布和更新。很好的线程。因此,您想避免会话以避免DB读/写,对吗?我正在做类似的事情,您在此主题上的经验非常宝贵。我问自己所有这些问题。

我正在尝试做类似的事情-您的HTML和JS是否最终在没有任何身份验证的情况下公开了,只有API是安全的?

#1 楼

令牌提供的服务是服务器将以某种方式将令牌识别为其自己的令牌之一。服务器如何验证基于HMAC的令牌?通过使用其秘密的HAMC密钥和HMAC进行操作的数据进行重新计算。如果希望通过用户ID,密码,IP和日期来计算令牌,则服务器必须知道所有这些信息。但是,您不希望服务器存储密码,并且客户端不会随每个请求将其发送回去。那么,您的系统如何工作?

基本概念是合理的:


用户以您认为合适的任何方式“登录”。
登录后,服务器会发送一个cookie值,并随每个后续请求一起发送回去(这就是cookie的作用)。
cookie包含用户ID,发布日期和值。 m = HMAC(K,userID ||日期|| IP)。
服务器收到请求时,它将验证cookie:userID和date来自cookie本身,源IP从Web服务器获取。层,服务器可以重新计算值m以检查它是否与存储在cookie中的值匹配。

如果服务器有一些(临时),则可以用随机会话ID替换整个cookie。储存空间。确实,服务器可以记住从随机会话ID到用户特定信息(例如其名称和IP地址)的映射。旧的会话ID可以自动过期,因此存储空间不会无限期增长。上面描述的cookie只是减轻客户端自身存储负担的一种方法。

注意:使用IP地址可能意味着一些实际问题。一些客户端位于代理之后,甚至是负载平衡的代理,因此客户端IP地址不仅可能被“隐藏”(从服务器,您看到的是代理地址,而不是客户端的地址),而且您获得的服务器端IP地址也可以不规则地移动(如果来自客户端的两个连续请求已通过代理服务器场中的不同代理)。

评论


感谢您提供有关IP地址缺点的信息。您对避免会话劫持的其他方式有建议吗?我可以使用用户代理之类的东西,但是根据我的理解,这些很容易被欺骗。我还根据您关于包括密码的明显观点更新了原始帖子。

–琼·温菲尔德
2012年9月1日22:13在

@JonWingfield:通过HTTPS发送的“安全” cookie大概是“安全”的-如果有人可以不当地访问该cookie的副本,那么您几乎无能为力,无论是从Javascript还是从服务器,但已弃用的旧cookie除外。

–托马斯·波宁(Thomas Pornin)
2012年9月1日22:19在

想提及有关HttpOnly cookie的信息以进一步保护它(owasp.org/index.php/HttpOnly)。 HttpOnly是Set-Cookie HTTP响应标头中包含的附加标志。在生成cookie时使用HttpOnly标志有助于减轻客户端脚本访问受保护cookie的风险(如果浏览器支持的话)。

–杰伊·库马尔(Jay Kumar)
14年3月14日在6:54

JWT是上述令牌概念的实现吗? API请求中的此类JWT令牌将使服务器1.验证其是否已发布令牌。 2.根据其有效负载确定用户。 3.发行持续特定时间段的令牌。谢谢。

–阿克谢·拉瓦特
15年5月1日在8:57



#2 楼

有一个更简单的解决方案:

在整个站点范围内使用SSL,然后使用框架的标准会话跟踪。

这就是您要做的全部。

更详细地,用户最初通过提供用户名和密码来登录;它被发布到服务器,服务器可以检查其有效性。如果身份验证成功,则服务器代码会在会话状态中设置一个标志,以记住用户已成功进行身份验证并记住用户的用户名。所有后续请求都将在同一会话上进行,因此您可以轻松地对其进行身份验证并允许它们继续。

(更多细节:每次收到请求时,您都要检查会话状态以查看是否用户已成功通过身份验证并被授权执行此操作。如果是,则允许请求并执行该操作;如果否,则将用户重定向到登录页面或显示其他错误消息。)

请注意,这符合您的所有要求。它不需要对每个请求进行数据库查找。它与RESTful API兼容。它与单页应用程序兼容。您不需要编写任何花哨的代码:您只需使用框架对会话的现有支持(通常,它使用具有唯一会话ID的会话cookie,以及一些在该会话ID关联的服务器端存储状态的机制) 。

作为在整个站点范围内使用SSL的一部分,您应该在会话ID cookie上设置安全标志,以防止它被窃听(这将确保它永远不会通过HTTP发送)。您还应该启用HSTS,以告知浏览器始终在您的站点上使用SSL。在此站点上搜索有关如何在整个站点上部署SSL的更多信息。

您不应依赖客户端的IP地址为静态。例如,如果客户端是移动的并且从一个无线网络移动到另一个无线网络,则它可以改变。因此,最好避免使用客户端的IP地址。

评论


Web应用程序没有框架。有一个用于RESTful API的框架(OpenRasta),但是JavaScript应用程序只是从同一服务器提供的简单的旧HTML和JS,以避免XSS问题。目标是不具有会话概念,但仍为Web客户端提供一定程度的安全性。也许我试图做的只是不可能的,我需要将某些东西持久化到数据库中,但是如果可能的话,我试图避免这种情况。

–琼·温菲尔德
2012年9月2日在21:23

@JonWingfield,我说的是服务器端Web应用程序框架(不是客户端的东西)。如今,几乎所有不错的Web应用程序框架都将为会话管理提供支持,并且几乎每个Web应用程序都是使用Web应用程序框架构建的。

– D.W.
2012年9月2日23:07

“目标是没有会议的概念”-我不知道为什么这是您的目标。这似乎是一个不寻常的目标,而不是您在问题中提出的目标。 (这似乎将机制与最终目标混淆了:将手段与最终目标混淆了。会话只是一种机制,只是达到目的的手段。您认为会话不兼容的最终要求是什么?)

– D.W.
2012年9月2日23:09



好的,因此在保持用户登录的意义上,我想您可以将其归类为会话。但是,Web应用程序中会话的一般概念通常与请求中的服务器端状态相关联,出于许多原因,我希望避免这种情况。客户端应保持请求之间的状态。关于框架,此Web应用程序没有服务器端框架。这只是Web服务器提供的纯HTML文件。所有逻辑都是使用各种JS框架(JQuery,Backbone等)在客户端进行的。

–琼·温菲尔德
2012年9月3日,0:30

@JonWingfield,好。我认为您需要对问题进行大的修改,因为那会大大改变事情!这是一个可解决的问题,但是无服务器端状态要求使其与您当前发布的问题完全不同。您仍然需要服务器端代码(例如,检查身份验证),因此仅纯HTML文件是不够的-但是在某些情况下可以在没有服务器端会话状态的情况下执行此操作。一旦您编辑了问题以反映实际需求,我将发布一个新答案。

– D.W.
2012年9月3日,0:37



#3 楼

在HTML5 Web App中使用OAuth2查看此帖子。 @jandersen答案很好地说明了在单页应用程序中使用资源所有者密码凭据流的情况。无论如何,此应用的首选流程应为“隐式”授权。实际上,@ jandersen在引用的帖子上的答复是关于调整资源所有者的密码凭据以使其类似于“隐式”授予。