54

我有一个与网络服务对话的移动应用程序(目前是 IOS 和很快的 Android)。没有登录,数据不是私人的。基本上,该应用程序发布一个标记(经度、纬度)并获取最近的 25 个标记以显示在地图上。

这是一个非常微不足道的应用程序,我无法想象有人会付出巨大的努力来滥用 Web 服务。但是,我可以看到有人在发布许多标记时很有趣。我最担心的是有人在运行一个推送许多请求的脚本(使用昂贵的带宽并对我的应用程序数据进行胡说八道)。

我慢慢得出结论,这并不安全。最好的答案是“不要这样做”。不要提供未经身份验证的 Web 服务。没有多少服务如此开放。Google 的 You Tube API 是开放的,但大多数都不是。不幸的是,我别无选择。因此,经过几天的研究,这是我的想法。请注意,我离安全专家还很远,我相信我的方法可以改进。但这可能会为您指明正确的方向。希望更有经验的人可以加入并纠正/改进这一点。我发现这篇文章和评论特别有用。

消息级安全

我将使用哈希加密来保护味精。客户端和 Web 服务都保留一个共享密钥的副本,该密钥用作盐以从 URL 和所有 POST 参数创建哈希。散列作为附加参数传递,并且在另一端重建和比较散列(使用共享密钥作为盐)。在您了解任何移动客户端代码都可以在几分钟内进行逆向工程之前,这非常好。在这一点上,这条防线完全没有用。

客户措施

客户端包括消息速率限制作为限制诚实用户发送的消息数量的措施。再一次,这对于越狱移动设备的攻击者来说毫无用处。

服务器端安全

因此,服务器端必须尽可能多地采取额外的安全措施,以独立于假设您的客户端(和共享机密)受到损害的情况。这是我所拥有的:

一个 msg arg 是用于限制重放攻击的 UTC 时间。这应该可以防止攻击者在服务器上重复触发相同的消息。

服务器通过 IP 进行速率限制。是的,IP 很容易被欺骗,并且代理切换是孩子们的游戏,但是当你拥有这么少的东西时,一切都会有所帮助。

当然,服务器严格验证所有参数,使用参数化查询并且不返回异常。

传输级安全

不幸的是,我相当有信心在没有注册过程的情况下颁发单个客户端 SSL 证书是不可能的。而且因为我使用的是 msg 哈希检查(而且我的数据不是私有的),所以我不完全确定 SSL 带来了什么。但是,我可能会使用 SSL(带有一个应用程序范围的证书),因为它增加了另一个级别的安全性,可以轻松且廉价地部署(尽管每个 msg 都会花费额外的连接时间)。

我的方法中的大洞

我被警告说,如果该应用程序变得流行,那么有人会破坏客户端上的共享秘密。仅仅因为他们可以而且他们可能会将其发布在互联网上。所以实际上这一切都归结为服务器端。不幸的是,我无法识别和阻止攻击者。这是我非常喜欢的。

最后的请求

经过几天的研究,这就是我所拥有的。但我想要更多。我将特别感谢任何加强服务器端的想法。所以,我把我所有的 SO 点都作为赏金。是的,先生,全97分!

4

8 回答 8

23

实际上,在您的特定情况下,由于它目前是仅限 iOS 的应用程序,因此有一个解决方案。

  1. 用户第一次下载并运行应用程序后,应用程序会访问/access_token/create一个提供 GUID 的 API,并通过 Apple 的推送通知将其中继回应用程序。

  2. 应用程序存储此 access_token,并在所有后续请求中使用它。您的实际 API 可以根据 access_token 进行速率限制。

基本上,您让 Apple 完成所有艰苦的工作,以确保初始请求来自实际的 iOS 设备。

将其扩展到桌面客户端是可能的,但在某种程度上破坏了用户体验。只需更改第 1 步以允许/access_token/create接受任意请求,如果请求不是来自 iOS 设备,则强制用户在向他们发出 access_token 之前验证他们的电子邮件地址/解决验证码等。

Android 设备(对它们不太熟悉)可能有类似的推送通知机制,在这种情况下您可以使用它,或者可能没有推送通知机制,在这种情况下,您可能会让您的 Android 用户受到上面列出的不便。

于 2012-08-22T19:30:59.830 回答
12

在谈到寻找垃圾邮件问题的全局解决方案时,我曾经听说过这个想法:强制您的客户执行一些耗时的计算。

准确地说:找到一些计算算法,可以在一眨眼之间计算出一些zx但是只给出一个y计算需要相当长的时间。我不能提供实际的算法,但我确信其中有很多符合这个标准。zx

现在整个过程应该如下所示:

  1. 根据第一个客户端请求生成一些session_idand 为此session_id一对xand y
  2. 为您的客户提供session_idx
  3. 客户端可以在收到数据后立即开始计算(在一些与用户交互无关的后台线程中)。
  4. 要请求标记,客户必须提供session_id并计算z.
  5. 您可以快速验证客户z是否正常,因为您已经拥有x并且y可以轻松完成。
  6. (选项 1)对于每个session_id商店,它被请求的频率/频率。在你怀疑它被滥用的那一刻——力量再生xy
  7. (选项 2)强制 newx并且y在每次连续请求时对session_id.

在 6 和 7 之间进行选择实际上是根据算法的复杂性与标记数据库的预期“公平”使用进行调整。如果您的估计是好的 - 邪恶的客户端永远不应该获得太多数据或使您的服务器过载。

希望能帮助到你。

于 2012-08-17T16:32:58.977 回答
6

在客户端,您实际上无能为力。您必须将整个应用程序(包括任何密钥或任何其他保护机制)提供给您的用户。如果恶意用户想要对您的 Web 服务进行恶作剧,他将不得不进行一些逆向工程才能访问您的 Web 服务。你可以让这变得更难,但无论你多么努力,你都无法阻止它。

我只是实现一些服务器端速率限制(每个 IP 地址),不再担心这个。这是一场你无法赢得的战斗。如果有人真的想伤害您的服务器,他可以在不了解您的 Web 服务协议的情况下直接对它进行 DDOS。

此外,在第一次连接时自动为每个用户生成唯一的密钥或证书根本没有帮助。在攻击者对您的协议进行逆向工程后,他知道如何处理所有这些并且不必遵守您的规则。每次遇到速率限制时,没有什么能阻止他从您的服务器请求新密钥。

Kuba Wyrostek 描述的方法可以工作 - 让客户端执行一些耗时的计算,您可以在允许处理请求之前快速检查。但这不会花费太长时间,否则您的用户会抱怨电池寿命缩短。此外,攻击者可能会使用更强大的桌面硬件而不是另一部 iPhone。

最后一点——你真的认为这是必要的吗?您不希望您的用户必须注册,因此您的数据或服务不能太重要。那么,对你的应用程序进行逆向工程并用请求淹没你的服务器会得到什么?

于 2012-08-19T20:06:34.200 回答
3

实际上,我一直在寻找实施其中一些想法的理由。到目前为止很好的问题和答案。

我同意@Kuba Wyrostek 关于将其视为垃圾邮件问题是解决方案的一部分。尤其是如果您的应用程序将包含文本消息(添加商店、服务或消息),您可能会发现向您的应用程序发送垃圾邮件的常见原因是宣传某些内容。这将导致我的第一个建议:

1) 将每条消息的有效性视为从 0% 到 100% valid 的百分比。在服务器端开发一个流程以使用启发式方法将消息标记为或多或少有效。这将允许您将一些附加方法(例如强制客户端计算复杂值)仅针对需要它的那些请求。您还可以更轻松地记录和查看可能的滥用行为(并且在针对滥用行为后更轻松地清除该滥用行为)。

但是,在垃圾邮件大战中,您的应用程序确实比电子邮件服务器具有强大的优势 - 您可以控制对话的双方。这种情况实际上让我想起了另外两个您可能会发现有用的相关情况:卫星付费电视“战争”和即时通讯克隆“战争”。(例如,参考 Jeff Atwoods 关于黑色星期天黑客的帖子)。以下是这些僵局中的一些想法,可能会帮助您在猫捉老鼠的游戏中领先一点:

2) 要求客户端发送额外的数据——尽可能多的关于请求的数据是有意义的。在 iOS 上,发送位置的准确度指标。在 Android 上,您实际上可以获得原始 GPS 数据,例如星历信息。然后,您可以(可能不是马上,而是稍后)开始检查这些数据的有效性。这迫使某人对请求进行逆向工程以更加努力地工作。例如,如果他们将 GPS 卫星发送到视野中,您可以根据公开数据进行检查以确认。

3) 将你的对手强加到移动设备上——正如@Sven 所说,你的攻击者可能使用台式电脑,这意味着“计算成本高”的请求可能变得微不足道。不要让他们这样做(或至少让他们更努力地工作)。例如,您可以让客户端计算一些数学函数(由服务器发送),然后根据手机型号查看它是否需要正确的毫秒数才能完成。或者使用来自服务器的数据执行小型 3D 渲染任务,这依赖于硬件裁剪行为。散列结果并将其发回。所有这些都在一个范围内——它是一个多任务操作系统。但这将有很大帮助。

4) 对它们进行动态处理- 发送需要在客户端上下文中计算的算法位。Apple 对要解释的远程代码感到有些好笑,但是像发送一些不呈现给用户的 javascript 之类的东西可能会起作用。该代码可能会提出各种难以预先预料的独特问题(屏幕分辨率、浏览器版本、WebKit 怪癖)。随着他们的追赶,您可以通过这些获得更多创意。

5) CAPTCHA - 如果您的启发式方法开始看到可疑数据,请强制他们进行身份验证。如果您有一个多语言应用程序,它可能就像将图片或 unicode 字符与另一个匹配一样简单。以您以后可以更新的方式渲染它。

无论如何 - 一些额外的想法。祝你好运!

于 2012-08-19T23:37:38.693 回答
2

在服务器端实现速率限制的最简单方法是仅使用 Web 服务器插件/模块。例如,如果您的服务在 apache 上运行,请安装并配置 mod_evasive。这将允许您根据 IP 地址、服务/URL 等进行速率限制。Mod Evasive 将比您自己实现的更有效。

如果您使用密钥,您需要有某种基于验证码的方式让客户在注册时获取密钥。您可以让它删除滥用用户的帐户。是的,当然一个参数是时间戳,它将在服务器端被验证为最近和过去。密钥将与时间戳一起加密整个有效负载,并作为附加参数添加。基于每个密钥存储请求的频率最终需要某种循环数据库,除非您只检查最后一个请求的新近度。

没有纯粹的客户端速率限制会产生任何影响。甚至从未见过您的客户端的人就可以在网络上发现您的 API。我怀疑共享秘密是否会长期有效。

您会发现许多不需要密码且仅受速率限制的 Web 服务……例如,twitter API 提供了许多速率受限的未经身份验证的 API 服务。

于 2012-08-21T04:39:23.133 回答
2

这是另一个“解决方案”:

  • 不要在这个问题上浪费时间。

因为:

  • 您不会向世界公开公共接口,因此您可以随时通过更新 Web 服务和更新您的应用程序来更改您的 Web 服务接口。
  • 该应用程序“非常琐碎”(正如您所说的那样),目前可能没有太多使用
  • 你现在可能有更好的事情要做,只是在浪费时间

如果存在可疑的性能或查询峰值,请使用耗时最少的解决方案:

  • 引入保存在您的应用程序中的密码 (clientid)(阻止 95% 的这些用户)如果其他程序员想要合法访问您的服务,此 clientid 以后可用于识别不同的客户端
  • 引入速率限制(如上所述)

这将在 99,99% 的情况下解决您的问题,您可以立即开始工作并编写很棒的新功能。

于 2012-08-23T08:12:07.827 回答
1

这很棘手,你不希望任何人篡改数据......所以你关心的不是完整性。而且由于您不维护任何客户列表……就不能担心真实性吗?

对于所有众所周知的 Web 服务攻击(如 DoS 或重放攻击),您可以获得可以阻止它们的防火墙。所以我认为你不需要太在意它们。

但是你不想发送纯文本数据,并想确保你的下载应用程序是推送数据的东西。

如果您查看您正在评估的方法:

安全密钥:据我了解,服务器和应用程序将共享相同的密钥,如果我正确,所有设备上的所有应用程序都将共享相同的密钥。当应用程序推送数据时,它会对实际提要进行散列处理,并通过实际提要 + 散列提要进行发送。在服务器端,您将使用密钥并对实际提要进行散列,并验证它是否与散列提要匹配。在我看来,这个解决方案主要是解决数据完整性方面的问题,这对你来说不是一个主要问题。rgt!(是的,逆向工程可能很容易。)

在上述方法中,服务器需要存储密钥因此,如果您的密钥被泄露,您的整个服务将被破坏,并且很难使用新密钥更新所有应用程序。或者,如果应用程序生成一个密钥,它必须将密钥与消息一起作为摘要或其他东西(如时间戳+一些随机数)在线发送。没那么难破解。

证书:即使有证书,您也可以获得相同的安全性.. 但它很难破解但很容易钢 :)。如果您在设备上保留一个私钥(当然,您必须在服务器上维护一个公钥)。您必须为每个客户端分配一个私钥,然后服务器需要为所有分配的私钥维护公钥。如果私钥被泄露,则只有单个应用程序可以被标记为红色并请求更新。

所以剩下的就是从应用程序开发的角度来看,您要避免伪造数据。为了防止恶作剧检查这些事情的唯一点是在应用程序逻辑中。您将需要缓存最后十个(或者甚至是最佳数量)提要(来自同一个 IP),并通过某种逻辑验证是否存在缺陷。

于 2012-08-12T16:30:39.910 回答
1

您可以使用速率限制 + 客户端“软”注册。

基本上,您将生成一个设备 ID,您可以在第一次请求时将其存储在用户默认值中。对于每个请求,您都会跟踪有多少请求已发送到服务器并限制它在服务器端。这可以很快实现。

您还可以使用某种共享密钥来使用生成的设备 id + post/get 参数对您的请求进行签名

于 2012-08-17T17:17:50.287 回答