an image of some pajamas!

pajamas..

php and javascript advanced md5 authentication system

The connexion between "pajamas", which is an acronym for "php and javascript advanced md5 authentication system" and an actual pair of "Pyjamas" is that when you feel secure, you sleep better. Of course the words sound identical, too.

pajamas began as an attempt to create a more secure login using client-side hashing, which is one-way encryption, and as a demonstration, mainly for other web-coders, to two enormous security holes in all-too-common existence..

The first exists when folk use "public" browsers. Often the username and password are stored on the machine, and can be re-used, even by accident, by other members of the public. Clearly this presents a problem, and one which, for some reason, most people like to forget and/or ignore. Probably, like me, they realized it would need to be done with JavaScript, and then ran in the opposite direction.

The second hole is more obvious, and that is the plain text password travelling freely across the wires. This one has received more worldwide attention, but it's still ignored in most php web applications. There are literally hundreds of articles out there describing how to store a user's password using all manner of weird and wonderful algorithms, to protect it from "unauthorised database access", or "unauthorised server access", and yet still expecting the password to arrive in plain text. GUYS!

If your database isn't secure you are in trouble. Same for your filesystem. These are places over which you have control. The place where you certainly don't have control, ever, is the internet. And the moment that packet of data leaves the user's presumably safe environment it's fair game. Its contents could be stored on any one of the many nodes between server and client, dubious proxy "servers" could scan it, on poorly configured servers (most) passwords will show up on other server's referrer logs, etc. There it is, your plain-text password, travelling around the internet in a bundle of other useful plain text information, like the URL of the so-called secure login page, probably your username. No! This is insane!

pajamas takes an entirely different approach. The password is securely hashed before being sent over the wires. Now, not only is interception no longer a problem (it's impossible to retrieve the password from the hash in the given time-frame, even a very much longer time-frame), but public browsers can't save or cache it, either*, being a one-shot mish-mash of your password and some random generated string. Each time you login, it's completely different.

With pajamas, the only places the password ever exists in the clear are in your presumably secure server environment, and the presumably secure user's brain. This password is only protecting access to this server's content; ergo, breaching the web server breaches the user's "protected" data, anyway. To my reckoning, it would be considerably more difficult to compromise a modern web server and get root, than it is to search some log for the phrase "password".

Which strategy is best? You decide.

Since its birth back in 2004, pajamas spent quite a long time lying fairly dormant, yet working away quietly in the background as a highly useful authentication script. More recently, pajamas has grown into a rather neat modular authentication system, and the old "pj" module has essentially become one of its plug-ins. There's also a "plain" plugin that retains many of the good features of pj, but without the client-side hashing, for situations where JavaScript isn't available (On The Moon, maybe!). pj's client-side hashing is made possible with the excellent JavaScript functions provided by Paul Johnston's javascript MD5 code.

You can enjoy my wee "protected" image gallery, and try-out pajamas at the same time, here.
If you'd like to ask questions, give feedback, enlighten me, etc, you can do that at the bottom.

There is also a sha1 pajamas plug-in called "shaggie", which is currently available only inside my other packages (e.g. the distro machine), feel free to download and play around with it; get back to me if you find any issues, thanks.

Here's the current pajamas code..
(of course, most of the good stuff is inside the modules!)
<?php // ۞// text { encoding:utf-8 ; bom:no ; linebreaks:unix ; tabs:4sp ; }
if (realpath ($_SERVER['SCRIPT_FILENAME'] )   ==   realpath __FILE__ ))  {
    @include 
$_SERVER['DOCUMENT_ROOT'].'/inc/source-dump.php';
                                                    
source_dump(__FILE__); }
/*

    pajamas
    modular authentication system

    For full details, usage instructions, etc, see the accomanying readme.
    If you you got this without a readme, check out the link below.

    If you need help, mail me @ corz.org, or if you think a solution to your
    issue would be valuable to others, drop a comment on the pajamas page..

        http://corz.org/server/security/pajamas.php

    Have fun!

    ;o) Cor

    ps..    Big thanks to PCheese for all the help with the OOP.
            d00D! I get it now!  And I hope you like where I took it. ;o)


    (c) 2004->tomorrow! ~ cor + corz.org ;o)

    Please view the license for this free software, here:

        http://corz.org/free-scripts-licence.nfo

*/

/*
    pajamas authentication..
                                */

class pajamas {

/*
    version

    Currently, we have the bare bones of the thing, and it works great!
    There may yet be bugs, and all bug reports are wholeheartedly welcomed.

    */
    
var $_version            '0.3';



        
/*        public properties..        */


/*
    default module

    (string)    name of module file (minus .php extension)


        current choices are 'plain' or 'pj' (the best)

        If, for some insane reason, you don't have access to a JavaScript-
        capable browser, use 'plain', otherwise, use 'pj'.

        the plain module can be configured in exactly the same way as
        the pajamas module, and has many of its features, too; sessions, IP
        check, time-out, etc., the only difference being that the password is
        sent over the wire in plain text.

        Though unlike HTTP basic authentication, which send the password with
        every single request, with the plain module, the password travels over
        the wires one time only.

    */
    
var $_default_module    'pj';


/*
    password

    (string)    default: 'password';

        a quick and dirty way to store your password..

        or you could keep it in a database, or include from another file,.
        include '/some/other/place/config.php'; and set it externally..

            $auth->_login_password = 'MyPassword';

        Passwords are case-sensitive.

    */
    
var $_login_password    'password';


/*
    IP address check?

    boolean (true/false)    default: true;

        normally, we check the IP address of the authorising browser. However, if the user
        is behind a proxy farm (very unusual), this will break his session, as his IP will
        change with (possibly) each request. If you have users behind proxy farms, (or you
        are) set this to false, or else advise them to use *yet another* proxy (two proxies).

    */
    
var $_check_ip          true;



/*
    do time-out?

    boolean            default: true;

        we can specify a time-out for the session.  if you set this to false,
        the session is live until the client's browser is quit, or they log out.

    */
    
var $_do_time_out       true;


/*
    time-out

    integer    (in minutes)     default: 60;

        an hour is reasonable, anything goes. the demo uses 0.5 (30 seconds)

    */
    
var $_session_time      60;

/*
    big luser

    integer    (max failed attempts)     default: 10;

        they tried and tried, but it just isn't happening. Or else they are taking the p*ss.
        A script perhaps, some brute force. Whatever, it would probably be best for everyone
        if we halted them in their tracks after how many failed login attempts?

    */
    
var $_big_luser         10;

/*
    kick bad users?

    boolean (true/false)    default: false;

        optionally we can prevent even correct logins from browsers that repeatedly sent bad logins..

        If you set this to true, after($_big_luser) failed login attempts, the property
        "$auth->_bad_user" will be set to true. Now, even a correct login will fail to authenticate.

        You can check for bad users, and then do what you like with them..

            if ($auth->_bad_user) { die('go away!');

        If you leave kick_bad_users set to false, a correct login will override all previous bad logins.

        The idea is, someone may be attempting to login from your terminal, and fail, so they receive
        a message informing them of the futility of it, *hopefully* they will stop now. If the *real*
        admin comes along, he should be able to log straight in, and shouldn't have the inconvenience
        of restarting the browser just because some twat was fooling around. But you can disable this
        behaviour by simply setting this to true.

    */
    
var $_kick_bad_users    false;



/*
    show error messages?

    boolean (true/false)    default: true;

        pj generates some messages for the various error conditions, you can use these however
        you like, and latest message is always in "_auth_message"

        If you like, you can have pj display these messages just above the login form,
        so the user is aware that their password was incorrect, or whatever..

    */
    
var $_do_messages       true;

/*
    create containing forms?

    boolean (true/false)    default: true;

        If you are already inside a form, set this to false to avoid nesting forms,
        which will break xhtml valiadation, among other things (including the md5)..

            $auth->_createForms = false;

        Remember you can also pass "true" to your form input function, to have a
        simple, div-less output, like this..

            echo $auth->getLoginForm(true);

    */
    
var $_createForms       true;


/*
    autocomplete="off"

    boolean (true/false)    default: true; (doesn't validate, but hey!)

        a good, mostly supported proprietary Internet Explorer property.

        This will break strict xhtml validation (which is annoying), but you may feel
        that it's worth it. With this set to true, browsers will not annoy you to try
        and save the password (which, at least with the 'pj' module, is a one-shot
        mish-mash that will become useless the instant you logout).

        It will only break your xhtml validation until you login, of course.

        Set this to true to add 'autocomplete="off"' to your password field. TADA!
        One of the rare occasions where Internet Explorer leads the way! If you are
        obsessed with strict xhtml 1.0 validation, screw your users and set this to
        false.

        btw: if you known an xhtml-friendly way to do this, MAIL ME! ;o)

    */
    
var $_no_autocomplete    true;


/*
    code loaction.

    (string)    default: '';

        Some modules may require included code.

        In "pj", this sets the default location of javascript MD5 functions file and
        will be used to create the <script> tag that includes the JavaScript MD5
        functions on your page, like this..

            echo $auth->getAuthCode();

        You can override the location by setting this..

            $auth->_code_location = 'inc/md5.js';

        *before* you echo the code. relative or absolute paths are fine, just like a
        regular javascript include.

    */
    
var $_code_location        '';

/*
    a simple error catcher.
    boolean (true/false)    default: true;

        session errors of level "E_NOTICE" (type 8) will be caught and stored,
        rather than spew onto your page. use..

            echo $auth->getErrors();

        to see them, or pipe that somewhere else. essentially this saves having
        your pages all messed up when you are testing your pj implementation on
        a server with error level E_ALL set (all development servers, yeah?),
        mainly for "session already started" type errors. It was annoying!

        we throw errors into a global variable because a) I use this system for
        errors anyway, (my debug script throws me a pop-up if it finds anything in
        $GLOBALS['errors'], and b) variables inside error handlers are a disaster!

    */
    
var $_error_catcher        true;



    
/*

        Private properties.
        DO NOT CHANGE THESE.

        You shouldn't change anything above either;
        set it externally like so..

        $auth->_do_time_out = false;

    */
    
var $_auth_message        '';
    var 
$_auth_module        ''// a pointer to *real* auth class
    
var $_bad_user            false;
    var 
$_default_uid        'pajamas';
    var 
$_is_authenticated  null;    // start out in unknown (unset) state
    
var $_module_loaded        false;
    var 
$_modules_path        'modules/';
    var 
$_interface            'advanced';    // 'advanced' or 'simple'


    // constructor..
    
function pajamas ($uniqueid='') {
        if (!empty(
$uniqueid) and ctype_alnum($uniqueid)) {
            
$this->_unique_id $uniqueid;
        } else {
            
$this->_unique_id $this->_default_uid;
        }
        if (
$this->_error_catcher) {
            
$this->startErrorHandler();
        }
    }

    function 
authModule() {

        include 
$this->_modules_path.$this->_default_module.'.php';
        
$this->_auth_module = new authModule($this->_unique_id);

        
// setup its preferences..
        // (we could perhaps check module's capabilities and only set those)
        
if ($this->_interface != 'simple') {
            
$this->_auth_module->_login_password        $this->_login_password;
            
$this->_auth_module->_check_ip                $this->_check_ip;
            
$this->_auth_module->_do_time_out            $this->_do_time_out;
            
$this->_auth_module->_session_time            $this->_session_time;
            
$this->_auth_module->_big_luser                $this->_big_luser;
            
$this->_auth_module->_kick_bad_users        $this->_kick_bad_users;
            
$this->_auth_module->_do_messages            $this->_do_messages;
            
$this->_auth_module->_createForms            $this->_createForms;
            
$this->_auth_module->_no_autocomplete        $this->_no_autocomplete;
        }
        
$this->_module_loaded true;
    }

    function 
auth_user() {

        if (!
$this->_module_loaded) { $this->authModule(); }
        if (
$this->_is_authenticated) { return true; }

        
$auth_status $this->_auth_module->auth_user();
        
$this->_auth_message $this->_auth_module->_auth_message;

        if (
$auth_status) {
            
$this->_is_authenticated true;
            return 
true;
        } else {
            
$this->_is_authenticated false;
            return 
false;
        }
    }

    function 
getAuthCode() {
        
// this will need to load before authentication,
        // so we set it here, and now overriding works as expected.
        
$this->_auth_module->_code_location    $this->_code_location;
        
$html $this->_auth_module->getAuthCode();
        if (!empty(
$html)) { return $html; }
            else { return 
''; }
    }

    function 
getLoginForm($simple=false) {
        return 
$this->_auth_module->getLoginForm($simple);
    }

    function 
getLogoutButton($simple=false) {
        return 
$this->_auth_module->getLogoutButton($simple);
    }

    function 
getSelf() {
        return 
$_SERVER['SCRIPT_NAME'];
    }

    function 
getBadUser() {
        return 
$this->_auth_module->_bad_user;
    }

    function 
remainingTime() {
        if (
$this->_do_time_out) {
            
$now explode(' ',microtime());
            
$time $now[1].substr($now[0],2,2);
            
settype($time'double'); // 100th/second..
            
return (($this->_session_time 6000) - ($time $_SESSION['auth'.$this->_unique_id]['login_at'])) / 100;
        } else { return 
false; }
    }

/*
    a simple session error catcher..
    */
    
function getErrors() {
        if (!empty(
$GLOBALS['errors']['pajamas'])) {
            return 
$GLOBALS['errors']['pajamas'];
        }
    }
    function 
startErrorHandler() {
        
set_error_handler(array($this'handle_error'));
    }
    function 
handle_error($type$string$file$line$vars) {
        switch (
TRUE) {
            case (
$type == and stristr($string'session')): // doesn't look so clever with only one case!
                
if (empty($GLOBALS['errors']['pajamas'])) { $GLOBALS['errors']['pajamas'] = ''; }
                
$GLOBALS['errors']['pajamas'] .= 'NOTICE! session error on line '.$line.' of '.$file.': '.$string;
                return 
true;
                break; 
// *ahem*
            
default:
                return 
false// better let php handle this one.
        
}
    }

// end class pajamas()



class pajamasSimple extends pajamas {

    function 
pajamasSimple($uniqueid='') {

        if (!empty(
$uniqueid) and strstr($uniqueid'-')) {
            
$simple_prefs explode('-'$uniqueid);
            
$uniqueid trim($simple_prefs[0]);
            if (!empty(
$simple_prefs[1])) { $my_module trim($simple_prefs[1]); }
        }
        
parent::pajamas($uniqueid);
        
$this->_interface 'simple';

        if (!empty(
$my_module)) { $this->_default_module $my_module; }
        if (!
$this->_module_loaded) { $this->authModule(); }

        if (!empty(
$this->_auth_module->_code_location)) {
            
$this->_code_location $this->_auth_module->_code_location;
        }
        echo 
$this->getAuthCode();

        if (
$this->_auth_module->auth_user()) {
            echo 
$this->_auth_module->getLogoutButton();
        } else {
            echo 
$this->_auth_module->getLoginForm();
        }
    }

}


/*

    version history

    0.3
    fixed bug, not passing variables through to getLogoutButton() and getLoginForm()

    0.2
    first public release of pajamas engine

    0.1
    basic authentication module loader. almost works.

*/



?>

have fun!

;o)


references:
At least, this is the expected behaviour - currently, as far as I know, Opera saves the *typed* password, rather than the *sent* password, effectively defeating all forms of client-side password hashing strategy, dudes! - I've figured out a way around this, by the way, which will hopefully hit the code stage for my upcoming "shaggie" pajamas module. Take it easy!

Welcome to the comments facility!


return to paged comments
cor - 17.04.05 10:41 pm

I decided to do a page where folk can leave wisdom, ask questions, correct me, etc.

and here you are!

;o) Cor


stev0 - 08.05.05 4:43 pm

Very nice job, I will use it on my site.


cor - 09.05.05 2:59 am

Thanks.

I've just finished the first version of my "pajamas security module", which you simply include() wherever you need security. think plug-in authentication, something like this..
<!-- usual header here -->
include($root.'/inc/pj.php'); 
if (!auth_user()) die();
<!-- your secure page here -->
at that point, pajamas will either create the special password form and get the user login or else, if the user is already authorised, continue your page, it's pretty neat. the module returns a global variable you can check, too, if you don't want the page to just die after the form. (ie for a footer, or "security message", or something)

I've been testing it at my site admin page, where it's working beautifully (it sure feels good knowing my raw password isn't flying over the wires every time I login, which is a lot) and I plan to release it for a small fee (because this place really has got to start paying for itself soon!), but I'd like a few folk to beta test the module on different servers and setups before it goes on full release (and in truth, I haven't coded my PayPal automation yet)

If you're interested, mail me, and you can play with it, give me some feedback, and get a free license!

for now..

;o) Cor


alexander - 15.05.05 2:43 pm

Very nice!
I dont understand half of it but it looks great smiley for :D

Noticed that one can reset the logout timer by reloading the page, any way to work around that?

Can this easily be implemented as an script that is included on every page on wish to have secured?

/alexander


cor - 15.05.05 3:31 pm

The reset for each page load is just a preference, it's on a hair-trigger for the demo! you only get 30 seconds to look at the pics, too!

As to the "included on every page" secure area thing, see my previous post!

;o) Cor


cor - 20.05.05 1:45 pm

Thanks for all the interest!

I have enough testers now, so if all goes to plan, the module (which I affectionately call "pj") will be released to the masses sometime within the next couple of weeks.

for now..

;o) Cor


Jack White - 21.05.05 9:01 am

I'll be waiting for that!

Cheers, Jack


Alexnader - 24.05.05 9:30 pm

Hi!

Noticed that even if you fail 10 times you can visit another page, then go back to the loginscreen again and if you enter the correct password you are allowed to enter. Is there any way to build that posibility away perhaps.
Anyway, very great script. I will try to write down some tips and ideas of improvement within a few days and send it over to you.

/alexander


G Funk - 30.05.05 11:48 pm

From what I can gather in my limited understanding of security, in order for this to work, you have to have the password exposed in plain text on the server end, be it in a text file, php script, database, etc. Would it be feasible to store the password in an md5 hash on the server, and have the client pass the hash of the combination of the key and the hashed password like
calcMD5(random_string + calcMD5(loginpass.value))
and then use the same logic on the server to compare it, or is it somehow less secure to do this?


cor - 31.05.05 11:00 am

Well G Funk, it's a mind-bender, that's for sure!

At first glance it seems reasonable to store the password as an MD5 on the server, but in reality, all we have done is replaced the password with an MD5 of itself. In other words, you could authenticate by simply knowing the MD5, just as easily as you can by knowing the actual password. When I first put pajamas together, I wrestled with this for some time!

The only "weakness" with the current pajamas implementation is that your password is visible to someone if they have access to your raw filesystem, and if they have that, no amount of authentication will stop them getting your goodies, will it? pajamas isn't designed to protect you from unscrupulous hosting admins!

Probably the best place to put your password is in a database, and I'm considering adding a small database function to the module for this very purpose, but even then, you need to store a database password somewhere...

There's not really a big problem with keeping passwords inside php scripts, phpmyadmin, phpbb, nuke, etc, all keep their passwords inside php files, and mostly have their users send them in plain text over the wire, too!

With any authentication system, you need the original "raw" password to exist somewhere, the philosophy behind the pajamas approach is that it only exists in places where we have 100% control, namely, our brain and the web server, and nowhere inbetween, NOT in the browser, and NOT in the wires connecting it to the server. For a great many situations, this is the ideal approach.

;o) Cor

ps.. alexander, the current behaviour is by design, but it would be very simple to have it your way. Is this really what we want? I guess could make it optional.


Alexander - 31.05.05 10:07 pm

Hi!

I have emailed over some comments and things on the script now.

Yes that I think would be great :) perhaps some temp IPban on anyone who fails X times, could be nice. But I dont know how hard that is to write.

/alexander.


cor - 01.06.05 8:11 pm

I got them! I've incorporated your absolute_luser facility into the module and I've jotted down the edits required to get your version to act this way, they will be in your inbox shortly. You can see it working already on my own admin page (link above).

Thanks for the contributions! As interior designers say, "I like what you've done with it!". I'll follow your example of a modularised logout button, and may even do that with all pj's "html" output, allowing the user to slot the parts in wherever they need, there will be preferences for these things, of course. (I like stuff to plug-in!)

By default, though, the module will come out-of-the-box as a plug-in authentication system, handling all aspects automatically with one simple include on your page, with lots of alternative behaviour configurable in the prefs.

for now..

;o) Cor


huskey - 24.06.05 11:17 am

Hey guys, I've got little knowledge with web programming but I have to say that this looks like a great little project. Keep it up! smiley for :D


Heruka - 28.06.05 11:52 pm

Great stuff!
Spend a little more time meditating - just a little more focus, you will see amazing things.
Thanks.


cor - 15.08.05 4:37 am

oops!

I've just been informed that I missed making this comments file world-writable when we moved servers. Sorree! Gotta get a mysql backend for these things. smiley for :lol:

pajamas development has been temporarily suspended while my future-pajamas-collaborator and I work on something else together, get a feel for this process, because we have big plans for pj's future..

The idea is to create a sort of universal plugin authentication system that web developers can pick up and drop into their sites, and pajamas would become a part of this, effectively one of the plug-in modules.

PCheese has also introduced me to the wonders of OOP in php, and an oopilized pajamas is definitely coming your way sometime soon.

all good, all to come.
stay tuned!

;o) Cor


doug - 05.09.05 12:02 am

looking forward to it!


John Doe - 22.11.05 11:11 pm

I really like what you have done.

Regarding G Funk's comment on storing the passwords on the server, would you be interested in avoiding this? There are a set of protocols informally called "Perfect Forward Secrecy", or "Forward Secrecy" by some. See first two paragraphs of http://en.wikipedia.org/wiki/Perfect_forward_secrecy .

There are some ways to avoid storing the password on the server. If you are still interested, we could discuss it more.

------------------------------------------

Re: Response to G Funk
------------------------------------------

Well G Funk, it's a mind-bender, that's for sure!

At first glance it seems reasonable to store the password as an MD5 on the server, but in reality, all we have done is replaced the password with an MD5 of itself. In other words, you could authenticate by simply knowing the MD5, just as easily as you can by knowing the actual password.
When I first put pajamas together, I wrestled with this for some time!


cor - 24.11.05 3:17 pm

John Doe, yes, it's interesting stuff, but as I understand it, Perfect Forward Secrecy is more a concept, a standard, than a "system".

Pajamas will likely end up as part of a larger, more modular authentication system, and PFS-like features could certainly be on the cards, for sure, I'd considered a few hacky temporary key systems, and unusual incremental id tagging long before I'd even heard about PFS, but something irks me about the "more guns" approach to security, and I didn't go too far into that.

But I'd like to know more about PFS, especially from someone who knows what they are talking about, and if you know of an implementation of PFS that pajamas could plug-into/mimic/utilise/whatever, then yes, I'd be very keen to hear more. There's an almost secret link to my IRC channel in the toolbar (or rather, a link to a link), feel free to drop in. I am sometimes around.

for now..

;o) Cor


wanbe - 12.01.06 11:35 am

very nice! thx.


Joe Mcstubilhosin - 16.01.06 6:26 pm

Hey, this PHP login doesn't seem to work for me; can you send me a .zip file of one. Maybe that would be easyier to copy then that code has well. Me email is
hacker-helper@gmail.com

Thank you, also if anyone is any good with javascript then I would like on of those; either if fine.
My server can support it so don't think that is what it is either, If anyone else needs some help I can give it just E-Mail me. KK


cor - 20.01.06 9:28 pm

You spotted the zip download link at the top of the page, yeah?

And Javascript is a browser thing, so long as your server supports php (>=v4.2) pajamas will run just fine, after that, it's their problem!

;o) Cor


sami - 28.01.06 12:57 pm

hmm, why don't you use onSubmit instead of onClick handler? It should resolve the click 'log in' issue, atleast to my knowledgesmiley for :D


cor - 29.01.06 5:45 am

Hmm. sounds good. I'll try that sometime. Thanks. smiley for :D

But then, it's only Internet Explorer users that suffer, and they do that anyway! smiley for :lol:

;o) Cor


Dane - 30.01.06 4:58 am

Maybe I missed this, but there's still a bit of a problem with this... that is, how to create the password in the first place. If you already know it, that's wonderful, but is there any way for a user to create a password and send it to the server for the first time without doing it in plain text?


cor - 30.01.06 6:16 am

Nope, Dane, this isn't a mechanism for creating passwords, just for authentication. There are possibly other ways to do that, but it's not something I've ever needed, or looked at. Sorree.

;o) Cor

ps.. sami, onsubmit doesn't seem to make any difference in IE. I'll maybe have another fiddle later.


cor - 28.03.06 10:30 am

Observant sorts may have noticed that earlier today I uploaded the new "pajamas modular authentication system", which is pajamas taken to the next level.

pajamas.php becomes a module-loader-authentication-engine-thing, and the old "pj" is now effectively a plug-in, works great. Everything is pure xhtml 1.0 strict, and with help from PCheese, 100% OOP! I expect oop-ness to start sneaking into my other php, it's certainly an intuitive way work the code.

Though I have tested it out fairly thoroughly, and am using it right now elsewhere, I expect bugs, and bug reports are most welcome. Feel free to play around with the demos (links at the top) and download the pajamas package, which comes with two plug-in modules "pj" and "plain", as well as the pajamas demos, example code, etc. Check out the readme for more details. You can also view the source right here.

Thanks for all the input so far, here and by mail, hopefully the new system will be all that was hoped for and more.

for now..

;o) Cor

ps.. when I first uploaded the whole lot here to corz.org, the "simple" interface demo didn't work, kept telling me the password was wrong when it wasn't. Then I remembered about the phpsuexec here at my host, added a few local php.ini files (whose only session directive is session.use_trans_sid = 0). All is suddenly well! Hmm. Any thoughts on would be appreciated.


cor - 08.10.07 12:14 pm

By the way, although there's not an official release, as such; if you grab the latest version of my distro machine, you get a pajamas installation with a SHA-1 module. It also outputs strict XHTML, which I don't think the current release does.

I'll put together a new pajamas distro proper in the near future.

By the way; here at corz.org, apart from the comments, pajamas controls all my authentication, and I pretty much have a site-wide login, which is real nice.

;o) Cor


Ryan G - 25.11.07 7:04 pm

Corz, I cam here via this page:
http://foruhttp://forums.invisionpower.com/index.php?showtopic=181089&mode=linearplus

It says that pajamas is only "obscuring" the password. Is this true?

Best.
Ryan.


cor - 26.11.07 4:57 pm

Heh, no.

Either the poster a) didn't look at the code, or b) didn't understand it.

Whether you can see the "random number" is irrelevant. Firstly, pajamas uses many criteria to judge whether a particular user is authenticated or not, and secondly, even if someone had access to some as-yet-uninvented computer that could find a collision within a reasonable time-frame, it would be ABSOLUTELY NO USE TO THEM. It became out-of-date the instant it was received. Which is kind of the whole point.

Also, there's a SHA1 plugin, so even our theoretical computer wouldn't help!

;o) Cor

ps. I've been using pajamas on-site, for all my admin authentication, ever since it was first created, and with 100% success.


Me - 08.06.08 2:05 am

What stops someone reverse-engineering your system by looking at the source code of the page?

"The only "weakness" with the current pajamas implementation is that your password is visible to someone if they have access to your raw filesystem, and if they have that, no amount of authentication will stop them getting your goodies, will it? pajamas isn't designed to protect you from unscrupulous hosting admins!"

And what happens when a cracker accesses your raw filesystem via URL injection?


cor - 08.06.08 3:22 pm


What stops someone reverse-engineering your system by looking at the source code of the page?


You can even look at the source code for the pajamas package itself; it won't help you reverse engineer anything; there's nothing to reverse-engineer, MD5/SHA1/etc. are one-way cryptographic functions. The code is already well-known.


And what happens when a cracker accesses your raw filesystem via URL injection?


My first response to this is.. stop talking nonsense! However, you may know something I don't; so if you tell me exactly how this attack is crafted, and how you could access my raw file system with it, I may amend my response.

;o) Cor

ps. I've uploaded a file /inc/db/.ht_secrets - please use your attack and tell me the password contained in that file. Cheers!


Frosty - 10.07.08 10:18 pm

um, a bit of help please? When ever I use the PJ theme (which is the one that I want to use) it won't work smiley for :erm:. Also, my sessions are messed up. In the .php file I have it set at the default (60 I think) and in the root php.ini file I have
PHP.ini
session.gc_maxlifetime = 1440
session.use_trans_sid = 0
(just a standard installation of php5, apache, and mysql). The demo in this just sits there saying that the password is wrong when I enter the correct one.

I'm just trying to get this to work were I have some users working on a tutorials page.

Thanks,
Frosty

PS. I Also have a copy of PHPBB and it works how it was supposed to. A "needed stuff" page similar to phpbb's would be helpful smiley for :)


cor - 11.07.08 12:45 am

I don't know what a standard installation is, if such a thing even exists, and without more in the way of real error messages, your pj troubles are also a mystery to me.

Feel free to mail me whole screeds of log output, php error messages, copies of pj, between now and when I wake up, tomorrow. If there's only a single error message, or a small amount of useful data, drop it here.

I didn't realize there was "needed stuff" for pajamas, aside from basic php4+. But there may well be. Again, more details welcome.

You've seen the readme link at the top of the page, right?

;o) Cor

ps. iirc, the latest pajamas release, currently, is inside the distro machine beta (elsewhere onsite), there are differences that may affect how the old release demo works, but pj itself works great. check the implementation in the distro machine beta.


dumpydooby - 05.12.08 6:03 am

There seems to be a bug with PAJAMAS on this system I'm using. It doesn't work on my own site where I've implemented it, and even your demo doesn't work. I don't know the details of the system I'm on, but I can give you the UserAgent value:

Mozilla/5.0 (Macintosh; U; PPC Mac OS X 10.5; en-US; rv:1.9) Gecko/2008061004 Firefox/3.0


cor - 05.12.08 6:15 am

If you can't get even the demo to work on your site, there is clearly something very wrong. You user agent string probably has nothing to do with it. Check your php error log and note any related errors, post them here. You might also want to download debug-report.php, which will spit out all sort of useful information, let you know if php sessions are working correctly and more.

You can get that here.

Also, does the demo work for you here at corz.org? If not, it's possible there's something up with your browser.

;o) Cor


dumpydooby - 06.12.08 8:58 pm

That's just the thing. I have PAJAMAS working just fine on my site. It works on every browser I've tried. The demo here on corz.org also works in every browser.

The problem that I was pointing out was only related to that specific system I was on the other night. I was in a classroom and I was trying to show PAJAMAS to a web development professor at my school. PAJAMAS didn't work on the computer that I was using (which is why I posted the UserAgent information), and I figured you should know what browser and OS I was using so that you could replicate the problem and see if you could figure out what was wrong (or you might know if there is a potential compatibility issue between MacOSX w/Firefox 3 and your script).


I'll tell you what, though. Next time I go into that classroom (which isn't often since I don't actually have any classes in there), I'll set up a test page for PAJAMAS on my site, and I'll unmask the password to see if there is an issue that stands out right away. I'll also try using one of the alternative javascript-based md5 scripts out there in cyberland.


cor - 06.12.08 9:23 pm

It's amazing how little feedback I get about pajamas, yet I keep coming across it, and recommendations for it, all over the place. No one ever thinks to mail me and say, "Hey! I got pajamas working on X server v0.x, works great. Thanks!", or anything like that. What I mean is, good to hear, ta.

As to the issue on that machine, were there any specific errors? I've noticed hits in my error log recently with FF3 looking for resources in totally the wrong place; I must check if it was on OSX, perhaps the combo has issues. Probably more useful than unmasking the password (if it changes length, the javascript part is probably working fine, probably), would be to have a peek at the session variables. See exactly what's been stored.

The debug script I mentioned in my previous post is excellent for this. I also have a session viewer script kicking around (it's not available for download (at least until I can get around to doing a safe online demo version - it has a drop-down of all available sessions, very handy)) mail me if you want a copy.

I'm curious, why were you showing to the professor? You can tell how feedback-starved I am about pj! smiley for :lol:

Another thing you might want to try is the sha1 module. I don't think it ever made it to an official pj release, but there will be a copy inside the most recent distro machine download, for sure, and elsewhere onsite.

Lastly, if other md5 scripts can slot into pajamas, that's something I'd be keen to know about! But any data you have is useful. Cheers!

;o) Cor


jdmfontz - 08.01.09 4:48 pm

This sounds neat. However, how do you get around the problem presented by G Funk?

" Re: Response to G Funk
-----------------------------------------

Well G Funk, it's a mind-bender, that's for sure!

At first glance it seems reasonable to store the password as an MD5 on the server, but in reality, all we have done is replaced the password with an MD5 of itself. In other words, you could authenticate by simply knowing the MD5, just as easily as you can by knowing the actual password.
When I first put pajamas together, I wrestled with this for some time! "

For this to work you would need to md5 a random string along with the password. But them how do you get the server to know what that is?

This is where PKI comes useful. Client uses server public key to create the hash, server opens hash with private key, etc.


cor - 18.01.09 6:00 pm

I believe I already answered that.

;o) Cor


Chris - 30.01.10 5:43 pm

I LOVE your pajamas! This is a very well thought out and useful script. Of course I found this a day after I figured out that you can use http auth with an SSL certificate to encrypt your password while it travels over the network =p

Why is it that the simple demo fails but the regular demo does not?

I added a php.ini with the following to /demo/, /demo/inc/, and /demo/inc/pajamas/ too no avail...

[php]
session.use_trans_sid = 0

Any idears?

Ensure you aren't manually setting php_value session.name. I have seen this interfere with some installations. ;o) Cor



Will - 01.03.10 3:09 am

A bit of a newb question, but I got here from a google search on htpasswd.

Is there any way to protect a Directory using pajamas, the way you would with .htaccess+.htpasswd?

The readme was a little more technical than my level. Thx!



cor - 04.03.10 3:14 pm

Yes, simply drop the whole lot into the directory you want to protect - or else put it elsewhere on your site and set that path in the preferences inside pajamas.

Remember to set the name of the main pajamas page to your default document (usually index.php or similar). That way, whenever someone enters that directory, they always get pajamas, and not a directory listing.

Download the zip. The examples in the demo folder (inside the pajamas zip) should get you started. Open the simple demo (simple.php) in a text editor. It's basically this..

<?php
include 'inc/pajamas/pajamas.php';
$auth = new pajamasSimple('wadeva');

if (
$auth->auth_user()) {
    
// Authorised here
} else {
    
// not authorised here.
}
?>


With that simple code you can protect anything (well, web resources!).

;o) Cor

ps. depending on the contents of the directory, you may want to opt for something with more features. Check out the distro machine, which includes pajamas.


drifter - 09.05.10 1:23 am

hi cor

i spent quite some time on your website today, checking out all of the interesting stuff you have here.

as far as pajamas is concerned:

I played with the demo and was browsing the images after authenticating. whilst clicking on the second image (instead of enlarging) it showed me the login screen again and i had to login again to continue.

after the last image (i still read the text under the image and gave it a good look for at least 30 seconds i would guess because my dog has now discovered fishing too), then logged out with the supplied button. It told me i must not hammer the site. could that be true?!

i then walked away from my pc for about 4 hours to do some other stuff. when i came back i clicked back several times to see where i was and it took me through all the stages as described above (i.e. pic4->pic3->login->pic2->pic1->login). i only thought about it later that it was not supposed to let me back in to see the images... or was it?!

i try to remember where i comment in case the people need more info of what i am on about, and i will surely come back to your site again, but i might miss this page totally. i find it a bit difficult to surf it due to that fairly cryptic image menu at the top. i initially came here from Google for the htaccess stuff, and when i tried to find it again later from your homepage as starting point it took quite some time.

thanks

drifter


Bobby - 20.06.10 2:35 am

Hi, I downloaded pajamas and am using the simple style... Even though I changed the password in the following variable directive in pajamas.php
var $_login_password = 'newpassword';
it still uses the old password, which is just password. Is there any place else that I need to change the password? Thanks!


cor - 20.06.10 2:47 am

I know; the readme is a bit lengthy. The bit you want goes like this..

When you run in "simple" mode, because you cannot override the module's built-in preferences, you will need to ensure that they are correct for your installation, and if need be, alter them inside the *module* itself


So do that, and you'll be okay.

;o) Cor


Bobby - 20.06.10 3:18 am

aah.. my bad.. thanks for a prompt response... i love the stuff u've created... looking at ur website, I can tell that you must be hell of a guy.. cheers !!!


Chris - 11.02.11 4:06 pm

I am a designer and lecturer living in London, teaching at Barnet Schools of Creative Industry, currently researching publising a source book for businesses and anyone seeking to set up online and market their product or services. Part of it covers designers and illustrators: http://www.neasdencontrolcentre.com/ http://www.bibliothequedesign.com/ to name a few.

I am planning format for ipad books. I wanted to know if you would me us to use your comments and credit you with links for the work on security online.

The info you wrote was outstanding on sit security.

Look forward to hearing from you.

Christopher

So long as you give credit where it's due, you and anyone who wants to can copy whatever bits they like from corz.org. Have fun! ;o) Cor



Donserdal - 15.03.11 12:37 am

Well im using Pajamas and disto machine Thanks works create!!

Cheers! ;o) Cor



DY - 20.03.11 10:57 am

Great script, thanks a lot!

I did kind of tear all the nice bits apart, and re-frankensteined it to a single file... but methods are still the same.

Do you have any examples to connect it to a database? I am working on my own implementation get a MySQL connection with multiple users, rights, statistics, etc... If you happen to have a bit a script that might be a pointer in the right direction, it'd be nice to have a look at.

Again; thanks a lot!

Regards,

DY

It's not something I've looked into, but I'm sure whatever code you produce would be useful to other pajamas users; do feel free to share back. ;o) Cor



DY - 04.04.11 7:24 pm

For the record; I am still working on it.

Currently, it is up&running fine (as it seems...), I will now do some testing, cleaning the code up and making it ready to publish.

Some features I added are;
- sha512 rather than MD5 (yep, I got inspired by your Shaggie)
- multiple hash turns (decoding hashes is to easy these days)
- multi-user/multi-pass (ofc)
- permissions (only the very, very basics of it)
- double hash turns; first 250 hashes, then the random/changing code is added, then it is hashed again 250 times, then it is sent&compared
This improves security for a database; if your DB will be stolen, thieves will only steal your hashes...

I am rather busy atm, but I'll contact you as soon as I'm done; I have no interest in spreading it, but you'll be free to do with it as you like (which includes spreading it).


BM - 13.06.11 5:55 pm

@DY:

Do you already have a working example with MYSQL?
I'm interested in your code for my own website.

See here. ;o) Cor



MAINTENANCE MODE!
Posting is currently disabled.

Welcome to corz.org!

If something isn't working, I'm probably improving it, try again in a minute. If it's still not working, please mail me!