In several modules, replace $_SERVER["REMOTE_ADDR"] with a function which understands X-Forwarded-For.
Proxy servers often (sometimes, always?) insert "X-Forwarded-For" headers which contains the "real" client IP address. I think it is useful to log the client IP address in that situation.
This little snippet works for me, and I'd suggest something similar be made into a function?
$headers = apache_request_headers();
if (array_key_exists('X-Forwarded-For', $headers)){
$hostname=$headers['X-Forwarded-For'] . ' via ' . $_SERVER["REMOTE_ADDR"];
} else {
$hostname=$_SERVER["REMOTE_ADDR"];
}
I can make a patch proposal if people like the idea.
Comments
Comment #1
degerrit commentedHere's my proposal for showing user IP addresses behind proxy servers, especially in log files. It adds a function remote_addr() and replaces all the uses of $_SERVER["REMOTE_ADDR"] with that function.
This is my first patch for Drupal, don't be too harsh one me :-)
A few notes:
- I patched session.inc because $_SERVER["REMOTE_ADDR"] is also called in session.inc and common.inc is not available at that time it seems
- maybe I replaced too vigorously in common.inc and sessions.inc, it works for me though
- maybe it should be renamed http_remote_addr or apache_remote_addr
Comment #2
dries commentedCouple comments:
apache_request_headers()might not always be available.remote_address(). We usually don't abbreviate words like 'address'.and not
} else {X-Forwarded-For-headers? If it is, it would be easy to trick Drupal (eg. in the statistics.module's log pages we group by remote address). For the watchdog it doesn't matter, but for the statistics module it does. Maybe we need a toggle soremote_address()can be told not to return the 'true IP address'.Comment #3
Steven commentedX-Forwarded-For can be spoofed without any trouble. Just connect and send the fake header. I don't think we should pay attention to it. If we do, we need to also store the original IP address.
Perhaps we could do "real.ip.#.# (forwarded.ip.#.#)"
Comment #4
Steven commentedSorry didn't look at the patch carefully enough. Yes, we need XSS protection: in practice, we always strore remote_addr() in the hostname column in the db. Wherever that column is displayed, it needs to be check_plain()ed.
Comment #5
degerrit commentedI will re-write the patch with Dries' suggestions, I haven't had much time this week. I found some interesting examples of scripts doing roughly the same, none of them seem to do input checking (which I hadn't thought of either, but is obviously very needed!). Good thing there are people like Dries around, eh!
There's also another possible header: HTTP_CLIENT_IP, I've never seen it but then I don't log all my clients' headers either ;-)
Comment #6
Steven commentedIn Drupal we tend to store the original information in the db, escaping or formatting on output as needed. All places where the hostname is output should be okay after some recent changes.
Comment #7
robin monks commentedMoving.....
Robin
I ♥ Bugz
Comment #8
markus_petrux commentedAbsolutely. Just create a node using PHP format with the following contents:
Just a question, why would you store something that can not be trusted?
-1 for this, also there are several other ways to hide the real IP, so...
Comment #9
degerrit commentedGiven the feedback, perhaps this change isn't such a good idea (although most headers would probably be legitimate, it's true that it is much easier to spoof than an IP address).
But I can answer your question : I'm currently hosting my site via a reverse-proxy; so all accesses look like the same IP to my server. I was just 'scratching my own itch' as they say ...
Comment #10
markus_petrux commentedMaybe if Drupal (and contrib modules) was always accessing the user IP through a function (say
remote_address()), then you could simply adatp it for your particular need. That would be easier than search/replacing all accurrences of $_SERVER['REMOTE_ADDR'].Comment #11
magico commentedComment #12
kbahey commentedThis is now duplicated by http://drupal.org/node/142773