13

我正在开发一个使用大量 AJAX 与服务器通信的网页。反过来,服务器具有广泛的 REST/JSON API,公开了 Web 客户端调用的不同操作。

该网站可供匿名用户和经过身份验证的用户使用。如您所料,由经过身份验证的用户发出的 Web 服务调用需要身份验证,因此可以防止未经授权的用户或应用程序访问。

但是,该网站有许多不需要身份验证的功能,其中一些使用匿名 Web 服务。我用来防止外人调用此 Web 服务的唯一方法是使用CSRF 令牌。我知道,CSRF 令牌在这方面不是很有用......有一些时间,即使他们使用 CSRF 令牌,您也可以弄清楚如何使用 Web 服务。

当然,您可以使用 CAPTCHA 来防止应用程序或机器人自动使用您的 Web 服务。但是,任何人都可以使用它。

另一方面,在客户端和服务器之间共享密钥是没有用的。这是因为任何局外人都可以从网页源代码中读取它。

我想让这些 Web 服务尽可能难以被任何 3rd 方应用程序调用。除了使用 CSRF 代币,你还会做什么?这听起来有点愚蠢,但是嘿,也许这很愚蠢,我只是在浪费时间。

注意:鉴于此应用程序使用浏览器而不是“可执行文件”作为客户端,这个问题与讨论无关。我不能在服务器和客户端之间使用秘密(至少据我所知)

4

5 回答 5

2

This is interesting. Below is a crazy suggestion. Remember, your question is also equally crazy.

Your website, once opened through a browser, should generate a long polling connection (Comet programing). This will create a unique session between the browser and the server. When ur JS is making the ajax call, send some token (unique token every time) to the server through the long polling thread. Let the AJAX also send the same token. At the server, get the AJAX token and check whether you have a similar token in you long polling session. If yes, fulfill the request. Any coder can break this. But, it won't be easy. Chances are the freeboarders won't even see these second piece of comet code. You can implement the comet code in such a way it is not easy to detect or understand. When they call ur service, send a 'Service Unavailable' message. They will be confused. Also make the comet code https.

You can also check how long that long polling thread is open. If the session was just opened and you get a ajax call right away, you can assume it is a 3rd party call. It depends on ur website flow. If ur Ajax call happens after 1 second of page load, you can check for that pattern on server side.

Anyone coding for your public api, will have 1 to 2 secret checks that they wouldn't even know and even if they know, they might be discouraged by all the extra coding they have to do.

于 2013-02-11T18:12:45.087 回答
2

我会采取一些步骤。

  • 在网站上强制使用 https。自动将任何传入的 http 请求重定向到 https 请求(RequireHttps 属性很方便)
  • 每个页面都需要(安全地,因此是 https)向客户端发送一次性使用令牌,以用于该页面。客户端上运行的脚本可以将其保存在页面内存中。任何返回的请求都会发送一个散列和加盐的响应,以及随机数盐。服务器可以使用保存的令牌+盐和哈希重复这些步骤以确认请求。(很像上面的 explunit 的回答)(值得注意的是,来自客户端的安全请求没有从用户帐户进行身份验证,而只是与整个页面一起发送的令牌。)
  • 一次性的定义可以是会话或页面加载,具体取决于您的安全性与便利性偏好。令牌应该很长并且相当快地过期以挫败攻击者。

SSL + Hash(token + nonce) 应该足以满足您的需求。

于 2013-02-11T08:03:39.600 回答
1

这只是一个基于 RSA 概念的想法,并将欺诈检测放在您的系统上。来自授权用户的风险很小,但他们也可以尝试匿名调用您的网络服务。

对于未经授权的用户:对于每个网络服务调用,使用 RSA 生成一个令牌,该令牌会在一段时间后更改(可以配置为 30 分钟)。这种方式代码的预测被最小化。到目前为止,我还没有听说过 RSA 冲突。将此令牌发送回用户以进行浏览器会话。为了进一步的安全性,我们可能想附加一个带有 RSA 令牌的会话 ID。由于会话 ID 是唯一的,新的匿名呼叫将需要新的会话 ID。

可以使用审核机制来跟踪呼叫。每个网络服务也可以有不同的 RSA 设置。欺诈检测算法如何工作本身就是一个挑战。

对于授权用户:应使用 Header 块通过其 IP 地址跟踪每个用户。可以应用 RSA 令牌原则。

解决方案非常模糊,但值得考虑。

于 2013-02-07T21:02:26.270 回答
1

也许您可以使用计数器来跟踪对话。只有服务器和客户端才能预测对话中的下一次迭代。这样,我认为,您可以防止第三方应用程序冒充某人(尽管只是一个想法)。

一开始,他们在某个迭代(i=0例如)开始交谈。

  • 每次客户端请求某些东西时,计数器都会在服务器端和客户端(i=i+some_number)中增加一些数字。

  • 而且,在几分钟没有沟通之后,他们都知道他们必须重置计数器(i=0)。

于 2013-02-06T22:29:11.363 回答
1

您可能会遇到比链接问题中描述的更简单的问题,因为您不需要将二进制文件分发给用户。即使您的应用程序是开源的,HMAC/签名密钥(在该答案的“请求签名”部分)也可以由环境/配置设置控制。

总结一下:

  1. 密钥实际上并未在客户端和服务器之间发送。相反,它用于签署请求
  2. 确保请求包含一些唯一/随机元素(您的 CSRF 密钥可能就足够了),以便对相同 API 数据的两个请求不相同。
  3. 使用密钥对请求进行签名并将签名附加到请求中。您链接到一个 PHP 问题,但不清楚您使用的是什么语言。在 .Net 中,我会使用HMAC类,例如HMACSHA256
  4. 在 API 服务器端使用相同的 HMAC 对象来验证请求是否使用相同的密钥进行签名。
于 2012-10-12T15:21:48.453 回答