Page 1 of 1

API: please recommend transport and security options

Posted: Fri Apr 11, 2008 11:44 am
by georgeoc
Hi all.

This is something of a follow-up on this topic, but is sufficiently different to require a new thread! As I have explained before, my app links together different web-based messaging systems (email, bulletin boards, blogs, RSS, etc) under a single interface.

I'd like it to be as flexible, modular and as useful as possible. A big part of it will be interfacing with 3rd-party code (for example, phpBB). One conundrum I've come across is collisions between function and class names in this code. For example, in order to mirror posts from a phpBB2 forum to a phpBB3 forum (yes, some people want to!), I'd normally have to include code from both packages into the scope of my application. My app, sitting on the user's server, would be triggered by a post in a phpBB2 forum (the phpBB2 functions are therefore defined in the global namespace), but would later need to include() the phpBB3 files in order to make the post. This is asking for trouble - there are many repeated function names between the two packages.

I have a working solution, but I'm not happy with it for a number of reasons. It parses the 3rd-party files I need, changes all function and class names to unique strings for that package instance, performs other substitutions such as global variables, and stores the parsed files in a cache to be included when needed. The problems with this theory:
  • It's very hard to make my parsed files bug-free, and developing the parser for each 3rd-party app takes ages
  • This is only a solution for apps on the same server as my app, which substantially limits the usefulness
The solution only struck me today as I cycled home, and I can't believe I hadn't thought of it before. I propose to write a small file for each 3rd-party app I want to support, to be added to the application directory and hooked in to be triggered by each new message. When triggered, it will package up the message contents, and send them via some kind of web service to my app. For exporting, my app will contact the file on the foreign server and deliver a similarly packaged message.

Having never done this kind of thing before, I'd like to ask for advice on the best approach. Don't worry about the formatting of the message - all that is taken care of. Instead, the issues I can think of are speed and security. Obviously the speed depends on internet connection quality, but I'd like advice on the fastest transport mechanism available in PHP, bearing in mind the message contents may possibly include attachments. Security is the big one - if I'm distributing an app which encourages a user to place a file on their server that enables a phpBB forum post to be made from a foreign server, I need to be absolutely certain that the connection between the two servers is secure and private.

So, I'd like some advice on the best transport option (including ideas for how best to compress the message) and the security for the connection, including authentication, hashing, salting, encryption, challenge-response, etc. (I'm a bit of a novice with securitiy considerations). Although I have required PHP 5.2 for my app, I'd like to avoid non-standard PHP modules and extensions where possible in order to cater for a wide community of users (the instance of my app will be hosted by the user, rather than by me).

I'm by no means looking for code; more a bullet-list of things to consider, and links to forum discussions and/or tutorials where I might do some research. Many thanks for your help!

EDIT: API is the word I've been looking for. Any links to good tutorials on the subject?

Re: Please recommend transport and security options

Posted: Fri Apr 11, 2008 11:50 am
by georgeoc
Is curl the best solution? If so, which protocol should I use?

What percentage of hosts are likely to have the extension enabled?

Re: Please recommend transport and security options

Posted: Fri Apr 11, 2008 11:53 am
by georgeoc
I also thought I should note that I'm using the Zend Framework for my app, so will have access to those libraries if necessary.

Re: API: please recommend transport and security options

Posted: Sat Apr 12, 2008 8:34 pm
by georgeoc
While waiting for some suggestions, I've put together a proof-of-concept. This script actually posts to itself, but you should think of the two halves of the script as being on two separate servers.

I wanted to explore a few things:
  • using cURL for the first time
  • I'd like the connection to be closed as soon as the message has been transferred, to allow both threads to continue working separately after the transfer (i.e. "END****" is never displayed to the browser in my example). I hacked together some lines which work for me - I'd love a suggestion for the best way to do it.
  • A basic system for authentication. I'd like to know where the weaknesses are. The secret would be stored on each server in a secure way, and would be unique for each client that tried to connect to the server. I'll eventually replace md5() with feyd's SHA algorithm.
I'd very much appreciate some feedback on which parts I need to improve for a secure system. Note that I propose to do this via a SSL connection eventually.

Code: Select all

<?php 
 
$thisUrl = 'http://' . $_SERVER['SERVER_NAME'] . $_SERVER['SCRIPT_NAME'];
 
if (empty($_POST)) // CLIENT
{
    $user = 'user2';
    $secret = 'mine is better!';
    
    $message = 'test message';
    $signature = md5($secret . $message);
 
    $ch = curl_init(); 
    curl_setopt($ch, CURLOPT_URL, $thisUrl); 
 
    // return the data in a string from curl_exec()
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); 
    
    $curlPost = 'user=' . urlencode($user) . '&message='  . base64_encode($message) . '&signature=' . urlencode($signature); 
    curl_setopt($ch, CURLOPT_POSTFIELDS, $curlPost);
    
    $data = curl_exec($ch); 
    
    if (false === $data) print_r(curl_error($ch));
    print_r($data);
    
    curl_close($ch); 
}
else // SERVER
{
    // set the HTTP session up to be closed later, rather than persistent
    header("Connection: close");
    ob_start();
    
    $secrets = array(
        'user1' => 'my little secret',
        'user2' => 'mine is better!',
        'user3' => 'I win!'
        );
    
    $user = $_POST['user'];
    $secret = $secrets[$user];
    
    $message = base64_decode($_POST['message']);
    $expected = md5($secret . $message);
 
    if ($expected === $_POST['signature'])
    {
        echo 'OK: ' . $message;
    }
    else
    {
        echo 'bad';
    }
 
    // send the content-length header so the browser thinks we're finished
    $size = ob_get_length();
    header("Content-Length: $size");
    ob_end_flush();
    flush();
    
    // now the script has closed the connection, and can continue processing the message
    sleep(5);
    echo 'END****';
}
 
?>