I’m running a cronjob which needs to write data to a cache. I wanted to put this cronjob in my private folder, however, even after CHMODding the cache folder in the private folder, it’s not getting writing rights. This seems to be somekind of plesk feature.
So, now I’ve placed the cronjob in the public folder. However, I need to make sure that only the server can execute the script. What about the following at the top of the cronjob?
if ($_SERVER['SERVER_ADDR'] != $_SERVER['REMOTE_ADDR']) die();
This seems to work. Is it not exploitable however, eg. can a user manipulate his remote_addr to my server’s? Or is there a better way to check this?
Another issue I have is that the above code is returning 2 warnings, even though it does seem to work:
PHP Notice: Undefined index: SERVER_ADDR in ... on line 2
PHP Notice: Undefined index: REMOTE_ADDR in ... on line 2
Any idea what’s the cause of that?
3
Answers
First, I would keep the executable PHP script in a private directory that can only be executed by the privileged user – and schedule it in the cron for that user. You should have no problems executing the script.
Second, you can change where you are writing the cache data to a public directory. It would be preferable to keep this in a non-public directory, but if you cannot figure out how to do it otherwise, and the data is okay to be public, then it is probably okay.
Finally, using $_SERVER[‘SERVER_ADDR’] and $_SERVER[‘REMOTE_ADDR’] is probably not the best way to check to see if the server is running the script. For one, I believe that $_SERVER[‘REMOTE_ADDR’] will not be set when running a command-line PHP script. This is taken from the HTTP headers, and since there are none, it will be empty. In fact, this is why you are getting the warnings – these are not set. (edit: looking at the PHP docs, it is likely that the ‘SERVER_ADDR’ variable will not be set for non-browser scripts)
Execute the script via the console, not the web server.
The cron could look like this:
Then the file could do this:
That will guarantee it’s only run by the server.
Edit in response to comments
You can’t get to a public folder inside a private folder, in general, and if you can’t add new directories outside the web root, your cache dir will have to be protected another way.
I’m going to assume all your files are in the web root, ie:
/home/site/publichtml
. Replace that with whatever your directory is.Create a new directory
/home/site/publichtml/.cache
. Add the following as a .htaccess file:Now your scripts should be able to access the folder from the file system, but it’s inaccessible via the web server.
If you can set up a cron job on the server (via the web admin or another way, it sounds like you can) do it as above, ie: Use
php -f /home/site/publichtml/cron.php
as the command, and include the check for the array key.Alternatively, you can check like this:
$_SERVER['argc']
is only set when the script is executed from the command line.If you can keep the cron script out of the web root, good. If not, that should be secure.
Finally, to get rid of the E_NOTICES, add this to the top of the cron.php:
or
I think the answer is hidden in your first reply from jon.
So if you only want this script accessed via cron, check for the existence of the session superglobals:
And, just because it’s easy, create a
.htaccess
file and do an deny-all.I typo’d the $_SESSION as $_SERVER, my bad. That works for your needs.