Password encryption for increased security using keys

You might have already noticed that even database servers like Microsoft's SQL Server 2000 have no method of hiding even password fields from prying eyes. Instead passwords are stored as plain text. Not good. Even Microsoft Access provides a way to mask fileds you would prefer not to be easily read. Not so SQL Server - and probably quite a few other database servers suffer the same issue.

This is easily rectified however using two handy functions built-in to ColdFusion, from at at least version 5.0 and above (I think they were in 4.x also). I've developed the following code using CFMX updated 3.

The Problem

Many database servers, including MS SQL Server 2000, will store even fields you designate as a "password" as freely readable text. MS Access allows you to mask a field with characters like your typical HTML form password field. But how secure is it?

You might have access to Secure Sockets Layer (SSL) to encrypt user logins between the client and server - but what happens if other people have access to your database and can read passwords because they are not encrypted or masked in any way? Who do you trust? Using SSL and this method together is an ideal solution. If you cannot use SSL you should at least implement this solution to protect your passwords.

The Solution

The solution is simple. The same technique can be used across multiple sites/applications. We are going to use an application specific "key" to use for encrypting and decryption our passwords. Without the key it is difficult - if not impossible - for the data to be read. The advantage of this solution is that you might use the same password across multiple sites. But with a unique "key" the same password in a database will be different to the same password in another database.

I don't suggest you use this method for "super user" or administration accounts - utilise your OS security for that wherever you can.

The Code

application.cfm

Starting with our "application.cfm" file we are going to define the encryption key.

Add the following lines to the application.cfm file of the application you wish to protect:

<cfif not isdefined("Request.PasswordKey")>
     <cfparam name=
"Request.PasswordKey" default="L2OIhfkjsyIJHK23jhfkuIYU">

</cfif>

We are using the REQUEST scope because it is available to ALL areas of the application and does not require locking (as in application/session variables). Because the application.cfm template is executed before every other template we test if it exists first (CFIF NOT ISDEFINED) - if it doesn't use CFPARAM to set the default. Future iterations of application.cfm will ignore the code in future (unless the server is restarted). The REQUEST scope is ideal for values that rarely change like DataSource Names, Administrator email addresses, Copyright messages, etc.

Important: make the default key value as random as you can.

Using the ColdFusion ENCRYPT function

Encrypt uses a symmetric key-based algorithm in which the same key is used to encrypt and decrypt a string. The security of the encrypted string depends on maintaining the secrecy of the key. Encrypt uses an XOR-based algorithm that uses a pseudo-random 32-bit key based on a seed passed by the user as a parameter to the function. The resultant data is UUencoded and may be as much as three times the original size (keep this in mind when setting the storage limit of your password field in your database).

Below is an example of a password (stored in MS SQL Server) AFTER it has been encrypted using a custom key (not the one above mind you):

%34*4E%P

In order to utilise encryption we need to let the user "register" so that we can encrypt their password. Your user will complete a HTML form and submit the form to our action page. Though not necessary it would be better to use SSL here.

User completes standard Register Now form and submits to our form action page:

<cfset Encrypted = Encrypt(Form.UserPassword, Request.PasswordKey)>
<cfset Form.UserPassword = #Encrypted#>

<cfinsert datasource=
"#Request.DataSourceName#"
             tablename="Users"
            
formfields="UserFirstName,UserLastName,UserPassword,UserEmailAddress">

Assuming no errors have occured your users account will now contain the password they submitted - but in an encrypted form according to the key we defined in the application.cfm.

User now needs to login to our application

In order for our user to gain access to our application we now need to "decrypt" their stored password. Easy with the login form action page like below:

<cfset Encrypted = encrypt(Form.UserPassword, Request.PasswordKey)>
<cfquery name=
"MailingListUpdate" datasource="#Request.DataSourceName#">
SELECT  ID,
            UserFirstName,
            UserLastName,
            UserPassword,
            UserEmailAddress
FROM     Users
WHERE   EmailAddress = <cfqueryparam cfsqltype="cf_sql_varchar" value="#Form.UserEmailAddress#"> 
      AND UserPassword = <cfqueryparam cfsqltype="cf_sql_varchar" value="#Encrypted#">
</cfquery>

User wants to "update" their details

To allow a user to do things like change their password we need to un-encrypt, or decrypt, their password and populate the form password field:

<cfoutput query="UserUpdate">
   <cfform name="UserUpdate" action="index.cfm">
    <table width="100%" border="0">
    <tr>
        <td halign=
"left" valign="top">
            <h5>Password:</h5>
        </td>
        <td halign="left" valign="top">
            <cfinput type="text" name="password"
                        maxlength=
"16" size="20"
                        required=
"yes"
            message=
"Please enter in a password"
            value=
"#Decrypt(Password,Request.PasswordKey)#">&nbsp;<sup>*</sup>
        </td>
    </tr>

        <input name="ID" type="hidden" value="#ID#">
        <input name=
"fuseaction" type="hidden" value="SaveChanges">
    <tr>
   
     <td>&nbsp;</td>
       <td valign=
"top" align="center"><input type="Submit" value=" Save Changes " style="cursor:hand"></td>
    </tr>
    </table>

</cfform>
</cfoutput>

When re-submitted to the database we re-use the encrypt code just as we did when the user registered to encrypt any changes.

Easy!

About This Tutorial
Author: Peter Tilbrook
Skill Level: Intermediate 
 
 
 
Platforms Tested: CF4,CF5,CFMX
Total Views: 62,421
Submission Date: April 14, 2003
Last Update Date: June 05, 2009
All Tutorials By This Autor: 5
Discuss This Tutorial
  • I know this posting of the how to is old but.... I would find it more reliable to just make a cfc which you pass in your password in plain text (you have your key if you aren't going to make your own hash function) and then run the function and return the password as you will store it in a database. Could also be used to validate user entry.

  • When comparing an encrypted database column to a form variable, I find it better to DECRYPT the encrypted value stored in the table, THEN compare to the form.variable instead of attempting to encrypt the form.variable and comparing to the queried value.

  • Always trim(form.variable) form variables. Certain browser, on Mac specialy add empty spaces upon submiting the form. A simple trim() around the submited var should take care of that. I always trim() my form vars. Above example with trim(): My 2

  • click here

  • Just query the database for all the records with the password column you require. The output the query, assigning the encryption and updating the database as it goes. Eg: SELECT ID, UserPassword FROM Users

  • How to loop the database for plain text password field and encrypt the password, so that it can be used to login.

  • in the page to reset password, generate new password, and email it to address in db. then the user can log in anc change password in standard users profile section.

  • just hash it, store it in the db, and hash the form.password to compare before login. use a question/answer validation to authorize to send email addy stored in db only with link to reset password. hash hash hash.

  • If a hacker has access to my database AND code, he has the encrypted password value, and by viewing the application.cfm he now has the password key. So he can just run the encrypt function himself to find the true value of the password. How can I effectively hide the value of of the password key so that my CF pages know what it is, but it is not a field in a database column or a plaintext variable in the code??? Thanks in advance.

Advertisement

Sponsored By...
Powered By...