【问题标题】:AngularJS SPA and RestfulAPI Server SecurityAngularJS SPA 和 RestfulAPI 服务器安全
【发布时间】:2014-02-27 16:48:08
【问题描述】:

快速背景:

与 REstful API 服务器对话的完整 Javascript SPA AngularJS 客户端。我正在尝试为 API 服务器制定最佳身份验证。客户端将具有角色,我不担心用户是否可以看到他们不允许的客户端区域,因为服务器应该是气密的。

身份验证流程:

  • 用户发布用户名和密码,比如说 /api/authenticate
  • 如果用户生成 api 令牌(字段的 sha 哈希或 md5)和其他一些元数据确定角色以在 1) 回复中传回。
  • 令牌存储在会话 cookie 中(无 exp,仅 http,ssl)
  • 身份验证后的每个请求都获取 cookie 中的令牌并验证这是用户。
  • 服务器上的 SSL 用户。

问题:

  • 这是保护服务器的最佳方式吗?
  • 我是否需要担心使用 SSL 的重放攻击?如果是最好的管理方法?
  • 我试图想办法用 AngularJS 实现 HMAC 安全性,但我无法在 javascript 客户端上存储私钥。
  • 我最初使用 http 身份验证方法,但每次请求都发送用户名和密码似乎很奇怪。

任何建议或示例将不胜感激。

【问题讨论】:

    标签: javascript angularjs authentication cookies ssl


    【解决方案1】:

    我目前正在使用 angularjs+node 作为 REST API 处理类似的情况,使用 HMAC 进行身份验证。

    不过,我正在处理这个问题,所以我的曲调随时可能改变。这就是我所拥有的。任何愿意为此戳洞的人,我也欢迎:

    1. 用户通过 https 进行身份验证、用户名和密码

    2. 服务器(在我的例子中是 node.js+express)向经过身份验证的用户发送回一个临时通用私钥。该密钥是用户用于签署 HMAC 客户端的密钥,并存储在浏览器的 LocalStorage 中,而不是 cookie(因为我们不希望它在每个请求中来回传输)。

      • 密钥存储在 nodejs 内存中,每六个小时重新生成一次,记录最后生成的密钥。密钥更改后的 10 秒,服务器实际上生成了两个 HMAC;一把新钥匙,一把旧钥匙。这样,在密钥更改时发出的请求仍然有效。如果密钥发生变化,服务器会将新的密钥发送回客户端,以便它可以在 LocalStorage 中刷新它。密钥是使用 node-uuid 生成的 UUID 的 SHA256,使用加密进行哈希处理。输入此内容后,我意识到这可能无法很好地扩展,但无论如何...

    3. 然后将密钥存储在浏览器上的 LocalStorage 中(如果在您尝试登录之前不支持 LocalStorage,应用程序实际上会吐出一个 your-browser-is-too-old 页面)。

    4. 然后所有超出初始身份验证的请求都发送三个自定义标头:

      • Auth-Signatureusername+time+request.body 的 HMAC(在我的情况下,request.body 是请求变量的 JSON.stringify()'d 表示)使用本地存储的密钥签名
      • Auth-Usernameusername
      • X-Microtime:客户端生成其 HMAC 时的 unix 时间戳

    5. 服务器然后检查X-Microtime 标头,如果X-Microtimenow 之间的间隔大于10 秒,则将请求作为潜在的重放攻击丢弃并返回401。

    6. 然后服务器使用与客户端相同的序列生成自己的HMAC,Auth-Username+X-Microtime+req.body,使用节点内存中的6小时私钥。

    7. 如果 HMAC 相同,则信任请求,否则,请信任 401。如果我们需要处理 API 上特定于用户的任何内容,我们有 Auth-Username 标头。

    显然,所有这些通信都是通过 HTTPS 进行的。

    编辑:

    必须在每次成功请求后将密钥返回给客户端,以使客户端使用动态密钥保持最新状态。这是有问题的,因为它的作用与 cookie 基本相同。

    您可以将密钥设为静态且永不更改,但这似乎不太安全,因为密钥永远不会过期。您还可以为每个用户分配一个密钥,该密钥在登录时返回给客户端,但是无论如何您仍然必须对每个请求进行用户查找,此时还不如只使用基本身份验证。

    编辑#2

    所以,在我自己做了一些测试之后,我决定为我的 REST API 使用后端代理,但仍然使用 HMAC。

    1. Angular 连接到同域后端,后端从上面运行 HMAC 过程,私钥存储在这个代理上。将它放在同一个域上可以让我们阻止 cors。

    2. 认证成功后,angular 会获得一个标志,我们将登录状态存储在 LocalStorage 中。没有密钥,但是可以识别用户并且可以公开的东西。对我来说,这个存储值的存在决定了用户是否登录。当他们注销或我们决定使他们的“会话”无效时,我们会删除 localStorage。

    3. 从 Angular 到同一域代理的后续调用包含用户标头。代理检查用户标头(只能由我们设置,因为我们已阻止跨站点访问),如果未设置则返回 401,否则只是将请求转发到 API,但 HMAC 会像上面那样。 API 将响应传回代理,从而传回 angular。

    这使我们能够将私有位排除在前端之外,同时仍然允许我们构建一个 API,该 API 可以快速进行身份验证,而无需对每个请求进行数据库调用,并且保持无状态。它还允许我们的 API 服务于其他接口,如原生移动应用程序。移动应用只需将私钥与私钥捆绑在一起,并为它们的每个请求运行 HMAC 序列。

    【讨论】:

    • 当你发回通用私钥时,你是否也发回了一个可以识别用户的公钥?
    • 不,这里我只使用在对服务器的每个请求中设置的 Auth-Username 标头。对我来说,因为这是 SSL,所以使用公钥和纯文本用户名没有区别。在我的书中,它们是同义词。但我也对那里的启蒙持开放态度。
    • 为了澄清该评论,当用户登录时,我们将他们的用户名存储在 User 对象中,然后用于构建 XHR 请求的 Auth-Username 标头
    • @MattE,我已经用一些新信息更新了我的答案。我不确定这是否是使用堆栈溢出的正确方法,但感谢您的倾听。
    • 1) 如果我是合法用户,进行身份验证,获取密钥,然后欺骗他人的用户名以继续生成 HMAC 请求怎么办? 2) 如果我对您的移动应用进行逆向工程以获取私钥怎么办?
    猜你喜欢
    • 2015-10-06
    • 2015-04-18
    • 2012-05-11
    • 1970-01-01
    • 2012-03-31
    • 2017-05-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多