Tuesday, July 22, 2008

Password encryption and decryption in coldfusion:-

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)#"> <sup>*</sup>
</td>
</tr>
<input name="ID" type="hidden" value="#ID#">
<input name="fuseaction" type="hidden" value="SaveChanges">
<tr>
<td> </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!

1 comment:

Unknown said...

This is completely a new concept for me. I am reading about it for the first time. Its a very interesting subject about which I would love to know more.
digital signature Microsoft