Search code examples
phpfirefoxpasswordsdomain-name

forge domain for firefox password autocomplete?


When running two different websites, say free.webhost.com/app1 and free.webhost.com/app2, it seems that Firefox has trouble storing different login credentials for both, especially when the same username is used with different passwords. If a user's credentials on the /app1 site are Name and pass1 and on the other site are Name and pass2, then Firefox can only store one of these and will ask to change the password when hopping between them.

I investigated this problem and to my astonishment this seems to be a WONTFIX in the firefox bug repository: https://bugzilla.mozilla.org/show_bug.cgi?id=263387

Is there any way I can workaround this when designing my apps? Like by setting a certain cookie property in PHP or html, or even specify a (fake) different domain name, so that firefox no longer considers free.webhost.com/app1 and free.webhost.com/app2 as the same website for password storage (and can thus store a different password with the same username for both sites)?


Solution

  • We need a custom saver. I'm going to try be short and concise.

    This is very useful if you don't want the browser saver. I think it can have some applications.


    THE BASIC

    I suggest in the PHP we use different cookies to save the session with session_name or session.name directive. For each site we must set a session name.

    In the HTML we should use different inputs name, so the app1 input will be <input type='email' name='email_app1' /> and app2 email_app2. We also can disable the autocomplete.

    The data is saved locally encrypted with AES. For this we can get CryptoJS. We also want to have salt hash in the client.

    THE CONCEPT (summarized):

    • Save locally the password encrypted. It is returned by the login controller. Of course if the user wants.
    • Save a salt which changes in each login. Of course if the user wants.
    • When the user return to the login page, the JavaScript checks if there is a salt and it sends it to server. The PHP returns the passphrase and JavaScript decrypts the local password.

    the sample code:

    In the controller:

    // I use functions in the controller like example
    public function getLoginPage(){
       // it prints the html and js to login using the basics how i have said
    }
    
    // salt is sended by the JavaScript
    public function getPassphrase( $salt, $username ){
       $passPhrase = get_passphrase_from_salt( $salt, $username, Request::IP() );
       return $passPhrase;
    }
    
    // It is to get the salt
    public function getSalt( $username, $password ){
          $user = get_user( $username, $password );
    
          // if valid user...
          $passphrase = random_string();
          $salt = random_string();
    
          $encrypted = encrypt( $password, md5($passphrase) );
    
          save_in_table_salt( $salt, $passphrase, $username, Request::IP() );
    
          // it prints a JSON like example
          return json_encode( array( 'salt' => $salt, 'encrypted' => $encrypted) );
    }
    
    // ... Normal login etc you could change the salt and reset in the client
    

    In the view we put the JavaScript logic. I used localstorage but I think it's not important.

    // in login page
    window.onload = function(){
        if( localStorage.getItem('salt') !== null ) { // the data is saved
           // Get the passphrase
           ajax_call('post', 'getPassphrase', { 
                 salt: localStorage.getItem('salt'),
                 username: localStorage.getItem('username')
              }, function( passphrase ){
              // It sets the inputs values!
              document.getElementById('username_app1').value = localStorage.getItem('username');
              document.getElementById('password_app1').value = decrypt( localStorage.getItem('password'), CryptoJS.MD5(passphrase) );
           });
        }
    };
    
    // it captures the submit action
    document.getElementById('login_form').onsubmit = function(){
        // it asks to user if he wants save locally the credentials
        if( localStorage.getItem('salt') === null
            && confirm('Do you want save credentials?') ){
            var form = this;
            // get salt
            ajax_call('post', 'getSalt', {
                  user: document.getElementById('username_app1').value,
                  password: document.getElementById('password_app1').value
               }, function( object ){
               localStorage.setItem('salt', object.salt);
               localStorage.setItem('password', object.encrypted);
               localStorage.setItem('username', document.getElementById('username_app1').value );
    
               form.submit(); // now yes
            });
            return false; // it prevents submit
        }
    };
    

    You must know that the code is a sample. Some functions don't exists and it's only to be understood. We need more conditions and logic to do it works.

    UPDATED: Now works with multiple computers and IP security and more!