Solved

Coldfusion: authenticating hashed password

Posted on 2013-05-30
16
675 Views
Last Modified: 2013-05-30
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
0
Comment
Question by:Claudia_Winter
  • 8
  • 6
  • 2
16 Comments
 
LVL 36

Expert Comment

by:SidFishes
ID: 39207781
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
 
LVL 36

Expert Comment

by:SidFishes
ID: 39207833
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
 

Author Comment

by:Claudia_Winter
ID: 39207891
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
 
LVL 52

Expert Comment

by:_agx_
ID: 39208157
>  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
 

Author Comment

by:Claudia_Winter
ID: 39208541
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
 
LVL 52

Expert Comment

by:_agx_
ID: 39208651
> 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
 

Author Comment

by:Claudia_Winter
ID: 39208699
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
 
LVL 52

Expert Comment

by:_agx_
ID: 39208760
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
How your wiki can always stay up-to-date

Quip doubles as a “living” wiki and a project management tool that evolves with your organization. As you finish projects in Quip, the work remains, easily accessible to all team members, new and old.
- Increase transparency
- Onboard new hires faster
- Access from mobile/offline

 

Author Comment

by:Claudia_Winter
ID: 39208808
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
 
LVL 52

Expert Comment

by:_agx_
ID: 39208899
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
 

Author Comment

by:Claudia_Winter
ID: 39208927
That's with datatype set to varchar(100)
0
 

Author Comment

by:Claudia_Winter
ID: 39208935
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
 
LVL 52

Accepted Solution

by:
_agx_ earned 500 total points
ID: 39209008
> '(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
 

Author Comment

by:Claudia_Winter
ID: 39209050
It works, I could not believe it was a simple issue. Thank you so much.
0
 

Author Closing Comment

by:Claudia_Winter
ID: 39209051
Very helpful, also a learnt a few tricks for error checking.
0
 
LVL 52

Expert Comment

by:_agx_
ID: 39209260
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

Featured Post

Backup Your Microsoft Windows Server®

Backup all your Microsoft Windows Server – on-premises, in remote locations, in private and hybrid clouds. Your entire Windows Server will be backed up in one easy step with patented, block-level disk imaging. We achieve RTOs (recovery time objectives) as low as 15 seconds.

Join & Write a Comment

Suggested Solutions

This article explains how to reset the password of the sa account on a Microsoft SQL Server.  The steps in this article work in SQL 2005, 2008, 2008 R2, 2012, 2014 and 2016.
Healthcare organizations in the United States must adhere to the guidance of both the HIPAA (Health Insurance Portability and Accountability Act) and HITECH (Health Information Technology for Economic and Clinical Health Act) for securing and protec…
This video shows how to set up a shell script to accept a positional parameter when called, pass that to a SQL script, accept the output from the statement back and then manipulate it in the Shell.
Sending a Secure fax is easy with eFax Corporate (http://www.enterprise.efax.com). First, Just open a new email message.  In the To field, type your recipient's fax number @efaxsend.com. You can even send a secure international fax — just include t…

705 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

17 Experts available now in Live!

Get 1:1 Help Now