Coldfusion: authenticating hashed password

Hello,

I have a login authentication system, the passwords in the database are stored as SHA-384. The following login script does nothing, when I include the Hash function. Where am I going wrong?

I'm using MSSQL Server 2008 R2, Coldfusion 10.

loginform.cfm

<cfif IsDefined("FORM.email")>
  <cfset redirectLoginSuccess="admin.cfm">
  <cfset redirectLoginFailed="login.cfm">
  <cfquery  name="UserAuth" datasource="sql1007539">
  SELECT email,userPass FROM customers WHERE email=<cfqueryparam value="#FORM.email#" cfsqltype="cf_sql_clob" maxlength="255"> 
  AND userPass=<cfqueryparam value="#Hash(form.userPassword, "SHA-384")#" cfsqltype="cf_sql_clob" maxlength="255">
  </cfquery>
  <cfif UserAuth.RecordCount NEQ 0>
    <cftry>
      <cflock scope="Session" timeout="30" type="Exclusive">
        <cfset Session.Username=FORM.email>
        <cfset Session.UserAuth="">
      </cflock>
      <cfif IsDefined("URL.accessdenied") AND true>
        <cfset redirectLoginSuccess=URL.accessdenied>
      </cfif>
      <cflocation url="#redirectLoginSuccess#" addtoken="no">
      <cfcatch type="Lock">
      </cfcatch>
    </cftry>
  </cfif>
  <cflocation url="#redirectLoginFailed#" addtoken="no">
  <cfelse>
  <cfset LoginAction=CGI.SCRIPT_NAME>
  <cfif CGI.QUERY_STRING NEQ "">
    <cfset LoginAction=LoginAction & "?" & XMLFormat(CGI.QUERY_STRING)>
  </cfif>
</cfif>

Open in new window


Edit: The script works if no HASH functions are used.

 Edit: I can also confirm the passwords are stored in SHA-384. I checked using the following HASH identifier: duncanwinfrey.com/tools/hashid/hash.php
Claudia_WinterAsked:
Who is Participating?
 
_agx_Connect With a Mentor Commented:
> '(space)#hash(form.password, "sha-384" ,'UTF-8')#'

The result will fit inside char(96).  But there's an extra space in front of the #hash(...)#  and that's why the last "7" is missing!  Also, I noticed the insert uses the extra encoding parameter ie UTF-8 . If you use it there, then you should do the exact same thing when you do the authentication query.  It may work anyway, but using different code is just asking for problems ... ;-)

Wipe out the test record and create it again with the space removed.  And use the exact same hash code in both places.  With the space removed it should work.

BUT make sure the final code uses cfqueryparam for all values, so you don't get hacked ...
0
 
SidFishesCommented:
A guess:

You might want to try changing cfsqltype="cf_sql_clob" to cfsqltype="cf_sql_varchar"

the hash output is just a 64 ascii character text string and I'm not sure what effect clob would have (due its support of unicode chars.?)

Varchar is probably a bit faster as well. (another guess)
0
 
SidFishesCommented:
Another possibility - if you don't specify an encoding argument, default encoding is UTF-8. If your document is set up as something different, you may have issues.

Haven't tested it but I'm guessing comparing a hash saved with utf-8 encoding will be different than the form hash if your doc is encoded with ISO-8859-1 or whatever
0
Improved Protection from Phishing Attacks

WatchGuard DNSWatch reduces malware infections by detecting and blocking malicious DNS requests, improving your ability to protect employees from phishing attacks. Learn more about our newest service included in Total Security Suite today!

 
Claudia_WinterAuthor Commented:
Hello,

I added your suggestions also, made a few changes. Still not working. The Password is being stored correctly.

<cfif IsDefined("FORM.email")>
  <cfset redirectLoginSuccess="admin.cfm">
  <cfset redirectLoginFailed="login.cfm">
    <cfset EncryptedPassword = hash(form.userPassword,'SHA-384')>

  <cfquery  name="UserAuth" datasource="sql1007539">
  SELECT email,userPass FROM customers WHERE email=<cfqueryparam value='#FORM.email#' cfsqltype="cf_sql_varchar">
  AND userPass= <cfqueryparam value='#EncryptedPassword#' cfsqltype="cf_sql_varchar">
  </cfquery>
  
  <cfif UserAuth.RecordCount NEQ 0>
    <cftry>
      <cflock scope="Session" timeout="30" type="Exclusive">
        <cfset Session.Username=FORM.email>
        <cfset Session.UserAuth="">
      </cflock>
      <cfif IsDefined("URL.accessdenied") AND true>
        <cfset redirectLoginSuccess=URL.accessdenied>
      </cfif>
      <cflocation url="#redirectLoginSuccess#" addtoken="no">
      <cfcatch type="Lock">
      </cfcatch>
    </cftry>
  </cfif>
  <cflocation url="#redirectLoginFailed#" addtoken="no">
  <cfelse>
  <cfset LoginAction=CGI.SCRIPT_NAME>
  <cfif CGI.QUERY_STRING NEQ "">
    <cfset LoginAction=LoginAction & "?" & XMLFormat(CGI.QUERY_STRING)>
  </cfif>
</cfif>

Open in new window

0
 
_agx_Commented:
>  Edit: The script works if no HASH functions are used.

Then doesn't that suggest the passwords in your db table are NOT hashed?  ;-) I know you said they are ..  but .. if that were true, removing the HASH should have the opposite effect.

Let's back up a bit.  Pick a known email and password grab record from the db:

        <cfset form.email = "some known email">
        <cfset form.userPassword = "real password before hashing">
     
        <!--- ONLY match on email ---->
        <cfquery name="qGetData" ....>
            SELECT  *
            FROM     yourTable
           WHERE email=<cfqueryparam value='#FORM.email#' cfsqltype="cf_sql_varchar">
        </cfquery>

Dump the results to the screen. What's the result?

        <cfdump var="#qGetData#">
 
If the db value isn't hashed, that's your problem. If it is, then hash the clear text password and compare it to the db value.  

         <cfset newhash = hash(form.userPassword,'SHA-384')>
         <cfif compare(newHash, qGetData.userPass) eq 0>
                SAME
          <cfelse>
                DIFFERENT
         </cfif>
 
What's the result?
0
 
Claudia_WinterAuthor Commented:
Thank you.
Okay, on first suggestion, CFDUMP I can see that the password is hashed.  However on second suggestion, returns as "different". Could it be the encoding?

NB. If I remove the hash (from original login.cfm), then the authentication works when I store a password in clear text., or enter the hash value that is stored in the database.  If I add the hash function, and run it against a record with a hashed password, it does not work for both clear text and hashed.
0
 
_agx_Commented:
> Could it be the encoding?

Maybe, but we need to see your results.  Create a sample record with some fake data you can share with us like:

         <cfset form.email = "fakemail@somewhere.com">
        <cfset form.userPassword = "real password before hashing">

Then post the results of the earlier tests.

> NB. If I remove the hash (from original login.cfm), then the authentication works ...

Ah, that makes more sense :)
0
 
Claudia_WinterAuthor Commented:
I used test@mail.com
password: password

The password in the CFDUMP matches the record in the database.

A8B64BABD0ACA91A59BDBB7761B421D4F2BB38280D3A75BA0F21F2BEBC45583D446C598660C94CE680C47D19C30783A7

CFDUMP:

CFDUMP of data
Entry in DB:

Entry in DB
0
 
_agx_Commented:
What's the data type of the userPass column?  

Yeah it looks the same visually, but I never trust that .. Can you print out both values as text (don't remove the pipe symbols) and post the result here?

ie <cfoutput>
      db |#qGetData.userPass#|<br>
      form |#hash(form.userPassword,'SHA-384')#|<br>
     </cfoutput>
0
 
Claudia_WinterAuthor Commented:
Datatype: varchar(100), also used char(96) as per suggestion.

The below output is in char(96), I think I can see an extra 7 in the form.

Output:

db | A8B64BABD0ACA91A59BDBB7761B421D4F2BB38280D3A75BA0F21F2BEBC45583D446C598660C94CE680C47D19C30783A|
form |A8B64BABD0ACA91A59BDBB7761B421D4F2BB38280D3A75BA0F21F2BEBC45583D446C598660C94CE680C47D19C30783A7|

varchar(100)

 db | A8B64BABD0ACA91A59BDBB7761B421D4F2BB38280D3A75BA0F21F2BEBC45583D446C598660C94CE680C47D19C30783A7|
form |A8B64BABD0ACA91A59BDBB7761B421D4F2BB38280D3A75BA0F21F2BEBC45583D446C598660C94CE680C47D19C30783A7|
0
 
_agx_Commented:
If there's a "7" missing, then that's why the original query doesn't find a match.  

The "form" value seems to be the correct one.  Can you post the code that INSERT's the password into the db?

BTW: What's the second result at the end of your post?
0
 
Claudia_WinterAuthor Commented:
That's with datatype set to varchar(100)
0
 
Claudia_WinterAuthor Commented:
Insert CFM

  <CFQUERY DATASOURCE="test" NAME="insert" result="insert">

INSERT INTO customers (
             email
           , userPass
           ,honorificPrefix
           ,givenName
           ,additionalName
           ,familyName
           ,property
           ,addNumber
           ,street
           ,locality
           ,town
           ,postalCode
           ,phone
           ,mobilePhone)
<!---SHA-384 - Generates a 64 character hash string using the SHA-384 algorithm
--->
VALUES('#form.email#',' #hash(form.password, "sha-384" ,'UTF-8')#', '#form.title#','#form.firstname#', '#form.middlename#','#form.lastname#','#form.propertyname#' ,'#propertynumber#','#streetname#','#county#','#city#','#postcode#','#telephone#','#mobile#')

</CFQUERY>
<cfoutput>Thanks! Done.</cfoutput>

Open in new window

0
 
Claudia_WinterAuthor Commented:
It works, I could not believe it was a simple issue. Thank you so much.
0
 
Claudia_WinterAuthor Commented:
Very helpful, also a learnt a few tricks for error checking.
0
 
_agx_Commented:
White space is will get you every time ....

For the archives, to be thorough the test code should've included length checks too:

<cfset newHash = hash(form.userPassword,'SHA-384')>
<cfoutput>
      db |#qGetData.userPass#|<br>
      raw len: #len(qGetData.userPass)#<br>
      trim len: #len(trim(qGetData.userPass))#<hr>

      form |#newHash #|<br>
      raw len: #len(newHash )#<br>
      trim len: #len(trim(newHash ))#<br>
</cfoutput> 

Open in new window

0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

All Courses

From novice to tech pro — start learning today.