PHP detecting human browser in cron job - php

I want to prevent users from running my cron job manually. Apart from using an unpredictable filename I want to have some sort of check in code.
Obviously using any clientside headers is a waste of time so I thought the easiest way around this would be to detect the presence of $_SERVER['SERVER_NAME'] which as far as I know is not set in CLI.
Are there better ways of doing this?

Have a look at php_sapi_name. It returns the type of interface between web server and PHP.
Example:
<?php
if(php_sapi_name() == 'cli') {
// CLI
}
else {
// HTTP
}
For more information, and additional examples, have a look at http://www.electrictoolbox.com/determine-php-run-via-http-or-cli/.

in your .htaccess
Options -Indexes
order allow deny
deny from all
allow from YOUR SERVER IP ADDRESS ONLY

Check for IP address, if its local, or server ip then run it, otherwise return.
$ip = getenv('REMOTE_ADDR');

My cron jobs are in a folder that is password protected using htpasswd. You can set an easy password and be sure nobody will lose his time trying to access it. I don't use any IP-based techniques because this is a server dependency I don't want to have.

Related

verify a website by uploading a file can be spoofed?

In my website i have a website verification process based on a file
The user has to upload in his root directory a empty file with a filename like this:
site-verification-$user_id.html
then my script use the php get_headers() function to check if this file exist, for example:
$headers = get_headers( "$user_website/site-verification-$user_id.html" );
if( preg_match( "|200|", $headers[0] ) { // ... website verified
everything works fine, but my question is, can this process be spoofed?
Yes, actually it's really easy to trick this mechanism. You just have to set up a webserver to catch all requests (e.g. via Apache's mod_rewrite configuration) and answer every single one of them with a valid response including HTTP-Status-Code 200 - pretty easy to set up.
If the User-Agent and/or IP of your webserver is known it would even be possible to lie specifically to your server while keeping up correct responses to all other visitors.
To be sure that this doesn't happen, you should give the user a randomly generated key that is then required as the content of the named file. You should then save the filename and the key in a DB and check both for compliance (analogous to how you would handle a combination of username and password).
This method is similiar to e.g. how you authenticate as the owner of a domain at Google Webmaster Tools. You can be pretty sure that only someone with access to the server can deposit this code at the specified address.
Keep in mind that "someone with access to the server" might still be someone without legitimate access. Also, an attacker executing a MITM attack between your own server and the server you are checking could send back whatever is needed to fool your server. Well, but then everything is lost either way.

How do you monitor a file on a web server and log every access, ideally by IP address, in a database (MySQL)?

For security reasons, there is a certain file on my web server I want to be able to monitor access to. Every time it is accessed, I want to have an entry added to a MySQL log table. This way, I can actively respond to security breaches from within the web application.
The Apache HTTP Server provides logging capabilities.
The server access log records all requests processed by the server. The location and content of the access log are controlled by the CustomLog directive. The LogFormat directive can be used to simplify the selection of the contents of the logs. This section describes how to configure the server to record information in the access log.
It can be used to write the log to a file. If you need to store in a MySQL table, run a cron job to import the file into the database.
Further information on logs is here:
http://httpd.apache.org/docs/1.3/logs.html#accesslog
Its been removed from PHP7 but for anyone else who finds this post there are a number of options within the FAM (now PECL) extension. This function http://php.net/manual/en/function.fam-monitor-file.php seems to describe what is needed here
Additionally you can access a lot of detail about the files status with http://php.net/manual/en/function.stat.php. Put this within a cron or sleep driven script and you can then see when its changed.
The file may be accessed from three points:
Direct filesystem access
Call to the url like www.example.com/importantfile.jpg (apache serves the file)
Call to some php script on your server www.example.com/readfile.php?name=important.jpg which reads the file.
If you are concerned only about case 2 then check the solution of Rishi Dua.
But if you want more than that then you should write a script with fileatime() call and then add it to cron to run every minute for example.
The pseudocode for it:
<?php
$previous_access_time = get_previous_access_time(); // get the previous last access time from you remembered in db or textfile or whatever
$current_access_time = fileatime('path/to/very_important_file.jpg');
if ($previous_access_time != $current_access_time) {
log_access_to_db();
save_new_access_time(); // update the new last access time
}
This solution however has some problems.
First is that you can get only the access time but not the user-id or ip of who accessed the file.
Second is that as the manual says, some Unix system do not update the access time and so the solution would fail.
If you are seriously concerned about the security, then I think you have to check for some audit util like this

Check if PHP is running in local server

Well. I read some topics in SO but I not found a very specific answer.
I need to check with PHP if a PHP code is running in local or remote host. Currently I check with $_SERVER['SERVER_NAME'] but it is inconsistent. In this case, if I run PHP with listed IPs like 127.0.0.1 or localhost it'll consider local, otherwise remote. If I share my IP with a friend, my code still local, but it consider remote because the shared IP isn't listed.
Well, I think that check IP for localhost is not a good idea (except if you know a good method). I tried methods like gethostbyaddr() and gethostbyname() but don't work correctly too.
I don't have a PHP code to show, but my code is basically that:
// true = localhost
return $_SERVER['SERVER_NAME'] === '127.0.0.1';
The fundamental question is: what can determine that PHP is running local? What is "local" for PHP? I think that it can solve the problem.
Obs.: I don't have access to CMD/Shell with PHP.
You could do what most PHP frameworks do and set a flag during your app's bootstrap phase that defines which environment the code is running in. In it's simplest form:
// the setting when run on a dev machine
define('ENV', 'local');
Then it's a simple case of:
if ( ENV == 'local' )
{
// do stuff
}
This is how I do it, which I find more reliable than trying to detect for 127.0.0.1:
if( strpos(gethostname(), '.local') !== false ) { }
Basically, the hostname's on my workstations all have .local appended to it. You can change this to match your workstation's hostname entirely.
Check $_SERVER['REMOTE_ADDR']=='127.0.0.1'. This will only be true if running locally. Be aware that this means local to the server as well. So if you have any scripts running on the server which make requests to your PHP pages, they will satisfy this condition too.
If someone is visiting your site via the web, the IP address you see will never be 127.0.0.1 (or ::1 for IPV6), regardless of the usage of a proxy. (Unless of course you're running the proxy yourself on the same server ;)
As far as I know, only you will be able to know what addresses are local or not. Your network could be set up with IP addresses that don't look local at all. PHP cannot as far as I know determine this by itself.

Accepting get/post requests only from localhost

Because the data size isn't little that my web app needs to load, it gets pretty slow some times so therefor I decided to add some jQuery ajax functions to load certain data upon request and then save it in a cache.
What I would like to know is how can I limit any GET or POST requests only from localhost/same server/same ip so I can avoid any calls from outside to my app?
That means that my php functions that returns data, should return data only if requested from localhost.
My web app runs on CodeIgniter's framework and my web server's configuration is a LAMP running on ubuntu.
Any ideas?
in the constructor you could use
if ($_SERVER['SERVER_ADDR'] != $_SERVER['REMOTE_ADDR']){
$this->output->set_status_header(400, 'No Remote Access Allowed');
exit; //just for good measure
}
However if this method isnt what you're looking for.. use .htaccess you can perform a quick google search to return a specific example for denying get/post to all and then allow for 127.0.0.1/localhost.
Using .htaccess is probably the best way, allow only from your local address and 127.0.0.1.
I found this example at petergasser.com and changed it only slightly:
AuthName "bla"
AuthType Basic
<Limit GET POST>
order deny,allow
deny from all
allow from 127.0.0.1
allow from <your-ip-here>
</Limit>
Use a key (think of API keys) to send along the request to your server. Then on your server you check that key and if it's the right one you return data.
I use like this, thanks to #gorelative
if(
isset($_SERVER['REMOTE_ADDR']) AND ( $_SERVER['REMOTE_ADDR'] !== $_SERVER['SERVER_ADDR'] )
){
die(' Access Denied, Your IP: ' . $_SERVER['REMOTE_ADDR'] );
}

Serve a large file via Zend Framework

In our application, authentication is handled via set of Controller Plugins that validate the user etc.
I want to serve a large (video) file only to authenticated users- the obvious way to do this is via readfile() in the controller, but I'm finding it hits the PHP memory limit - presumably the output from the controller is buffered somewhere.
How can I turn off buffering just for this one controller?
EDIT: Thanks for all the useful tips about flushing any existing output buffering - I guess I was specifically looking for a way of doing this within the framework though?
Interesting problem... You could try:
// ...
public function largeFileAction()
{
// this clears all active output buffers
while (ob_get_level()) {
ob_end_clean();
}
readfile('path/to/large/file');
exit(); // to prevent further request handling
}
// ...
Ok, I might be totally wrong here, but I think to have read somewhere OB has to be enabled for ZendLayout and placeholder helpers to work, so you'd have to disable them for the downloadAction (you probably aint gonna need them for serving the file anyway).
Would something like this achieve what you want to do?
class DownloadController
{
public function downloadAction()
{
$this->_helper->layout()->disableLayout();
$this->_helper->viewRenderer->setNoRender(true);
// authenticate user if not done elsewhere already
header( /* ... the usual stuff ... */);
filepassthru(/* some path outside webroot */);
exit;
}
}
As Tyson wrote, your best choice (if you have full control over the server) is to validate users credentials and redirect him (302 temporary redirect) to the URL where he can download the file.
To prevent reuse of this URLs we are using Lighttpd and its mod_secdownload that allows you to generate a hash that is valid for the specified amount of time.
nginx has X-Accel-Redirect and Apache has mod_xsendfile.
If you decide to implement a separate lightweight web server there are other benefits as well (mainly lower memory consumption while serving static files and faster response times).
If you decide to go this route you will either have to add another IP address to the server and bind Apache only to the one IP address, and the other server (lighty of nginx) to the other because they are web servers the both listen on port 80. And changing the port for one of the servers is not a good idea because a lot of people do not have access to higher ports.
If adding another IP address is not an option you can install nginx on port 80 and use it as a reverse proxy to pass the dynamic requests to Apache which can listen on another port and serve all of the static files.
Considering using an external script to output the file, and stream it to the browser using PHP's passthru function.
If on a Linux-based system, you could try something like passthru("cat video_file.flv");
However, a better practice is to avoid this streaming (from within PHP) altogether and issue the client a 301 HTTP redirection to the URL of the actual static resource so that the webserver can handle streaming it directly.
I don't think you can actually. As far as i know php buffers all output before sending it to the requester.
you could increase the memory limit using ini_set()
$handle = fopen('/path/to/file', 'r');
$chunk_size = 8192;
while ($chunk = fread($handle, $chunk_size)) {
echo $chunk;
ob_flush();
}
This will probably need some tweaking, such as adding correct headers and reading in binary mode if necessary, but the basic idea is sound. I have used this method successfully to send 50+ MB files, with a 16 MB PHP memory limit.

Categories