Reason:
I am a webmaster of 7 sites, and to manage unwanted comments on a contact form I block the IP of bad commentators. Each time i get a new bad IP I have to edit each contact form on all 7 servers, which is very time consuming. What i would like is for the IP addresses to be put in 1 file on my server and just read in my all the other sites.
Current Code: (I have shortened the IP array)
<?php
$deny = array("91.200.14.59", "91.207.7.141");
if (in_array ($_SERVER['REMOTE_ADDR'], $deny)) {
header("location: index.php?page=error404");
exit();
} ?>
Answer Required:
How do i get the above code to read the IP file (array) from another server?
An example of the code would truly be appreciated.
Thanks
I'd be going about this the other way around: keep the list up to date locally (in a version control repository no less), and push the changes using a deploy tool. For instance, Ansible is a neat little tool. Example configuration:
---
- hosts: comment-forms
tasks:
- name: Ensure blacklist is up to date
copy: src=blacklist.txt
dest=/var/www/conf/blacklist.txt
owner=www-data
group=www-data
mode=440
Then deploy whenever you update the list:
$ ansible-playbook blacklist.yml
It's that easy, once you've set it up. And it means you don't need to make costly remote requests from your servers all the time.
here what you can do:
Create one blocked IP file on one of your servers.
e.g filename = blockip.txt
content of blockip.txt:
91.200.14.59,91.207.7.141..
Make sure the file is accessible via http protocol.
e.g: http://www.example.com/blockip.txt
On your application server, create a function which will read blockip.txt file and compare with the remote ip .
e.g:
<?php function check_spam_user($remote_ip){
$x = file_get_content('http://www.example.com/blockip.txt');
if(strpos($x,$remote_ip) === FALSE){
//real user
}
else {
//spammers
}
} ?>
You can use any logic for reading file and comparing ip address.
With this every time you got new IP address you need to update just blockip.txt file, rest all will be taken care by function check_span_user().
Related
I would like to make a PHP website, where employees can log in/out themselves and these logs will count as a time when they started and ended their working day. I would like to allow them to do that only on their work computer and not for example on their phone while they are still on the way, but they want to avoid "being late".
So I'm struggling with a few ideas, but any of them seems to be the right solution.
Allow using the website only for specific IP addresses. But then I realized that in our place IP address is dynamic and changing it for static costs too much in our area.
Check user location. But then I saw that when I'm checking my public IP address, the location is completely wrong! Our building isn't even close to the loaded area.
Using a COOKIE/token on a work computer. But it's very easy to set the same cookie on your own device and I'm not the only IT employee here.
Checking MAC address. As I read here it's possible only in specific cases.
Block access for mobiles. But detecting a mobile is based on browser and if the user click "Request Desktop Site" scripts will say that's a computer.
Is there another method, which I can use to achieve my goal? Am I missing something?
May I bind my app for example with some other technologies that will allow me to do that? Or maybe I should try a combination of all of them?
I couldn't find any script, which would take care of that. In the worst case it doesn't have to be "perfectly secure", but I would like to be it at least hard, annoying, or time-consuming to try to "cheat" in this system.
I would run your app in the office LAN. Nobody will be able to access it from outside except if they can do remote desktop to the office computer or if they have VPN. But if you are in the IT team you may could fix IP ranges for the office computers so that you could exclude the VPN.
In terms of security, in any case it may be better having it running in your LAN. I'm sure you've got a server somewhere and if it's not the case then you could use a NAS (Synology offers NGINX, Apache, PHP and much more) or a little Rasperry Pie or something similar.
If you haven't got a fixed IP, you could also use DynDNS and have it mapped to a sub-domain such as company-name.dyndns.org and then on your PHP app you could have a cron job that gets the IP address from the domain name and updates it every minutes (I'm sure it's quickly run). It could then store it inside a config file, this way:
<?php
define('ALLOWED_IP_FILE', 'allowed-ips.inc.php');
$ALLOWED_DOMAINS = [
'your-company.dyndns.org',
'you-at-home.dyndns.org',
];
$allowed_ips = [];
foreach ($ALLOWED_DOMAINS as $allowed_domain) {
$ip = gethostbyname($allowed_domain);
if ($ip !== $allowed_domain) {
// Store with the IP in the key and value for ease when checking the IP validity.
$allowed_ips[$ip] = $ip;
} else {
fprintf(STDERR, "ERROR: Could not find the IP of $allowed_domain!\n");
}
}
$allowed_ips_export = var_export($allowed_ips, true);
$config_file_content = <<<END_OF_CONFIG
<?php
// Don't edit! This config file is generated by cron-ip-address.php.
\$ALLOWED_IPS = $allowed_ips_export;
END_OF_CONFIG;
if (file_put_contents(ALLOWED_IP_FILE, $config_file_content) === false) {
fprintf(STDERR, 'ERROR: Could not write config file ' . ALLOWED_IP_FILE . "\n");
}
This generates a config file to include in your app. Example of content generated if you run the script I wrote above:
<?php
// Don't edit! This config file is generated by cron-ip-address.php.
$ALLOWED_IPS = array (
'142.250.203.99' => '142.250.203.99',
'23.201.250.169' => '23.201.250.169',
);
Now, in your app, just include it and test the presence of the IP in the $ALLOWED_IPS array:
<?php
include ALLOWED_IP_FILE; // If this is declared in a common config file.
// include 'allowed-ips.inc.php'; // If you haven't got a common config file.
if (!isset($ALLOWED_IPS[$_SERVER['REMOTE_ADDR']])) {
http_response_code(403);
die('Sorry, you cannot access it from here.');
}
Ideally, if what you actually want to track is when employees are in the workplace and logged on / for how long, it would be probably better to just track local machine-logins via a domain controller - a method reachable from the internet is suboptimal exactly for the reasons you mentioned.
If you have an intranet which users cannot tunnel into but can access from their work machines, I'd say hosting your login-page only inside that intranet is the easiest way to achieve what you want with the methods you suggest.
Alternatively, if employee work-machines use windows under a domain controller - you can restrict access to Windows certificate-storage, then install/push a certificate and require that to be present via your server-configuration. In that case, it doesn't matter if the website is accessible from the internet. I'm sure there are similar solutions if work-machines are not on Windows.
This admittely old question gives some pointers in the right direction on how to require client certificates from a Webserver (IIS in that case).
What is the most accurate way to get user's IP address in 2017 via PHP?
I've read a lot of SO questions and answers about it, but most of answers are old and commented by users that these ways are unsafe.
For example, take a look at this question (2011): How to get the client IP address in PHP?
Tim Kennedy's answer contains a recommendation to use something like:
if (!empty($_SERVER['HTTP_CLIENT_IP'])) {
$ip = $_SERVER['HTTP_CLIENT_IP'];
} elseif (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
$ip = $_SERVER['HTTP_X_FORWARDED_FOR'];
} else {
$ip = $_SERVER['REMOTE_ADDR'];
}
But as I've read a lot, I have seen that to use X_FORWARDED_FOR is unsafe, as the comment below highlights:
Do NOT use the above code unless you know EXACTLY what it does! I've
seen MASSIVE security holes due to this. The client can set the
X-Forwarded-For or the Client-IP header to any arbitrary value it
wants. Unless you have a trusted reverse proxy, you shouldn't use any
of those values.
As I didn't know EXACTLY what it does, I don't want to take the risk. He said it is unsafe, but did not provide a safe method to get user's IP address.
I've tried the simple $_SERVER['REMOTE_ADDR'];, but this returns the wrong IP. I've tested this and my real IP follows this pattern: 78.57.xxx.xxx, but I get an IP address like: 81.7.xxx.xxx
So do you have any ideas?
Short answer:
$ip = $_SERVER['REMOTE_ADDR'];
As of 2021 (and still) $_SERVER['REMOTE_ADDR']; is the only reliable way to get users ip address, but it can show erroneous results if behind a proxy server.
All other solutions imply security risks or can be easily faked.
From a security POV, nothing but $_SERVER['REMOTE_ADDR'] is reliable - that's just the simple truth, unfortunately.
All the variables prefixed with HTTP_ are in fact HTTP headers sent by the client, and there there's no other way to transfer that information while requests pass through different servers.
But that of course automatically means that clients can spoof those headers.
You can never, ever trust the client.
Unless it is you ... If you control the proxy or load-balancer, it is possible to configure it so that it drops such headers from the original request.
Then, and only then, you could trust an e.g. X-Client-IP header, but really, there's no need to at that point ... your webserver can also be configured to replace REMOTE_ADDR with that value and the entire process becomes transparent to you.
This will always be the case, no matter which year we are in ... for anything related to security - only trust REMOTE_ADDR.
Best case scenario is to read the HTTP_ data for statistical purposes only, and even then - make sure that the input is at least a valid IP address.
You have to collaborate with your sysops team (or if you're wearing that hat too, you will need to do some research). The header check is used when your network infrastructure is configured in certain ways where the remote requester is one of your network appliances instead of the end
user.
This sort of thing happens when your web server(s) sit behind a load balancer or firewall or other appliance that needs to interrogate the payload to properly handle it. An example is when a load balancer terminated ssl and forwards the request on to the web server without ssl. When this occurs the remote address becomes the load balancer. It also happens with firewall appliances that do the same thing.
Most instances the device will offer configuration to set a header value in the request with the original remote ip address. The header is usually what you'd expect but it can in some cases be different or even configurable.
What's more, depending on your web server configuration (apache, nginx or other) may not support or be currently configured to support certain custom headers such as the common ip header.
The point is us you will need to investigate your network configuration to ensure that the original requester's ip makes it all the way through to your application code and in what form.
If you'd like to use a pre-built library, you can use Whip.
Using pre-made libraries are usually better because most of them will have been checked thoroughly by an active community. Some of them, especially the ones that have been around for a long time, have more features built-in.
But if you want to code it yourself to learn the concept, then it's ok I guess. I recommend packaging it as a stand alone library and releasing it as open-source :)
EDIT: I do not recommend using the remote IP in security mechanisms as they are not always reliable.
First, it is impossible to reliably determine someone's source IP address if they are intent on being hidden. Even something which today seems foolproof, will soon have a loophole (if it doesn't already). As such, any answer below should be considered UNTRUSTED, which means that if you put all of your eggs in this basket, be prepared for someone to take advantage of it or circumvent it somehow.
I won't get in to all the ways someone can circumvent IP tracking, because
it is constantly evolving. What I will say is that it can be a useful tool for logging as long as you know that IP addresses can easily change or otherwise be masked.
Now, one big point to make is that there is a difference between a public IP address and a private IP address. In IPV4, routers are generally assigned one public IP address, which is all that a server-side language can actually grab, because it doesn't see your client-side IP address. To a server, your computer doesn't exist as a web-space. Instead, your router is all that matters. In turn, your router is the only thing that cares about your computer, and it assigns a private IP address (to which your 172...* address belongs) to make this work. This is good for you, because you can't directly access a computer behind a router.
If you want to access a private IP address, you need to use JavaScript (client-side language). You can then store the data asynchronously via AJAX. As far as I know, this is only currently possible using WebRTC-enabled Chrome and Firefox. See here for a demo.
I tested this and it returns private IP addresses. Typically I think this is used by advertisers to help track individual users in a network, in conjunction with the public IP address. I am certain that it will quickly become useless as people come up with workarounds or as public outcry forces them to offer the ability to disable the WebRTC API. However, for the time being it works for anyone who has JavaScript enabled on Chrome and Firefox.
More Reading:
What is a Private Network?
STUN IP Address requests for WebRTC
Quick Link: IP address checker
Get Client IP Address:
<?php
echo $ip = $_SERVER['REMOTE_ADDR'];
?>
Note::
This would work only on live site, because on your local host your ip would be one (1) of the internal ip addresses, like 127.0.0.1
So, its Return ::1
Example : https://www.virendrachandak.com/demos/getting-real-client-ip-address-in-php.php
Its Show Your Local Ip:
Like ... 78.57.xxx.xxx
Example:
<?php
$myIp= getHostByName(php_uname('n'));
echo $myIp;
?>
As the real method is to check user IP is $ip = $_SERVER['REMOTE_ADDR'];
If the user is using VPN or any proxy then it will not detect the original IP.
How about this one -
public function getClientIP()
{
$remoteKeys = [
'HTTP_X_FORWARDED_FOR',
'HTTP_CLIENT_IP',
'HTTP_X_FORWARDED',
'HTTP_FORWARDED_FOR',
'HTTP_FORWARDED',
'REMOTE_ADDR',
'HTTP_X_CLUSTER_CLIENT_IP',
];
foreach ($remoteKeys as $key) {
if ($address = getenv($key)) {
foreach (explode(',', $address) as $ip) {
if ($this->isValidIp($ip)) {
return $ip;
}
}
}
}
return '127.0.0.0';
}
private function isValidIp($ip)
{
if (!filter_var($ip, FILTER_VALIDATE_IP,
FILTER_FLAG_IPV4 | FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE)
&& !filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6 | FILTER_FLAG_NO_PRIV_RANGE)
) {
return false;
}
return true;
}
I use this code, and it works for me. Take a look to it.
<?php
// Gets client's IP.
$ip = getenv("HTTP_CLIENT_IP")?:
getenv("HTTP_X_FORWARDED_FOR")?:
getenv("HTTP_X_FORWARDED")?:
getenv("HTTP_FORWARDED_FOR")?:
getenv("HTTP_FORWARDED")?:
getenv("REMOTE_ADDR");
echo $ip;
?>
Here, a working example. Hope it helps!
Because of different network setups (proxy servers, private networks, etc.) and how administrators configure their networks, it is difficult to obtain the client IP address. Standards are being addressed related to this issue.
The following function worked in 4 different tests (Home Network, VPN, Remote connection, public internet). The code can be used as base code for your project. Modify as needed.
The function does validate the IP address, but does not validate IP ranges. This would be an additional test after you obtain the client IP.
$_SERVER["REMOTE_ADDR"] does not always return the true client IP address.
Because some of the parameters can be set by end users, security can be an issue.
Set Client IP address
$clientIpAddress = $du->setClientIpAddress($_SERVER);
public function setClientIpAddress($serverVars) {
# Initialization
$searchList = "HTTP_CLIENT_IP,HTTP_X_FORWARDED_FOR,HTTP_X_FORWARDED,HTTP_X_CLUSTER_CLIENT_IP,HTTP_FORWARDED_FOR,HTTP_FORWARDED,REMOTE_ADDR";
$clientIpAddress = "";
# Loop through parameters
$mylist = explode(',', $searchList);
foreach ($mylist as $myItem) {
# Is our list set?
if (isset($serverVars[trim($myItem)])) {
# Loop through IP addresses
$myIpList = explode(',', $serverVars[trim($myItem)]);
foreach ($myIpList as $myIp) {
if (filter_var(trim($myIp), FILTER_VALIDATE_IP)) {
# Set client IP address
$clientIpAddress = trim($myIp);
# Exit loop
break;
}
}
}
# Did we find any IP addresses?
if (trim($clientIpAddress) != "") {
# Exit loop
break;
}
}
# Default (if needed)
if (trim($clientIpAddress) == "") {
# IP address was not found, use "Unknown"
$clientIpAddress = "Unknown";
}
# Exit
return $clientIpAddress;
}
I'm taking user input of their downloadable files, where they can be uploaded-
to their own server (i.e.: example.com/files/filename.ext)
or, to a remote one. (i.e.: external.org/someone/somewhere/filename.ext)
As I's trying implementing a download button (with some process), then I came to know that file downloading from remote server is not like so. That's why I need to check whether a URL is of my own server or from an external one.
If I can differentiate between both then with a simple conditional I can pass the flow to whether:
an on server way
or, an off server way
Get hostname from file URL and compare with your web hostname
$fileHost = parse_url("example.com/files/filename.ext", PHP_URL_HOST);
//$fileHost == "example.com"
if($fileHost == $myHost)
{
//this is local file
}
else
{
//this is external file
}
you can let your PHP to get $myHost with
$myHost = $_SERVER['HTTP_HOST'];
http://php.net/manual/en/function.parse-url.php
I'm trying to get the Public IP of someone that use the form of the page I do.
I don't know with which programming language would do that. I was reading on the web and I found some:
// PHP Code
$_SERVER["REMOTE_ADDR"]
This outputs: 127.0.0.1 (Local IP).
Then I found this too:
// PHP Code
$externalContent = file_get_contents('http://checkip.dyndns.com/');
preg_match('/\b(?:\d{1,3}\.){3}\d{1,3}\b/', $externalContent, $m);
$externalIp = $m[0];
This outputs the correct IP (Public IP), but that needs to use other web page (http://checkip.dyndns.com/).
I wonder How do the pages like that get the Public IP?. I am looking for a way to get it without need to use other web page. Thanks.
The $_SERVER["REMOTE_ADDR"] should work fine for what you are trying to do here. The reason you are getting 127.0.0.1 is because you are running this in a local environment.
If you put this script on a live webserver and I access it, you will get the same IP from $_SERVER["REMOTE_ADDR"] as I get when I check whatismyip
And anyhow, having the server call:
$externalContent = file_get_contents('http://checkip.dyndns.com/');
will only get you successful in returning your servers IP address, not the visitors.
This problem had me stumped for a long while.
If you have access to your own remote server, what I did to solve this problem was create a simple server-side script echo $_SERVER['REMOTE_ADDR']; to give me the public IP assigned by my ISP to my device from my localhost.
I run security checks on a number of AJAX calls to see if the same IP requested that I have on record.
I used the following set of class functions to establish the IP (which can come via load balancers, hence the lengthly methodology.
private function IPMask_Match ($network, $ip) {
$ip_arr = explode('/', $network);
if (count($ip_arr) < 2) {
$ip_arr = array($ip_arr[0], null);
}
$network_long = ip2long($ip_arr[0]);
$x = ip2long($ip_arr[1]);
$mask = long2ip($x) == $ip_arr[1] ? $x : 0xffffffff << (32 - $ip_arr[1]);
$ip_long = ip2long($ip);
return ($ip_long & $mask) == ($network_long & $mask);
}
private function IPCheck_RFC1918 ($IP) {
$PrivateIP = false;
if (!$PrivateIP) {
$PrivateIP = $this->IPMask_Match('127.0.0.0/8', $IP);
}
if (!$PrivateIP) {
$PrivateIP = $this->IPMask_Match('10.0.0.0/8', $IP);
}
if (!$PrivateIP) {
$PrivateIP = $this->IPMask_Match('172.16.0.0/12', $IP);
}
if (!$PrivateIP) {
$PrivateIP = $this->IPMask_Match('192.168.0.0/16', $IP);
}
return $PrivateIP;
}
public function getIP () {
$UsesProxy = (!empty($_SERVER['HTTP_X_FORWARDED_FOR']) || !empty($_SERVER['HTTP_CLIENT_IP'])) ? true : false;
if ($UsesProxy && !empty($_SERVER['HTTP_CLIENT_IP'])) {
$UserIP = $_SERVER['HTTP_CLIENT_IP'];
}
elseif ($UsesProxy && !empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
$UserIP = $_SERVER['HTTP_X_FORWARDED_FOR'];
if (strstr($UserIP, ',')) {
$UserIPArray = explode(',', $UserIP);
foreach ($UserIPArray as $IPtoCheck) {
if (!$this->IPCheck_RFC1918($IPtoCheck)) {
$UserIP = $IPtoCheck;
break;
}
}
if ($UserIP == $_SERVER['HTTP_X_FORWARDED_FOR']) {
$UserIP = $_SERVER['REMOTE_ADDR'];
}
}
}
else{
$UserIP = $_SERVER['REMOTE_ADDR'];
}
return $UserIP;
}
The Problem is I've been getting problems with users operating via a proxy. Can anyone indicate why that might be? I've used basic free proxy's online to try and emulate, but it doesn't look to be getting variable IPs or anything - so I'm not sure why this would be saying the two IPs don't match.
I am going to explain what a proxy is first so we are both on the same page.
What Is A Proxy
A proxy is usually a single computer that accesses the internet ON BEHALF OF the user and then the proxy sends the results back to the user. The problem appears when there could be hundreds or even thousands of other people also using that one computer - and they all have the SAME IP address but normally the headers indicate that the users are via a proxy.
Your script i am assuming (without properly looking) is getting the IP's and headers mixed up.
Different Solution
There is a better way. Use sessions and save a key in the session ensuring they have previously been to the main site first BEFORE accessing the ajax page. Example:
index.php
session_start();
$_SESSION['ajax_ok'] = true;
ajax/username_check.php
session_start();
if (empty($_SESSION['ajax_ok'])) {
die("You can not access this page...");
}
That will enforce that they must visit your main site first and the client must also support sessions which most browsers will which is a plus to help prevent bots etc abusing your ajax scripts.
More reliable and easier solution than using that mangle of code you got above ><
What if you can't use sessions?
If you can't use sessions on the specific comp you're on, you could setup another computer, rewrite the session handler (using the callbacks that php provides) or instead of using the file system use something else like the database for sessions instead? There must be something your website uses that the sessions could also use. Such as if you have a load balancer file based sessions generally wont work anyway so it's generally a good idea to change the sessions to use something else like i mentioned above.
The problem unfortunately almost certainly isn't a proxy - it's almost certainly a stationary public IP router, routing traffic through a subnet.
And subnets can be HUGE (say, at universities).
And even if it was by some fluke a genuine proxy (they are rare these days - 10 year old tech), even if the proxy volunteers to forward, it won't happen to mean anything because it's almost certainly a subnet ip like 192.168.x.x anyway.. This is basically the public IP address (aka switchboard) internal extension.
You could cross your fingers and try php ipv6 Working with IPv6 Addresses in PHP or even be even more clever and try mac address How can I get the MAC and the IP address of a connected client in PHP? but both are doomed to failure. My gut instinct is to try to cheat: I would gamble that the best way is basically using a network share for the session store and allowing the load balanced PHP servers to all access it and do everything via the same dns prefix. Or perhaps set up a 3rd party dns for doing the sessional gathering.
The answer is that unless you track with "cookies" like your an ad agency you can't do it.
A friend identified this, basically some proxy's can come back with X_FORWARDED_FOR as a comma separated value OR as comma separated and spaced.
To fix:-
after:
foreach ($UserIPArray as $IPtoCheck) {
add this line:
$IPtoCheck = trim($IPtoCheck);
Sorted.
The Problem is I've been getting problems with users operating via a
proxy. Can anyone indicate why that might be? I've used basic free
proxy's online to try and emulate, but it doesn't look to be getting
variable IPs or anything - so I'm not sure why this would be saying
the two IPs don't match.
Your parsing code explodes HTTP_X_FORWARDED_FOR on comma, but separator may be "comma space". If that happens, the RFC 1918 check will fail. While some proxies do not add space, the standard is to use it:
http://en.wikipedia.org/wiki/X-Forwarded-For
The general format of the field is:
X-Forwarded-For: client, proxy1, proxy2
where the value is a comma+space separated list of IP addresses, the
left-most being the original client, and each successive proxy that
passed the request adding the IP address where it received the request
from. In this example, the request passed proxy1, proxy2 and proxy3
(proxy3 appears as remote address of the request).
So you ought to change the explode separator to ", ", or better, use preg_split with ",\s*" as a separator and cover both cases.
Then, your problem is to authenticate the page doing the call in AJAX to the AJAX call itself.
If you don't want to use cookie-based sessions, which is the best way, you can try and do this with a nonce. That is, when you generate the page, you issue a unique ID and inject it into the HTML code, where the AJAX code will recover it and pass back to the AJAX servlet. The latter will be able to add it in Access-Control-Request, as detailed here, or just add more data to the request.
I'd like to discuss whether your solution does anything on behalf of security.
$_SERVER['REMOTE_ADDR'] cannot be forged. It is set by the webserver because of the accessing IP address used. Any response goes to this address.
$_SERVER['HTTP_FORWARDED_FOR'] and $_SERVER['HTTP_CLIENT_IP'] can easily be forged, because they are HTTP headers sent to the webserver - neither will you know you are talking to a proxy if it is configured to omit these headers, nor will you know you are NOT talking to a proxy if a client decides to insert these headers.
Filtering based on the IP address FORGED will not really help you, but this highly depends on the stuff you want to achieve - which remains unknown until you go into more detail there.
If you look around, you will stumble upon the Suhosin patch and extension for PHP, and it's feature to encrypt the session and cookie content. The encryption key is built by using some static key, but adding stuff like the HTTP User Agent or parts of the requesting IP address - note: The IP used to actually make the request, i.e. the proxy if one is used, because this is the only reliable info.
One can argue that using the full IP address is not a very good idea unless you know your users do not use proxy clusters with changing IP addresses for multiple requests, so only a part of the IP would usually be used, or none at all.
The HTTP User Agent though is a nice source of unique information. Yes, it can be forged, but that does not matter at all, because if you only want to allow requests from the same source, it is valid to assume that the user agent string does not change over time, but will be different for a bunch of other users. Hence there are statistics that show you can generate a nearly unique fingerprint of a browser if you just look at all the HTTP headers sent, because every user installs different extensions that change something, like accept-content headers.
I cannot provide working code, nor can I tell from your question whether any of this answer applies, but I'd suggest not using the IP info, especially if it can be forged. This is even more valid if you think about IPv6, where every client has multiple active addresses even on the same interface, and they are all randomly generated and highly unlikely to ever occur again later in time. (Of course this does not apply if you are never gonna host on IPv6, but at some point you'll be out of users then.)