Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/google-app-engine/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 限制来自任何给定IP地址的请求数_Python_Google App Engine_Webapp2 - Fatal编程技术网

Python 限制来自任何给定IP地址的请求数

Python 限制来自任何给定IP地址的请求数,python,google-app-engine,webapp2,Python,Google App Engine,Webapp2,我正在从事一个Google应用程序引擎项目(python/webapp2),在该项目中,我有点担心有人滥用/滥发我正在创建的服务,并提出大量请求。为了消除这种可能性,我的想法是限制应用程序某些部分在任何给定时间内每个IP地址允许的请求数。我目前的计划如下: 根据每项要求,我将: 从标头中获取ip地址 使用时间戳将此ip地址存储在数据存储中 删除中超过一小时的所有ip地址实体 计算具有该IP地址的数据存储实体的数量 如果超过给定限制,则不允许访问 我的问题是: 这是最好的方法吗?我只是一个初学者,

我正在从事一个Google应用程序引擎项目(python/webapp2),在该项目中,我有点担心有人滥用/滥发我正在创建的服务,并提出大量请求。为了消除这种可能性,我的想法是限制应用程序某些部分在任何给定时间内每个IP地址允许的请求数。我目前的计划如下:

根据每项要求,我将:

  • 从标头中获取ip地址
  • 使用时间戳将此ip地址存储在数据存储中
  • 删除中超过一小时的所有ip地址实体
  • 计算具有该IP地址的数据存储实体的数量
  • 如果超过给定限制,则不允许访问
  • 我的问题是:

    这是最好的方法吗?我只是一个初学者,我想这样做会有相当大的开销,可能这是一个常见的任务,可能有更好的解决方案。有没有更好的方法来做到这一点,而不是资源密集型的?

    在过去,我使用memcache来实现这一点,它要快得多,特别是因为您只关心近似限制(近似,因为memcache可以由系统刷新,可能不会由所有实例共享,等等)。您甚至可以使用它使密钥过期。类似这样的情况(假设
    self
    是一个webapp2请求处理程序,并且您已经导入了GAE的memcache库):


    这将创建一个密钥,该密钥在大约MAX_请求在WINDOW_秒时间内拒绝用户,并将每个WINDOW_秒时间内的计数重新归零。(即,它不是滑动窗口;每个时间段都会重置为零。)

    首先,您的设计有两个注意事项:

    • 人们通常很容易获得一个新的IP地址,将iPhone从LTE切换到3G,然后再切换回来,拔下并重新安装DSL型号,选择一个新的开放代理,等等。因此,如果你希望这样做能够防止故意滥用,而不仅仅是人们没有意识到他们做得太多,那么这并没有多帮助

    • IP地址通常由或按顺序共享。如果每个IP每小时200个请求意味着一个人,那么这似乎是合理的,但如果它意味着BigCorp区域办事处的所有7500名员工呢

    不管怎样,你的解决方案是可行的,而且,根据你的流量模式,它可能是合理的,但是有一些替代方案

    例如,您可能希望保留一个共享黑名单,而不是检查每个连接。当连接进入时,立即根据该黑名单接受或拒绝,并启动“更新数据库”作业。你可以做更多的技巧来合并更新,而不是每N秒更新一次,等等。当然这意味着你现在拥有了所有连接都可以读取、后台作业可以写入的共享数据,这意味着你已经打开了通往比赛条件、僵局和所有有趣的事情的大门,Guido努力确保你很少面对GAE

    您可以使用memcache而不是dataStore。但是,您需要仔细地修改密钥,以便它们对于简单的键值存储有意义,从而满足您的需要。例如,您可以为每个连接保留一个键入的IP值加上一个时间戳或随机数或其他任何内容,再加上一个键入的IP连接值列表,以便查找其他值。从缓存中删除的任何值都不再计算,如果连接列表值下降,则用户必须降至0。但这增加了很多复杂性

    如果您有一小部分用户,每个用户都会发出大量请求,那么您可以使用计时器来减少或重置或重新计算每个IP。但是,如果您预计每小时会有数百个不同的IP,那么您需要手动合并所有这些计时器,并且可能也会合并作业(例如,“17:55:39,减少17个IP的列表”),并且计时器可能会频繁触发,这可能不值得

    就我个人而言,我会先做最简单的实现,然后进行压力测试和性能测试,如果足够好,就不用担心了


    如果还不够好,我可能会在考虑优化实现之前先考虑是否可以简化设计。例如,如果是每个日历小时每个IP有N个连接,那么这会使一切变得更加简单,只需在每个IP(数据存储或memcache)中存储一个计数器,并在每个XX:00擦除所有计数器。这可以接受吗?

    需要担心的一件事是NAT。如果NAT系统(例如公司或某些ISP)后面有大量用户,则您看到的所有用户的传入地址都是相同的(或分散在一个小集合中)。+1到DrC。但值得注意的是,不管怎样,许多服务都能做到这一点,从AmpliFIND这样的小型服务到Twitter这样的巨头。解决这一问题的通常方法是为开发人员和/或最终用户提供一个选项,让他们可以使用某种每用户/-system/-program/-which身份验证(例如OAuth令牌)。对于静态IP地址,您可以在应用程序中使用拒绝服务配置文件dos.xml。只要将滥用您服务的IP地址列入黑名单,并按照上面所述重新部署您的应用程序,这些都是我必须研究的极好建议。谢谢你的帮助这正是我要找的。非常简单,你甚至给了我一个很好的开始。非常感谢:)请注意,如果尚未在Memcache中设置密钥,您应该在第一个if语句中检查
    count不是None和count>MAX\u REQUESTS
    memcache_key = 'request-count-' + self.request.remote_addr
    
    count = memcache.get(memcache_key)
    
    if count is not None and count > MAX_REQUESTS:
        logging.warning("Remote user has %d requests; rejecting." % (count))
        self.error(429)
        return
    
    count = memcache.incr(memcache_key)
    if count is None:
        # key didn't exist yet
        memcache.add(memcache_key, 1, time=WINDOW_IN_SECONDS)