Jump to content

Recommended Posts

I have two servers: WebServer and FaxServer.  WebServer needs to send a fax.  Is my approach shown below fairly secure?

Before sending a fax, ServerWeb needs to store a record in a table representing the message, and I am using a pseudo random value for the PK which is generated as 2147483648+mt_rand(-2147483647,2147483647).

WebServer then generates a hash equal to hash('sha256',$pk.'secretCodeWhichOnlyWebServerAndFaxServerKnow').

WebServer then sends curl request to FaxServer using POST which includes $pk, the hash, the fax number, some text to include in the fax, and an optional array of document to include (array(array('id'=>321,'name')=>'fileName.pdf')).

FaxServer verifies that the hash is correct given $pk, that the minimum information has been received, and that the fax number is a valid phone number, and quickly responds to WebServer by echoing 0 or 1 so the code in the WebServer could continue and inform the user.  If all looks okay, a new instance of PHP is started.
 

if(missingInformation) {echo(0);}
else {
   session_start();
   $_SESSION['_xfr']=$_POST;
   exec('/usr/bin/php -q /path/to/send_fax.php '.session_id().' >/dev/null &');
   echo(1);
}

New instance of PHP send_fax.php then does the following:
 

session_id($argv[1]);//Set by parent
session_start();
$data=$_SESSION['_xfr'];

$doc_list=null;
foreach ($data['documents'] AS $doc)
{
    if(ctype_alnum($doc['id']))
    {
        $file='/some/tmp/directory/'.$doc['id'];
        if(!file_exists($file))
        {
            $url='http://machine.WebServer.com/index.php?task=displayDocument&id='.$doc['id'].'&x='.hash('sha256','displayDocument'.$doc['id'].'secretCodeWhichOnlyWebServerAndFaxServerKnow');
            $cmd='wget -O '.$file.' '.escapeshellarg($url);
            exec($cmd);
        }    
        $doc_list.=' '.$file;
    }
    exit('invalid document');
}

//Send the fax...

//Send another CURL request to the WebServer similar to the wget giving the fax status.
exit;

When WebServer receives the wget request for a document, it confirms the hash and sends the document to the FaxServer using X-Sendfile.

When WebServer receives the CURL request regarding status, it updates the database for the applicable message.

 

Seem reasonably secure?
 

First of all: Inventing your own security protocol makes no sense, even if it only needs to be “fairly secure” (whatever that means).

 

Coming up with your own stuff usually takes more effort than simply setting up a proper HTTPS connection, custom protocols are almost always fundamentally flawed (yours is), and it's not even possible to reliably estimate their strengths and weaknesses. I mean, even if I told you that your approach is “fairly secure” (which I don't), that wouldn't mean anything. Protocols are evaluated by teams of experts, not a bunch of random guys in a PHP forum.

 

Just use HTTPS with self-issued certificates. It's easy to set up, it doesn't cost anything, and it provides solid security. Knowing how to do this is also a very important ability which will probably help you in the future.

 

 

 

As to your protocol:

 

The first fundamental issue is that you haven't defined the goal (or at least you haven't told us). What does “fairly secure” mean? Which threats are you trying to protect against, and which threats are you willing to accept? We can't evaluate a protocol if we don't even know what it's supposed to do.

 

Generally speaking, there are several issues (or properties, if you will):

  • The protocol (obviously) provides no confidentiality, so an eavesdropper can read all data going back and forth.

  • An eavesdropper can also record valid requests an replay them.

  • The hash stuff is dubious at best and uses common anti-patterns. While you've been lucky(?) enough to avoid the even worse construction SHA256(key + message), your variation is highly vulnerable to hash collisions. Granted, there are currently no known SHA-2 collisions. But that's still not an excuse for using a broken scheme instead of a standardized construction like HMAC.

  • If you do the hash validation in a naïve way like $provided_hash == $expected_hash, you'll reveal the key through time differences.

The whole idea really only makes sense if you assume that passive eavesdropping is no problem at all (is this reasonable?). But then why do you think that active attacks are a problem? Active attacks are generally more difficult than passive attacks, so it's odd to assume that an attacker can do the former but not the latter.

 

Or maybe you just want to authenticate the client so that a random visitor cannot simply download a document? Then you might as well use a plain password.

 

Again, without a concrete definition, the whole exercise is pointless from the beginning.

Edited by Jacques1

My goals are:

  1. Prevent any access to the fax server except from the webserver application.  A user will interact with the webserver, and the webserver application will assure the user is authorized.
  2. Prevent the ability to download files from the webserver except by the faxserver (or by other parts of the webserver application, but let's ignore this as it is not relevant).

 

I planned on using HTTPS after I get some basic concept working.  I never used HTTPS with CURL, and didn't know if I would have challenges.  Also, while I've implemented HTTPS with self signed certificates between a browser client and a webserver, I've never done so between two servers and didn't know the challenges.

 

Yes, HTTPS would prevent eavesdropping, but how would it protect against some just sending a HTTPS request to the faxserver and sending an unauthorized fax, or sending a HTTPS request to the webserver and downloading a file?  Unless, should I just include a plan text password in the POST, and use HTTPS so that it can't be viewed?  And if I use HTTPS, is even HMAC required?

 

Also, not necessarily security related, but any advice or constructive criticism about the other parts of my implementation would be appreciated.

Edited by NotionCommotion

Once you've established an HTTPS connection, you can safely use classical password authentication. So you generate a random password on the web server, store its hash on the fax server (plain SHA-256 is enough), and now the web server has to include the password in every request. You do the same thing in the other direction.

 

HTTPS also supports mutual public key authentication: We all know server certificates, but there are also client certificates which can be used to authenticate the client. This is more secure than passwords, but it's a bit more effort to set up if you've never done it before.

 

HTTPS doesn't require any additional HMAC stuff. It automatically protects against eavesdropping, data tampering and even replay attacks (it's not possible to record a valid request and then send the same data again).

 

 

 

Also, not necessarily security related, but any advice or constructive criticism about the other parts of my implementation would be appreciated.

 

Personally, I'm a fan of cleanly designed APIs and standardized protocols like JSON-RPC, so the whole approach looks a bit hacky to me.

 

Sure, wget and echo are theoretically enough to make two parties communicate over HTTP(S). But once things get more complex, you may regret that choice and wish for an actual API with proper error handling etc.

 

It really depends on the job. Do you just need a quick hack so that you can move on? Or is this a serious task which is worth some extra effort?

In regards to storing the hash of of the password on the other server, I suppose it could be hardcoded into some configuration file, right?  And, not the same password (and associated hash) for both directions?

 

Just read up on HMAC and was excited to use it.  Oh well, will do so next time.  Just curious, would one ever include the IP of the server in the message so that the password would only work from a given IP?  Proxies and the like will probably be an issue, so likely not a good idea.

 

Yea, it is a bit hackish, but I just need to get it down quick, and could later improve.  I've decided on going away with my ugly passing data from one PHP instance to another via a session, and will either pass it as an argument (assuming it is not too much data), or maybe better yet have the script respond but continue to execute by sending the appropriate headers.

I would build an api using https, json responses, checking $_SERVER['REMOTE_ADDR'] and hard coding a relatively secure password.

If multiple users can make a public and also private api key system.

Make yourself a script acting as the front door.

Include anything considered not for public view from outside the servers root folder if passes.

I'm not sure if IP checks are a good idea. They provide very little protection, and the IP must be kept up-to-date for the lifetime of the application. The check may also break entirely if the server architecture changes (e. g. Apache running behind a front end server and receiving the server IP rather than the client IP).

 

If you are and will be in full control of the server, sure, you can use this as additional protection. But otherwise it probably causes more harm than good.

 

 

 

In regards to storing the hash of of the password on the other server, I suppose it could be hardcoded into some configuration file, right?

 

Yes.

 

 

 

And, not the same password (and associated hash) for both directions?

 

Two separate passwords. If one password gets compromised, then at least the other password is still intact.

 

If you used the same password, then the hash would actually be rather useless, because the plaintext would be sitting right next to it.

Edited by Jacques1

Yes, make sure you setup HTTPS between the servers. That is your main protection. If you want to just use a self-generated certificate that is fine, you'll just need to tell curl to accept certificates from your custom CA. You can do this with the CURLOPT_CAINFO option. You also want to ensure that CURLOPT_SSL_VERIFYPEER is enabled.

 

$ch = curl_init($url);
curl_setopt($ch, CURLOPT_CAINFO, '/path/to/caroot.pem');
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true); 
//...
Once HTTPS is up and running, you could just use something as simple as HTTP Basic Auth rather than have to code specific verification procedures into your application.
  • Like 1
This thread is more than a year old. Please don't revive it unless you have something important to add.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.