Question

I've started working on a new web project and this time I thought I would put some more thought into how I handle user authentication (previously only working with MD5 hashed passwords). I feel like I've searched all the corners of the web for an easy, non-overkill solution and now I wonder if the following is possible to implement:

  • Client enters username and password and presses "Submit"

  • On submit an AJAX request is made to the server asking for a random token/nonce/secret/passphrase

  • The server returns the nonce to the client where a hash is made with the password and the nonce

  • The client sends the username and the hash(password+nonce) to the server where the authentication is made

My questions are as follows:

  1. Is it possible for AJAX to ask the server for a nonce and have the server waiting for the hash to be transferred back? (async: false maybe? Feel free to provide snippets/examples) The only other alternative I see is storing the nonce in a hidden field and that seems less favorable.

  2. Would this provide any added level of security at all?

  3. If not, what other options are there? Should I just send the password in clear text like I used to?

Note: I know a lot of people will want to say that HTTPS/SSL is the only way to accomplish a secure site and I hear you, but since this project isn't supposed to have more than a handful users all created manually by me and there will be no secure information like financial transactions or other sensitive data exchanged I only want to have a reasonable means of protecting the password/data during login. MITM and all the other threats out there are not an issue for me in this case since a) the majority of all hackers out there won't be interested in my tiny, private-use-only project and b) the calculated cost of any data loss or security breach isn't enough to warrant the purchase of an SSL certificate

Any input or advice is appreciated (even from those of you who want to scold me for being a stingy rookie ;) )

Was it helpful?

Solution 3

After a lot of research and looking through code snippets I ended up realizing that no matter what kind of protection I implemented at the client side (hashing in Javascript, requesting nonces etc.) the sense of added security would just be an illusion. Sure, it wouldn't hurt but I keep on getting back to the "security through obscurity" quote.

Maybe there is a way to create a smart, simple way to authenticate users and protect credentials without using HTTPS/SSL but I haven't been able to find it (and I definitely don't have the coding skills to figure it out on my own).

I think I'll just get on the SSL bandwagon and save myself a lot of time and trouble.

OTHER TIPS

1 - Yes is is possible. You can send multiple AJAX requests which you can set up with a bit of logic to fire and respond only once certain conditions have been met. Perhaps you can consider creating a random salt on the client side with say md5 or some other supported techniques.

2 - Yes, anything is better than md5 in regards to hashing sensitive information and sending text in the clear is downright trouble.

3 - Look into phpass from openwall. It is an easy to implement, open source, password hashing framework that will help you get the job done right. A few of the bigger names use it including wordpress, etc. You'll have to make some modifications of your own if you are set on ajax.

<?php

    // this is normally where you should include a connection to you database
    // to check user input against what is stored 
    if(isset($_POST["username"])) {
        $username = $_POST['username'];
        if ($username == "Joe Schmoe") {
            echo $username.' is taken';
            exit();
        } else {
            echo $username.' is available';
            exit();
        }
    }
?>
<?php

    // this is also where you should include a connection to you database
    // to check user input against what is stored 
    if(isset($_POST["submitIt"])) {
        $username = $_POST['submitIt'];
        if ($username == "Joe Schmoe") {
            echo 'Username is taken';
            exit();
        } else {
            echo 'Success!!';
            exit();
        }
    }
?>
<!DOCTYPE html>
<html>
<head>
    <script>
        function ajaxObj(meth, url) {
            var x = new XMLHttpRequest();
            x.open(meth, url, true);
            x.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
            return x;
        }
        function ajaxReturn(x){
            if(x.readyState == 4 && x.status == 200){
                return true;
            }
        }
    </script>
    <script>
        function username_availability() {
            var un_value  = document.getElementById("username_value").value;
            var un_error  = document.getElementById("username_error");
            var un_status = document.getElementById("username_status");
            if (un_value != "") {
                var ajax = ajaxObj("POST", "<?php echo $_SERVER['PHP_SELF']; ?>");
                ajax.onreadystatechange = function() {
                    if(ajaxReturn(ajax) == true) {
                        un_status.innerHTML = ajax.responseText;
                    }
                }
                ajax.send("username="+un_value);
            }
        }
        function submitIt() {
            var un_value  = document.getElementById("username_value").value;
            var un_status = document.getElementById("username_status");
            var sb_button = document.getElementById("submit_button");
            var r_message = document.getElementById("result_message");
            var un_form   = document.getElementById("username_form");
            if (un_value == "") {
                un_ststus.innerHTML = "Form data is missing";
            } else {
                un_status.innerHTML = 'processing...';
                var ajax = ajaxObj("POST", "<?php echo $_SERVER['PHP_SELF']; ?>");
                ajax.onreadystatechange = function() {
                    if(ajaxReturn(ajax) == true) {
                        if(ajax.responseText == "Username is taken") {
                            un_status.innerHTML = ajax.responseText;
                        } else {
                            window.scrollTo(0,0);
                            r_message.innerHTML = 'Username is yours!!!';
                            un_status.innerHTML = ajax.responseText;
                        }
                    }
                }
                ajax.send("submitIt=" + un_value);
            }
        }
    </script>
</head>
<body>
    <form name="username_form" id="username_form" onsubmit="return false;">
        <div>Username: </div>
        <input id="username_value" type="text" onkeyup="username_availability()" autofocus>
        <button id="submit_button" onclick="submitIt()">Submit</button>
        <div id="result_message">Submit Username</div>

        <div id="username_status"></div>
    </form>
</body>
</html>
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top