Solved

Coldfusion: authenticating hashed password

Posted on 2013-05-30
16
683 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
PRTG Network Monitor: Intuitive Network Monitoring

Network Monitoring is essential to ensure that computer systems and network devices are running. Use PRTG to monitor LANs, servers, websites, applications and devices, bandwidth, virtual environments, remote systems, IoT, and many more. PRTG is easy to set up & use.

 
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
 

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

PRTG Network Monitor: Intuitive Network Monitoring

Network Monitoring is essential to ensure that computer systems and network devices are running. Use PRTG to monitor LANs, servers, websites, applications and devices, bandwidth, virtual environments, remote systems, IoT, and many more. PRTG is easy to set up & use.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Suggested Solutions

Pop culture is prime bait for hackers seeking to infect user’s computers and mobile devices with malicious malware. Hackers know exactly what the latest trends are online and know how to use them to their advantage.
With healthcare moving into the digital age with things like Healthcare.gov, the digitization of patient records and video conferencing with patients, data has a much greater chance of being exposed than ever before.
Using examples as well as descriptions, and references to Books Online, show the different Recovery Models available in SQL Server and explain, as well as show how full, differential and transaction log backups are performed
Viewers will learn how to use the INSERT statement to insert data into their tables. It will also introduce the NULL statement, to show them what happens when no value is giving for any given column.

813 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

20 Experts available now in Live!

Get 1:1 Help Now