IP Address Filtering - ruby-on-rails

I'm looking at implementing IP Address filtering for my Rails SaaS app. In a nutshell I want administrators to be able to specify one or more IP Addresses (or a range of IP Addresses) and then my app only accept requests on their instance from the specified addresses.
I'm looking at using IPAddress (http://github.com/bluemonk/ipaddress) for the parsing/validating of each address/range of addresses. Is this a good fit or are there better/more appropriate libraries?
Has anyone implemented this kind of filtering who could describe an approach that has worked for them or are there any gotchas I need to worry about?
Alternatively, is there an existing Ruby library that handles all of this automatically that has managed to elude my Googling?
Many Thanks,
Ash

ipaddress is an awesome library (I know the author), but you won't probably need it unless you are planning to perform some advanced manipulation of IP Addresses.
In fact, the most simple way is to
store the array of IP addresses to filter somewhere. You can use the string representation (192.168.1.1) or the long int representation. With the string version, you can even allow wildcards (192.168.1.*)
then configure a before_filter in the controller that will load the list of banned IPs and perform a simple string match to check whether current request.ip_address (request.remote_ip in rails 3) matches a banned IP. If true, redirect to the error page.
As you can see, you don't even need to convert the IPs into IP objects, unless you need to perform other kind of manipulations.

A little late to the party, but since I was looking for something similar and bumped into this nice Ruby gem I'll add it here to contribute to the thread. I like #simone's solution, but if you need a more control then Rack::Attack may be a good choice.
https://github.com/kickstarter/rack-attack
Rack::Attack!!!
A DSL for blocking & throttling abusive clients

I think you can achieve what you want using Rails 3 built-in routing features. Gregg Pollack introduces Rails 3 Action Dispatch and mentions (from the screencast) :constraints => {:ip => /192\.168\.1\.\d{1,3}}/} option where you can supply a regular expression matching the IP address range you want to allow.
Extending that a bit more, looking at the Advanced constraints and their example demonstrates pulling a list of blacklisted IPs out from the database and checking if the request.remote_ip is in the list of blacklisted IPs. It looks like you want a list of accepted (aka whitelist IPs) but the code would be nearly identical to the example in Rails guides.
So I would build your admin view to be able to input approved IP addresses, then the application routing can pull this list for incoming requests.

Related

Expanding a website - providing different contents across different places

I am working on a website. Currently the website was targeted to serve users from a specific Geographic region. Now I would like to expand its userbase to another region. The need is to serve different contents to different regions with the same base functionality.
My initial thought (I might sound a noob here) is to host the content specific to different regions on different databases -> Redirect users to specific domains and thus map the users geographically. Do suggest if its the right way to proceed.
Also, I would like to know whether there is a need to localize my website for these regions (Current language used is English)
Please post your experiences in such scenarios and also your ideas to bring about the transition.
Thanks in advance.
How do you see users being matched to their specific regional content?
Will they be presented with an option to choose?
Will you use geo functions to determine location?
Will you use server based reverse DNS lookup to determine location?
Will each region get its own "entry" URL (aka different domains)?
The first three are fraught with their own specific problems...
Presenting a choice/menu is considered bad form because it adds to the number of "clicks" necessary for a user to get to the content they actually came for.
While geo functions are very widely supported in all modern browsers, it is still seen as an issue of privacy in that a large number of users will not "allow" the functionality, meaning you'll have to fallback to a choice/menu approach anyway.
Server based reverse DNS, while a common practice, is very unreliable because many users are using VPN, proxies, TOR, etc. to specifically mask their actual location via this method of lookup.
Personally, my experience is to use completely separate entry URLs that are all hosted as virtual domains on a single Web Server. This gives you a large array of methods of determining which entry URL was used to access your code, and then format/customize the content appropriately.
There is really no need to setup separate servers and/or databases to handle these different domains/regions.
With that said, even if the language is common across regions, it is a very good habit to configure your servers and databases to support UTF-8 end-to-end, such that if any language specific options need to be supported in the future, then you won't need to change your code to do so. This is especially true if your site will capture any user generated input.

How to set up a custom domain prefix for my website's url

I just need to know what the name for the mail in:
*mail.*google.com
would be named
I thought 'custom domain prefix' made sense, but that doesn't seem to be it.
Please provide a link to documentation if possible, or just a proper search query.
Also, would it be a good idea to use these prefixes? Basically I have a site called smokelessmi.org and I want to make a prefix a2.smokelessmi.org for the city (Ann Arbor, Michigan) since this is a localized website.
Eventually I want to add other cities in Michigan, but I'm just starting with this one.
Not surprisingly there's a plethora of rfc's (rfc1591 rfc2606 and rfc2181 to name just a few) that talk about the structure of domain names, and this quote from rfc2181 stresses the hierarchical nature of DNS
Occasionally it is assumed that the Domain Name System serves only the
purpose of mapping Internet host names to data, and mapping Internet
addresses to host names. This is not correct, the DNS is a general
(if somewhat limited) hierarchical database, and can store almost any
kind of data, for almost any purpose.
So, to the left of your Top Level Domain (.com in your example) and what's quite often called second level domain (also used in the aforementioned rfc2606 and also in rfc920) or in short domain, you can still have a whole hierarchy of names. Personally I like to think of the leftmost one as the host name, because if you're addressing a service chances are that the most specific one represents a computer. The "intermediate ones" are commonly called subdomains.

How to restrict purchases to ONLY IP addresses in the United States using Ruby/Rails?

I have a client who has a requirement that they can't sell particular products 'outside the United States'.
They'd prefer that users can see the site, but when they try to checkout present a message indicating they are outside the United States.
Their site is built in Rails 2.3.8.
Check out the GeoIP gem (make sure to read the instructions, you need to download the GeoLiteCity or GeoLiteCountry database in order for it to work). It uses MaxMind's GeoIP database and can give you the country (or city, in the case of the city database) of an IP address, with some accuracy. There is a commercial database with better accuracy available, which I would recommend for your use case.
However, be advised that this is by no means a definitive solution. Some customers will be turned away wrongfully, and some will be able to order even though they should not. Things like satellite connections, proxy servers and VPN services make IP location impossible, and no database is 100% complete or correct.
What you're looking for is some kind of rough geolocation. One way to get this is to query a DNS zone designed specifically for this; one such zone is described at http://countries.nerd.dk.
I am from Ukraine. And when a particular US shop doesn't want to sell products overseas it usually specifies in the policy/faq/etc that only US bank issued payment cards are accepted.
That seems for me the best solution to solve: "can't sell particular products 'outside the United States'. "
As there are package/mail/freight forwarding companies which can be used by a potential client of that customer though residing outside US but whom the customer won't have to ship directly. That customer would still benefit from those sales but are freed from dialing with burden associated with overseas shipping.
And when you will solve it with geolocation, that customer would still be able making additional money, when people would still be using the site through different kind of proxies, if that customer will be worth it. :)
You can use their data that you pull into your database to check the user's IP address. http://www.ipligence.com/geolocation/ (you still have to worry about proxying)
I would also check where your shipping it to (checking addresses like suggested above), also check the card address with the card backer like VISA, etc..
And suggested above, your money processing agent shouldn't allow any transactions from outside the U.S. on particular items (if possible)
But I did read your statement SOME products may not be allowed to be sold outside the U.S. So you'll need a way to mark those products in your system and then let the user know they are unable to purchase those items, but continue on with others in the cart.
You could use a Rack Middleware, but it will require that you fork it on Github first.
https://github.com/roja/rack-geo
At the moment this project gives you City and Organisation names based on the IP address of the computer making the request - you need Country Code too.
You could add it to the code relatively easily here: https://github.com/roja/rack-geo/blob/master/lib/rack/geo.rb
You could then set a Rack environment variable to indicate if the request is from the USA, in the call method:
Rack::Request.new(env)["born"] = "...in the USA"
Add it to your config file:
config.middleware.use Rack::Geo
And then in your controller you can test if the request has this environment variable set appropriately and redirect to a 'sorry you must be from the USA' page:
if params['born'] == "...in the USA"
redirect_to "/not_from_round_here"
end
Bear in mind that IP address sniffing is fallible. I often take trains in the UK and end up with Google in German.
A geoip alternative is can be found here: http://humbuckercode.co.uk/licks/gems/geoip/
Uses the maxmind libraries, easy to set up, no schema updates needed, fast

Is it possible to track the country where a user is accessing a particular website?

I wish to track a user's country from where my website is accesed .
ex; if a customer from a particular is accessing say america how to trace that the user is actually from america.
Is there any way
What you are talking about is called GeoIP and there are many ways to do it. Normally this is done using a third party that has a mapping of IP addresses to physical locations.
This is of course not 100% accurate, as people may be using VPNs, TOR or simply spoofing addresses.
It's not possible in all cases, but most IP addresses can be mapped to a location (even down to the city). There are quite a large number of such geomapping services.
Use MaxMind service.
http://www.maxmind.com/app/javascript_city
They got free and paid versions.
You can determine the country of the IP address of last proxy that a user is using. This is often their country, but not always.
Users can set out to obscure it e.g. by using TOR or another proxy service.
Or their ISPs might be passing them through NAT or through other countries.
And what do you do with the information? Offer them the site in their presumed-native language? Or customise your contact details appropriately?
So you have to think carefully about how you use this information. It is a good idea to present a page in the native language that you think the user is surfing from, but you must make it easy and obvious for the user to change their country. Not all surfers in any given country actually speak the language, and not all people can call toll-free numbers, and not all people in one country are wanting support that's specific to their country, they may be seeking support for when they are elsewhere or for a friend etc.

Detect company names that are visiting my site

I'd like to use visitor IP addresses into a company name. This will be used for displaying something like "Hello visitor from Apple Inc." . Note I am looking for the company name, not the domain name. Extra points for determining the originating country. The app is written in Ruby on Rails, but examples in other languages will do. Thanks!
There are databases for this kind of thing, but they are hardly 100% accurate, so I'd think long and hard before using them to make assumptions regarding content you present to your visitors. If you still want to do it, here are two companies that offer databases that include organization level detail:
http://www.maxmind.com/app/ip-location
http://www.ip2location.com/
Edit to clarify based on additional answers:
The organization level detail in the databases from these vendors is different than ISP information, which is what the others are referring to. The databases from the vendors above are actually assigned organizational information based on research, not reverse lookup on IP ownership.
For starters, know that often it is impossible - e.g. many people's connection will be from Insight, or Comcast, or whatever their ISP is. I'm not sure if your intended feature is all that snazzy if you greet me as being "from" Insight Broadband.
You're very likely to get this more wrong than right, but you can get this from a whois client.
For example, to see owners of US addresses (at least), you can whois from the CLI to play around:
whois -h whois.arin.net 17.18.19.20

Resources