views:

496

answers:

8

Is it possible for a user to forge the result that is returned from $_SERVER['REMOTE_ADDR'] in PHP so they could in theory use SQL injection on a database?

This is a bit dumb, but I'm still new enough to PHP that I want to know if it can be done, whether or not I need to sanitize database input when the SELECT statement chooses from IP addresses returned from $_SERVER['REMOTE_ADDR']. So, if I wanted to use something like $query = "SELECT * FROM users WHERE IP='" . $_SERVER['REMOTE_ADDR'] . "'";, would there be any danger to my doing this?

Again, probably a "nooby" question, but I feel it must be asked.

Thanks

+5  A: 

Always sanitize all external inputs - use mysql_real_escape_string, or better still, prepared statements

K Prime
+13  A: 

It's a stretch, and unlikely, but I wouldn't go as far as to say it's impossible. So....

Use parameterized queries anyways.

Even if you never get attacked via the IP address field, you will still get the added benifit of faster queries through caching.

Neil N
What are parameterized queries? Can you give an example?
Cyclone
I looked them up. Thanks!
Cyclone
+2  A: 

You could use PHP's Data Filtering Functions.

filter_var() with FILTER_VALIDATE_IP will validate the remote IP. If the remote IP is valid, use it in SQL.

EDIT: filter_input() with INPUT_SERVER is another option ;)

http://www.php.net/manual/en/book.filter.php

http://www.php.net/manual/en/filter.filters.validate.php

http://www.php.net/manual/en/function.filter-var.php

http://www.php.net/manual/en/function.filter-input.php

Hope this helps,

Simeon

simeonwillbanks
+1  A: 

I always put this code in all my projects (some initial input sanitization), to prevent something nasty with faked IPs going on. I am not sure whether they can fake the REMOTE_ADDR anyway.

function validate_ip($ip) {
    // Try IPv4 First, as its the most used method right now
    if(!filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) {
        // Oops... try v6
        if(!filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) {
            return false; // Sorry...
        }
        else {
            return true;
        }
    }
    else {
        return true;
    }
}
if(!isset($_SERVER['REMOTE_ADDR'])) # wtf?
    die("Could not find your IP Address...");
else {
    if(validate_ip($_SERVER["REMOTE_ADDR"]))
        die("Could not validate your IP Address...");
}
Jimmie Lin
That `# wtf?` made me laugh
Cyclone
Haha right, I forgot about that comment that I added. Late-night 'coding' (well, writing small and simple pieces of code just to stay awake) forces me to write awful comments.
Jimmie Lin
+5  A: 

I think the only way for someone to forge $_SERVER['REMOTE_ADDR'] would be to construct a IP packet with a fake IP address (because it is set by the server, not the client), in which case responses would be routed back to the faked address. If you're worried about injection attacks, I think you're ok because the address fields in IP packets only have room for addresses.

danben
I agree (actually I was writing that as you posted).However, it would theoretically be okay to try injection attacks that would enable some other entrance way (blindly like you said), but that's pretty unlikely.
Eduardo
+1  A: 

REMOTE_ADDR isn't sent by the client, it's set by the server. While it's technically possible to spoof an IP address at the network level, the attacker has to work blind. The trickiest part is guessing the sequence number. (Under Coldfusion, by the way, it's another story.)

As others have said, use prepared statements and you don't need to worry about SQL injection (though other types of injection attacks are possible).

outis
Interesting, I didn't think it was even really possible at all
Cyclone
Note that IP address spoofing doesn't work as a vector for SQL injection, it just means you can't know for certain REMOTE_ADDR is the address of the computer that sent the request. Also, guessing sequence numbers isn't easy. On OpenBSD, which starts at a random number, it's basically impossible.
outis
+1  A: 

For efficiency and safety you may wish to store and work with IPs as ints in your database.

The straightforward way to store IP addresses is to use a varchar field in your DB. However, another way to represent IPs is as an integer. Converting the supplied IP in this way will sanitize it, and also make your storage and queries more efficient. Storing an INT takes up less space in a DB, and works better for indexing and I believe query caching.

Check out ip2long and long2ip for PHP functions to convert, and inet_aton and inet_ntoa to do it in MySQL.

So, the process might go like

$user_ip=ip2long($_SERVER['REMOTE_ADDR']);
if(!$user_ip){ //returned false due to odd input
   echo 'wtf, yo';
   }
else{
   //do your query
   }

You can also sanitize an IP and keep it in the original dotted quad form by combining the two

$user_ip=long2ip(ip2long($_SERVER['REMOTE_ADDR']));
Alex JL
You might want to make your coding style better. $_SERVER[REMOTE_ADDR] is awful.
Jimmie Lin
Thanks, for some reason I thought those were unquoted constants or something. Yes, I one should include the quotes, so I've updated my answer. I don't really think it's a matter of coding style though.
Alex JL
+1  A: 

You can't rely on REMOTE_ADDR being true... it could be the wrong address due to anonymising proxies or some such trick. You can rely on it always being an IP address, so SQL injection by this path is impossible.

Way down at the bottom of the stack, that's been converted from the source address on the packets making the TCP connection to your server. That means a) it has to be an IP address and b) it has to route back to the client for the connection to happen at all.

Andrew McGregor