I've also posted this in the code critique forum.. and I generally do NOT "repost" stuff in another forum.. however, in this case I think (I hope) is's okay (mods.. if not, by all means, please delete appropriately :p) -- Anyway...
I'll start out by saying that while I consider myself to be extremely proficient in PHP, I also know that there are PLENTY o' folks out there much more "proficient" than myself! That said, let me give a little background and then get to the point.
I'm about to launch an entirely new concept in search engine technology (at least I think it is :p) While ask.com is kinda similar to what I'm about to launch, it is not altogether the same... in truth, not the same at all. I've recently built "AToM"... and AToM is what's at the core of the search engine site I'm about to launch. At any rate, this isn't about the site, but rather the code behind some of it.. so here.. down to it..
I've got some areas of the site (Developers Corner, Control Panel, Private On-Site Email, Etc...) that I need protected. Basic auth is simply not secure enough to suite me and right now no SSL is available (64-bit system -- everything EXCEPT friggin' OpenSSL! :p) -- At any rate, here's how it needs to work (and DOES work, just needs some (major!) tweeking and fixes, as nested folders don't work, etc... I'm sure you see the cavets)...
- User database is stored in mySQL table.. I'll call it "users" with fields:
-- Login (Login name)
-- Password (Simple Base64/XOR Encryupted Password)
-- Groups (Duh!)
-- IPRange (where this user can log in from.. ex. 127.0.0.1/255.255.255.255)
- .htaccess file as follows:
-- RewriteEngine on
-- RewriteCond %{REQUEST_URI} !/dispatch.php(.)$
-- RewriteRule (.)$ /dispatch.php?$1
- dispatch.php
-- <?php die(require('*********/authorize.inc'))?>
- authorize.inc
session_start();
// Set static XOR key location
$keyfile = '************************.inc';
include($keyfile);
require('mysql.inc');
require('functions.inc');
// Get list of possible users and passwords from mySQL DB
$sql = "SELECT Login,Password FROM users";
$result = mysql_query($sql) or die('There was an error while connecting to the database! Sorry! Access Denied!');
while ($data = mysql_fetch_array($result)) {
$user = $data['Login'];
$password = base64_decode($data['Password']);
// Decrypt Password
$decrypted = '';
$thisxorkey = substr($xorkey,0,strlen($password));
for ($x=0;$x<=strlen($password)-1;$x++) { $decrypted .= chr(ord(substr($password,$x,1)) ^ ord(substr($thisxorkey,$x,1))); }
$users[$user] = $decrypted;
}
// seed with microseconds
srand(make_seed());
if (!isset($_SESSION['Realm'])) { $_SESSION['Realm'] = 'AToM Protected Area ('.strtoupper(substr(md5(rand(17,96743)),floor(rand(7,13)),4)).')'; }
$realm = $_SESSION['Realm'];
if (empty($_SERVER['PHP_AUTH_DIGEST'])) {
header('HTTP/1.1 401 Unauthorized');
header('WWW-Authenticate: Digest realm="'.$realm.'",qop="auth",nonce="'.uniqid().'",opaque="'.md5($realm).'"');
die('You are not authorized at this time.');
}
if (!($data = http_digest_parse($_SERVER['PHP_AUTH_DIGEST'])) || !isset($users[$data['username']])) { die('You are not authorized at this time.'); }
if ($data['response'] != md5(md5($data['username'] . ':' . $realm . ':' . $users[$data['username']]).':'.$data['nonce'].':'.$data['nc'].':'.$data['cnonce'].':'.$data['qop'].':'.md5($_SERVER['REQUEST_METHOD'].':'.$data['uri']))) { die('You are not authorized at this time.'); }
if ($_SERVER['QUERY_STRING'] == '') { die(require('index.html')); } else { die(require($_SERVER['QUERY_STRING'])); }
- The "http_digest_parse" function:
function http_digest_parse($txt)
{
$needed_parts = array('nonce'=>1, 'nc'=>1, 'cnonce'=>1, 'qop'=>1, 'username'=>1, 'uri'=>1, 'response'=>1);
$data = array();
preg_match_all('@(\w+)=([\'"]?)([a-zA-Z0-9=./\_-]+)\2@', $txt, $matches, PREG_SET_ORDER);
foreach ($matches as $m) {
$data[$m[1]] = $m[3];
unset($needed_parts[$m[1]]);
}
return $needed_parts ? false : $data;
}
Phew! -- Now, some things are terribly sloppy, I know... It's not just something I "threw together", but something I've worked LONG and HARD on... the authorize.inc and function were based on some code right off php.net (in the digest auth function page.... something like that..)
Anyway, I need the XOR encryption (and I'll eventually use something MUCH stronger, AES.. etc..) and all this needs to be in a mySQL DB table... Eventually this WILL be run over pure SSL (for the ULTIMATE in security, of course), but for now a non-SSL connection must be used.
The code posted above DOES work so long as one doesn't try to go to "myhost.mydomain.com/subdirectory" -- then it dies. I'm sure in time I could pin it down and fix, but a little help / advice here would be GREATLY appreciated!
Incidentally, phpmyadmin runs perfectly.. requiring both my digest auth and its own http basic auth / dbuser scheme.....
I know someone out there can help me clean this up.... I would be eternally grateful! 😃
Jason