WordPress.org

Ready to get started?Download WordPress

Forums

[resolved] serialize auth cookies (3 posts)

  1. rob1308
    Member
    Posted 2 years ago #

    Hi All,

    I am trying to implement an admin capability to do a multi-upload of custom files via a plugin.
    Using Uploadify which is based on SWFUpload it's not possible to pass along cookies in the request the SWF makes to post the files to the handling script. I can get it working without authorisation by just pointing it at a standalone php script but for starters it's not very secure that way and then I don't have all the useful wordpress functions etc to hand to help process the files such as $wpdb etc.

    What I would like to know is how using admin-ajax.php I can authenticate via a serialized ( and crypted) version of the $_COOKIE which I can pass as a separate $_POST parameter in SWFUpload.
    The goal of this is to allow only "authorised" admin users to post files to the handling script.

    I feel it ought to be possible by intercepting one of the hooks and once decrypted nad unserialized, be able to populate the $_COOKIE again with the previous requests values to be able to "authenticate" correctly and carry on. As it stands I keep getting a returned value of "-1" which is generated at line 48 of admin-ajax.php

    I have looked since a few hours online and haven't found anything concrete which is wordpress specific. The source code does elude to the inbuilt media uploader also encountering these issues with Flash not sending cookies - see line 16 of wp-admin/async-load.php but I am not sure how they are getting around it?

    Any pointers would be greatly appreciated.

    Thanks,

    Rob.

  2. rob1308
    Member
    Posted 2 years ago #

    Hi All,

    I managed to find a solution as detailed for other's with a similar issue. Please see below. Any references to SWFUpload can be substituted for Uploadify.

    The original hook fails due to the SWFUpload not passing the session cookies in it's request so WordPress thinks it's a non-logged-in user.

    So what I did was pass $_COOKIE[AUTH_COOKIE] and $_COOKIE[LOGGED_IN_COOKIE] values to the page from which SWFUpload is initialised whereby one can then add the additional parameters in a similar fasion as this:-

    'formData'      : {'action': 'uploadClientFiles', 'auth_cookie': auth_cookie, 'logged_in_cookie': logged_in_cookie}

    Whilst this is not terribly secure as you are in essence then sending the session variables over the wire as-is and potentially allowing someone to sniff out the session details therefore I also added an encryption/decryption method on either side of the requests. These two functions were found at http://www.php.net/manual/en/function.mcrypt-encrypt.php#71452 courtesy of davidwhthomas.

    So the methodology is as follows.
    1. Encrypt the cookies to send to javascript variables for SWFUpload to POST back with its request.
    2. Decrypt the POSTed back variables.

    One last point to mention is that to make it harder for anyone to "spoof" the application by sniffing the cookie variables passed in the POST, I have made the "key" of the encryption use the users IP address so that only one IP address is valid and can decrypt correctly.

    The functions slightly amended to allow IP_address as the key:-

    function encryptCookie($value){
       if(!$value){return false;}
       $key = $SERVER[REMOTE_ADDR];
       $text = $value;
       $iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB);
       $iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
       $crypttext = mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $key, $text, MCRYPT_MODE_ECB, $iv);
       return trim(base64_encode($crypttext)); //encode for cookie
    }
    
    function decryptCookie($value){
       if(!$value){return false;}
       $key = $SERVER[REMOTE_ADDR];
       $crypttext = base64_decode($value); //decode cookie
       $iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB);
       $iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
       $decrypttext = mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $key, $crypttext, MCRYPT_MODE_ECB, $iv);
       return trim($decrypttext);
    }

    The original hook:-
    add_action('wp_ajax_uploadClientFiles', 'uploadClientFiles');
    Also needs to have a _nopriv alternative which we pass to a new function to re-initialize the session with POST values which can be added to a SWFUpload request as below:-
    add_action('wp_ajax_nopriv_uploadClientFiles', 'reSession');

    Here I took the top lines from the wp-admin/async-load.php file but amended them to decrypt the cookies as per the function mentioned above with the IP_Address as the key. Then when the authorization was concluded I added a call to the original function I had been hoping to reach as indicated by the add_action('wp_ajax_uploadClientFiles', 'uploadClientFiles'); call.

    Be sure to die() here as otherwise you will still get the -1 output from the original call to admin-ajax.php after line 46 - do_action( 'wp_ajax_nopriv_' . $_REQUEST['action'] ); has been executed.

    Here is the reSession function:-

    function reSession(){
    
    	define('WP_ADMIN', true);
    
    	if ( defined('ABSPATH') )
    		require_once(ABSPATH . 'wp-load.php');
    	else
    		require_once('../wp-load.php');
    
    	// Flash often fails to send cookies with the POST or upload, so we need to pass it in GET or POST instead
    	if ( is_ssl() && empty($_COOKIE[SECURE_AUTH_COOKIE]) && !empty($_REQUEST['auth_cookie']) )
    		$_COOKIE[SECURE_AUTH_COOKIE] = decryptCookie($_REQUEST['auth_cookie']);
    	elseif ( empty($_COOKIE[AUTH_COOKIE]) && !empty($_REQUEST['auth_cookie']) )
    		$_COOKIE[AUTH_COOKIE] = decryptCookie($_REQUEST['auth_cookie']);
    		echo decryptCookie($_REQUEST['auth_cookie']);
    	if ( empty($_COOKIE[LOGGED_IN_COOKIE]) && !empty($_REQUEST['logged_in_cookie']) )
    		$_COOKIE[LOGGED_IN_COOKIE] = decryptCookie($_REQUEST['logged_in_cookie']);
    	unset($current_user);
    	require_once('./admin.php');
    
    	uploadClientFiles();
    	die();
    }

    and finally for completeness the setting of the cookies as javascript variables to be included in the page where SWFUpload is to be called/used.

    wp_localize_script('some-script', 'auth_cookie', encryptCookie($_COOKIE[AUTH_COOKIE]));
    			wp_localize_script('some-script', 'logged_in_cookie', encryptCookie($_COOKIE[LOGGED_IN_COOKIE]));

    I hope this helps someone in the future with similar predicament(s)!

    Thanks,

    Rob.

  3. rob1308
    Member
    Posted 2 years ago #

    Hi Again,

    Just realised that I hadn't omitted a line of debugging in the above code. Please remove the
    echo decryptCookie($_REQUEST['auth_cookie']);
    from the reSession function above :)

    Thanks,

    R.

Topic Closed

This topic has been closed to new replies.

About this Topic