如何在不登录的情况下保护Web服务

时间:2012-08-12 15:05:32

标签: ios web-services security

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

这是一个非常简单的应用程序,我无法想象任何人都在努力滥用Web服务。但是,我可以看到有人在发布许多标记时很有趣。最让我担心的是有人运行一个脚本来推送许多请求(使用昂贵的带宽并使我的应用数据无效)。

我慢慢得出结论,这不可能是安全的。最好的答案是“不要这样做”。不提供身份验证的Web服务。没有多少服务如此开放。 Google的You Tube API已经开放,但大部分都没有。不幸的是,我别无选择。所以经过几天看这里是我的想法。请注意,我离安全专家很远,我相信我的方法可以改进。但它可能会指出你正确的方向。希望更有经验的人可以加入并纠正/改进。我发现this article并且评论特别有帮助。

邮件级安全性

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

客户端措施

客户端包括邮件的速率限制,作为限制诚实用户发送的邮件数量的措施。然而,对于越狱移动设备的攻击者来说,这是无用的。

服务器端安全性

因此,服务器端必须具有尽可能多的额外安全措施,并且假设您的客户端(和共享密钥)受到损害。这就是我所拥有的:

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

服务器通过IP执行速率限制。是的,IP容易被欺骗,代理切换是孩子们的玩法,但是当你这么少时,一切都会有所帮助。

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

传输级安全性

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

我的方法中的大洞大洞

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

最终辩护

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

8 个答案:

答案 0 :(得分:22)

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

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

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

  3. 基本上,您让Apple尽一切努力确保初始请求来自实际的iOS设备。

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

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

答案 1 :(得分:12)

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

准确地说:找一些计算算法,可以在一眨眼间为一对zx计算一些y,但它需要相当多的计算z的时间仅为x。我不能提供实际的算法,但我确信有很多这样的标准。

现在整个程序应如下所示:

  1. 首次客户请求时会生成一些session_id,并为此session_id生成一对xy
  2. 为您的客户提供session_idx
  3. 客户端可以在收到数据后立即开始计算(在某些后台线程中与用户交互无关)。
  4. 要请求标记,客户必须提供session_id并计算z
  5. 您可以快速验证客户z是否正常,因为您已经拥有xy,可以轻松完成。
  6. (选项1)对于每个session_id商店,请求的数量/频率。您怀疑它被滥用的那一刻 - 强制重生xy
  7. (选项2)在x的每个连续请求中强制新ysession_id
  8. 在6到7之间进行选择实际上是在调整,这取决于算法的复杂性与预期的“公平”之间的关系。使用标记数据库。如果你的估计是好的 - 邪恶的客户端永远不应该获得太多数据或服务器过载。

    希望它有所帮助。

答案 2 :(得分:5)

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

我只是实现一些服务器端速率限制(每个IP地址),不再担心这个问题。这是一场你无法获胜的战斗。如果有人真的想要伤害你的服务器,他可能只是DDOS而不知道你的网络服务协议。

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

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

最后一点 - 你真的认为这是必要的吗?您不希望用户必须注册,因此您的数据或服务不会太重要。那么,任何人都需要从逆向工程应用程序中获得什么,并充斥您的服务器请求?

答案 3 :(得分:3)

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

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

  

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

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

  

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

     

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

     

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

     

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

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

答案 4 :(得分:2)

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

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

没有纯粹的客户端速率限制会产生任何不同。有人可以在网上发现您的API,甚至没有见过您的客户。我怀疑共享秘密会长期有效。

您会发现大量不需要密码的网络服务,而且只是速率限制......例如,twitter API提供了许多速率受限的未经身份验证的API服务。

答案 5 :(得分:2)

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

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

,因为:

  • 您不会向全世界公开公共界面,因此您可以随时通过更新网络服务和更新您的应用来更改您的网络服务界面。
  • 该应用程序“非常微不足道”(正如您所说)并且可能目前使用不多
  • 你现在可能有更好的事情要做,而且只是消耗时间

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

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

这将有99,99%解决您的问题,您现在可以开始工作并编写出色的新功能。

答案 6 :(得分:1)

这很棘手,你不要指望任何人篡改数据......所以你关注的不是诚信。 由于您没有维护任何客户列表......对真实性没有任何顾虑?

对于所有众所周知的Webservice攻击(如DoS或重放攻击),您可以获得可以阻止它们的防火墙。所以我认为你不需要为此烦恼。

但是,您不希望发送纯文本数据,并希望确保您的下载应用程序正在推送数据。

如果你看一下你正在评估的方法:

安全密钥:据我所知,服务器和应用程序将共享相同的密钥,如果我是正确的,所有设备上的所有应用程序将共享相同的密钥。当应用程序推送数据时,它会散列实际Feed并发送实际Feed +散列Feed。在服务器端,您将使用Key并散列实际的Feed,并验证它是否与散列的feed匹配。在我看来,这个解决方案主要解决数据完整性方面,这不是您的主要关注点。 RGT! (是的,逆向工程可能很容易。)

在上述方法中,服务器需要存储密钥因此,如果您的密钥被泄露,您的整个服务将会很难用新密钥更新所有应用程序。 或者,如果应用程序生成密钥,它将必须在线路上发送密钥以及消息作为摘要或某些内容(如时间戳+一些随机数)。不难打破。

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

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

答案 7 :(得分:1)

您可以使用限价+客户'软'注册。

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

您还可以使用生成的设备ID +发布/获取参数来签署您的请求的某种共享密钥