0

我有一个小的 GAE 应用程序,我的 Android 应用程序的后端。我在应用程序中有一个 servlet,它从数据存储中提取数据并将其发送给用户。我不希望任何人能够使用这个 servlet,所以我在应用程序中存储了一个私钥,并且对于每个请求,我都会发送一个令牌 - 私钥的哈希字符串和当前毫秒,以及毫秒我在哈希中使用过。服务器正在获取毫秒和私钥,并将其与令牌进行比较。如果一切顺利,服务器会将毫秒存储在 a 中HashSet,这样它就会知道不再使用它。(有人可以嗅探设备数据 - 并一遍又一遍地发送相同的毫秒和令牌)。

一开始,我在Servlet类中持有一个静态字段,后来发现是错误的,因为这个字段没有持久化,当实例被销毁时,所有数据都丢失了。

我已经阅读过Memcache,但这不是一个最佳解决方案,因为据我了解,Memcache如果应用程序内存不足,或者即使服务器出现故障,也会删除其中的数据。

我不想使用数据存储,因为它确实会使请求变慢。

我想我不是第一个面临这个问题的人。我该如何解决?

4

1 回答 1

1

我在我的一个应用程序中使用了反向方法:

每当一个新的客户端连接时,我都会在服务器上生成一组三个随机的“挑战”(比如你的毫秒),我将它们存储在 memcache 中,过期时间为一分钟左右。然后我将这些挑战发送给客户。对于客户端发出的每个请求,它需要使用这 3 个挑战之一(使用私钥散列)。然后服务器删除使用过的挑战,创建一个新挑战并将其发送给客户端。这样,每个挑战都是一次性的,我不必担心重放攻击。

关于这种方法的几点说明:

  • 我产生 3 个挑战的原因是允许并行运行多个请求。
  • 您进行挑战的时间越长,它被随机重用的可能性就越小(然后允许播放攻击)。
  • 如果 memcache 忘记了我存储的挑战,应用程序的请求将失败。在失败中,我的响应包括“忘记所有其他挑战并使用这 3 个新挑战:...”命令。
  • 您可以将挑战与客户端的 IP 地址或某种其他类型的会话信息联系起来,以降低有人“破解”您的可能性。
  • 通常,最好让服务器为身份验证生成挑战或加盐,而不是为客户端提供这种灵活性。

如果您想坚持使用时间戳,您可以使用的另一种方法是使用第一个请求交换来确定服务器实例和客户端设备之间的时间偏移。然后,只接受带有“当前”时间戳的请求。为此,您需要确定您可以获得时间偏移的不确定性,并将其用作时间戳不是当前的截止值。为了防止在该截止时间内重放攻击,您可能需要保存并禁止使用最后几个时间戳。您可以在您的实例中执行此操作,因为 AppEngine、AFAIK 会将来自同一客户端的请求优先路由到同一实例。然后,如果关闭一个实例并重新启动一个实例(即清除您的不允许缓存)比您的“当前”截止时间更长,那么您不应该

于 2013-03-15T00:50:22.883 回答