【问题标题】:Rack Middleware For Monitoring 7 Days Traffic用于监控 7 天流量的机架中间件
【发布时间】:2015-05-24 14:21:54
【问题描述】:

我需要一些帮助来了解如何开始这个项目。 我必须编写一个机架中间件来监控 7 天的流量,如果流量增加超过阈值,则相应地阻止生成流量的特定 I.P。

基本我想防止我的网站受到 DDOS 攻击,并且我想编写我的自定义 RACK 应用程序。

这个应用程序有多业余并不重要,但我需要了解它是如何工作的,这就是我想做这个应用程序的原因。

有人可以指导我吗?

我已经看到的一些资源是 Rack Throttle 和 Rack Defense gem,但我仍然很困惑,请指导我解决这个问题。

【问题讨论】:

  • 你提到了两个可以做你想做的事情的宝石,但没有说为什么它们不能满足你的需求。你想做什么他们做不到的?
  • 所以你是对的,大部分功能都是由这些宝石提供给我的,但我很难理解它们,然后在其之上构建一些额外的逻辑。所以基本上我需要要知道如何监控 7 天的流量,然后从下周开始继续比较数据,如果任何特定日期或一周的流量超过 50%,然后阻止 ip 生成这些请求或将它们重定向到验证码.我很困惑如何在这些宝石之上实现它
  • 这似乎是一个非常具体的要求。是否有特定的业务需求?许多人和您有同样的问题,并且对这些 gem 提供的解决方案感到满意,那么您的案例有何不同?也许你会接受与他们相同的解决方案。
  • 通过相同的解决方案,您的意思是这些 gem 具有跟踪 7 天流量的内置功能,如果是,您能解释一下如何做到这一点吗?
  • 看我的回答,继承RackThrottle::TimeWindow很容易实现

标签: ruby-on-rails rack


【解决方案1】:

据我了解,这仅用于学习目的,所以这里是如何实现它的小细节。为了在生产中使用它,我绝对建议只使用 Rack Throttle,因为有许多极端情况和选项,我们在这个简单的示例中没有介绍。

这是最小的 Rack 中间件,它只打印出 IP

#!/usr/bin/env rackup

require "rack"

class Limiter
  attr_reader :app

  def initialize(app)
    @app = app
  end

  def call(env)
    request = Rack::Request.new(env)
    puts request.ip
    app.call(env)
  end
end

use Limiter

run lambda { |env| [200, {'Content-Type' => 'text/plain'}, ["Hello, world!\n"]] }

中间件必须是类,因为它们需要有一个初始化器,该初始化器将传递给链中的下一个应用程序。 call 方法获取请求环境,做它需要做的任何事情,然后调用下一个应用程序。我们的中间件现在只是打印出 IP 地址。

https://github.com/rack/rack/blob/master/lib/rack/request.rb#L354 https://thoughtbot.com/upcase/videos/rack

现在我们可以存储每个 ip 地址的请求计数,并在超过限制时阻止请求:

#!/usr/bin/env rackup

require "rack"

class Limiter
  attr_reader :app, :options, :counter

  def initialize(app, options)
    @app = app
    @options = options
    @counter = {}
  end

  def call(env)
    request = Rack::Request.new(env)

    if counter[request.ip].to_i > options[:max].to_i
      [200, {'Content-Type' => 'text/plain'}, ["You are blocked, request count: #{counter[request.ip]}\n"]]
    else
      counter[request.ip] ||= 0
      counter[request.ip] += 1
      app.call(env)
    end
  end
end

use Limiter, max: 1

run lambda { |env| [200, {'Content-Type' => 'text/plain'}, ["Hello, world!\n"]] }

如果您执行此应用程序,它将在第一次请求后阻止您。

您可以看到我们现在使用选项max: 1 初始化中间件,我们可以从options 访问中间件内部。我们使用它来确定何时阻止请求。

我们还初始化了一个简单的散列,我们在其中存储每个 IP 地址的请求计数。请注意,这仅适用于您拥有单个 Web 服务器的情况。如果您有更多服务器,则需要在服务器之间同步计数。不错的选择是 Redis 或 Memcache。

总的来说,Rack Throttle 代码可读性很强,因此我建议通读一遍。大多数逻辑都在Limiter class 中实现,大多数其他类都从该Limiter class 继承。

编辑

作者提出的这个问题

通过相同的解决方案,您的意思是这些 gem 具有跟踪 7 天流量的内置功能,如果是,您能解释一下如何做到这一点吗?

AFAIK Rack::Throttle 尚未实现此功能,但通过继承 TimeWindow 可以轻松添加

  class Weekly < RackThrottle::TimeWindow
    ##
    # @param  [#call]                  app
    # @param  [Hash{Symbol => Object}] options
    # @option options [Integer] :max   (3600)
    def initialize(app, options = {})
      super
    end

    ##
    def max_per_week(request = nil)
      @max_per_week ||= options[:max_per_week] || options[:max] || 3_600 * 7
    end

    alias_method :max_per_window, :max_per_week

    protected

    ##
    # @param  [Rack::Request] request
    # @return [String]
    def cache_key(request)
      # %U returns the calendar week
      [super, Time.now.strftime('%U')].join(':')
    end
  end

请注意,这将按日历周进行跟踪。如果您想要滚动跟踪器,您需要每天计数,然后获取最近 7 天的数据。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-10-02
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多