Rails 3 - Whitelisting list of IPs via routes

2019-02-03 10:13发布

问题:

This is a two part question. I'm needing to restrict a rails site that I'm throwing on development server to only a few IP addresses, so the public can't access it. (Basic HTTP auth doesn't 'entirely' work as the auth breaks a Flash uploader in the project.)

Based on what I've Googled, this is what I've come up with in my routes file...

class WhitelistConstraint
  def initialize
    @ips = '127.0.0.1'
  end

  def matches?(request)
    @ips.include?(request.remote_ip)
  end
end

MyProject::Application.routes.draw do
  constraints WhitelistConstraint.new do
     # all my routing stuff here
  end
end

Works pretty good. However, I need to modify this in order to work with several IP addresses. I tried using a array on @ips, as well as looping through an each loop, but neither worked.

On top of that, the second part of my question...I may need to check only against a segment of the IP, like '127.0.0'. How would I do that?

回答1:

I didn't know you could do this through routes, my approach would be to just have a before_filter in the ApplicationController and just have something that does:

before_filter :protect

def protect
  @ips = ['127.0.0.1', '203.123.10.1'] #And so on ...]
  if not @ips.include? request.remote_ip
     # Check for your subnet stuff here, for example
     # if not request.remote_ip.include?('127.0,0')
     render :text => "You are unauthorized"
     return
  end
end


回答2:

what about using NetAddr::CIDR?

and something like this?

class WhitelistConstraint
  def initialize
    @ips = []
    @ips << NetAddr::CIDR.create('127.0.0.0/8')
    @ips << NetAddr::CIDR.create('192.168.0.0/16')
  end

  def matches?(request)
    valid = @ips.select {|cidr| cidr.contains?(request.remote_ip) }
    !valid.empty?
   end
 end

 MyProject::Application.routes.draw do
    constraints WhitelistConstraint.new do
     # all my routing stuff here
     end
 end 

This way you can specify the blocks of IPs that should be whitelisted, and not have to worry about the partial matches?

>> require 'netaddr'
=> true
>> @ips = []
=> []
>> @ips << NetAddr::CIDR.create('127.0.0.0/8')
=> [127.0.0.08]
>> @ips << NetAddr::CIDR.create('192.168.0.0/16')
=> [127.0.0.08, 192.168.0.016]
>> @ips.select { |c| c.contains? '192.168.10.1' }
=> [192.168.0.016]
>> @ips.select { |c| c.contains? '192.169.10.1' }
=> []


回答3:

Or simply use apache's .htaccess:

  1. Add the following to the http.conf or whatever conf file you have for apache and your rails app

AllowOverride all

  1. Create a file .htaccess in the rails folder and add the following
Allow from xxx.xxx.xxx.xxx
Deny from all


回答4:

It is also possible to surround your route declaration with a scope like so:

scope :constraints => lambda{|req|%w(127.0.0.1).include? req.remote_addr} do

  ... your beautiful routes

end