在appengineservlet-java中存储已用令牌的列表

在appengineservlet-java中存储已用令牌的列表,java,google-app-engine,memcached,Java,Google App Engine,Memcached,我有一个小GAE应用程序,是我的Android应用程序的后端。 我在应用程序中有一个servlet,它从数据存储中提取数据并发送给用户。 我不希望任何人能够使用这个servlet,所以我在应用程序中存储了一个私钥,对于每个请求,我都会发送一个令牌——私钥的哈希字符串和当前毫秒数,以及我在哈希中使用的毫秒数。 服务器正在获取毫秒数和私钥,并将其与令牌进行比较。如果运行良好,服务器将毫秒存储在哈希集中,这样它就知道不再使用它。(有人可以嗅探设备数据,并一次又一次地发送相同的毫秒和令牌) 起初,我在S

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

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

我读过关于
Memcache
,但这不是一个最佳解决方案,因为据我所知,如果应用程序内存不足,或者即使服务器出现故障,
Memcache
中的数据也会被擦除

我不想使用数据存储,因为它会使请求速度慢得多

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

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

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

关于此方法的几点注意事项:

  • 我生成3个挑战的原因是允许并行处理多个请求
  • 进行挑战的时间越长,随机重用的可能性就越小(允许播放攻击)
  • 如果memcache忘记了我存储的挑战,应用程序的请求将失败。在失败响应中,我包括一个“忘记所有其他挑战,使用这3个新挑战:…”命令
  • 您可以将这些挑战与客户端的IP地址或其他类型的会话信息联系起来,以减少有人“攻击”您的可能性
  • 一般来说,最好让服务器为身份验证生成挑战或salt,而不是让客户端具有这种灵活性

如果希望坚持使用时间戳,可以使用的另一种方法是使用第一次请求交换来确定服务器实例和客户端设备之间的时间偏移。然后,只接受带有“当前”时间戳的请求。为此,您需要确定获得时间偏移的不确定性,并将其用作时间戳不为当前的截止点。为了防止在该截止时间段内发生重播攻击,您可能需要保存并禁止使用最后两个时间戳。这可能是在实例内部完成的,因为AppEngine、AFAIK优先将来自同一客户机的请求路由到同一实例。然后,如果关闭一个实例并重新启动一个实例(即清除不允许的缓存)所花的时间比“当前”截止时间长,那么重播攻击不应该有太多问题。

谢谢您的详细回答。您处理挑战的方式很好,但有一些开销,我不确定是否要添加到servlet中。我已经考虑过你的另一种方式(时间偏移),但它为错误留下了一些空间。我会接受你的回答,因为它给了我很多很好的信息,但我想我会坚持我的方式,只使用Memcache。谢谢