Encryption is the process of applying a random key and an algorithm to plaintext data (called cleartext) to produce encrypted data (called ciphertext) that is unreadable or meaningless to third parties who do not have the key for decryption. Several places throughout an application can benefit from encryption. One of these is the transmission of sensitive data between a browser and the server. Another can be in the storing and transfer of data within the application. Encryption between servers and browsers is best handled by the Web server through the use of Secure Socket Layers (SSL). ColdFusion MX 7 does offer the Encrypt(), Decrypt(), and Hash() functions, which are useful for encrypting sensitive information before it is written to a database, cookie, or URL variable. These functions, however, are not intended as a replacement for SSL. NOTE The encryption functions are useful for encrypting strings only after ColdFusion has processed them. None of these functions can operate on strings sent by a client's browser to the Web server. Cleartext RisksFor years, a class of software referred to as packet sniffers has existed, with the intended purpose of troubleshooting network issues. These programs work by displaying the contents of each data packet traveling along a network. Although they are necessary tools that help network administrators to do their jobs, in the wrong hands packet sniffers offer an opportunity to expose data not intended to be shared. As previously mentioned, any data sent across the Internet usually passes across the hardware of several networks along the path to the data's destination. If anyone is running a packet sniffer on any of the networks the data is crossing, the data's contents will become visible to those networks. To counter this risk, a number of encryption schemes have been created. Their purpose is not to prevent someone from sniffing a packet but rather to make the contents of that packet unreadable. ColdFusion Encryption FunctionsOne of the rubs against ColdFusion is that it lacks strong encryption capabilities. ColdFusion includes three functions for the encrypting of strings: Encrypt(), Decrypt(), and Hash(). Previous versions of ColdFusion used an XOR-based algorithm, a 32-bit pseudo-random key (based on a developer-provided seed), and UUencoding for Encrypt() and Decrypt(). The Hash() function used the MD5 algorithm in a one-way hash to create a fixed-length, 32-byte hexadecimal string from variable-length string. No matter the size of the original string, the resulting hash was always 32-bytes. NOTE XOR stands for exclusive-or. It is a bitwise or Boolean operator which returns true (or one) if its operands have different values, and false (or zero) if the values are the same. UUEncode (or Unix to Unix Encoding) is a method of converting binary data to ASCII for sending across the Internet. ColdFusion MX 7 now leverages the Java Cryptography Extension (JCE) to the Sun Java run-time. This allows developers to leverage the algorithms of default and third-party JCE providers in the ColdFusion encryption functions. The result is stronger encryption strings for greater security by allowing developers to specify different algorithms, feedback modes, and padding methods. CFMX 7 also adds two additional binary encoding methods to the default UUencode: Base64 and Hex. TIP ColdFusion MX 7 embeds the Sun 1.4.2_05 JVM, which includes the JCE by default. Should you want to change JVMs for Cold Fusion, ensure that your JVM of choice includes the JCEand that the SunJCE provider is the default provider. How Encrypt() and Decrypt() WorkEncrypt() works by using a symmetric keybased algorithm, which means the same key used to encrypt the string must be used to decrypt it. A string encrypted this way is only as secure as the key. If the key is compromised, the string can be decrypted by anyone possessing the key. Also remember that if the key is lost, the data cannot be decrypted. When specifying the default algorithm (CFMX_COMPAT), Encrypt() uses an XOR-based algorithm to create a pseudo-random 32-bit key based on the specified key. Encrypted data can be much larger (potentially as much as three times as large) as the original string. Use the following syntax for CFMX_COMPAT algorithm: encrypt(string, key) To enable strong encryption, specify a Block or Password-Based encryption algorithm. You also need to specify the appropriate optional parameters for the algorithm you want to use. Block encryption ciphers are symmetric-key encryption algorithms that encrypt fixed-length blocks (usually 64- or 128-bits) of plaintext data into same-length blocks of ciphertext. They require binary keys of specific lengths and may require an Initialization Vector (IV). Use the GenerateSecretKey function to create a unique key of the appropriate length. You can manually create binary keys, but you have to ensure that the keys are the correct length for the specified algorithm. This may mean changing the algorithm's default encryption mode and padding methods. ColdFusion will automatically create an Initialization Vector for the specified algorithm. You may also create one manually and pass it to the IVorSalt parameter, but you need to ensure the correct block size for the algorithm. CAUTION The values ColdFusion generates for the Initialization Vector and the generateSecretKey function should suffice for most encryption schemes. ColdFusion will automatically prepend a secure, random Initialization Vector onto the encrypted data. However, if you create your own IV, ColdFusion will not include it with the encrypted data, and you have to keep track of it throughout the application. The generateSecretKey function returns a Base64-encoded binary key of the default length for the specified algorithm that is created using a secure random number generator. It can only be used for Block Encryption algorithms. Password-Based Encryption (PBE) uses passwords or passphrases as keys. For PBE algorithms, ColdFusion will automatically generate a binary salt value. A salt is a random string that is prepended to the specified passphrase and hashed over a number of iterations in order to create the encryption key. ColdFusion will automatically create a secure, random 8-byte salt value and use an iteration count of 1000. You can create your own binary salt value and pass it to the IVorSalt parameter. Use the ColdFusion Decrypt() function to decipher a string that has been encrypted with the Encrypt() function. Decrypt() is a mirror of Encrypt() in that they require the same arguments (refer to the earlier section "Encrypt() and Decrypt() Parameters"). Remember that ColdFusion's encryption is symmetricyou must use the same key to encrypt and decrypt the string. If you use strong encryption (a Block or Password-Based Encryption algorithm) to encrypt the string, then you need to use the same key (seed) or password (salt), algorithm, and IVorSalt values to decrypt it. Listing 7.1 shows an example of using strong encryption with Encrypt() and Decrypt(). Listing 7.1. The Encrypt() and Decrypt() Functions at Work[View full width] <cfsetting enablecfoutputonly="yes"> <!---#### Name of file: encypter.cfm Description: Demonstrates strong algorithms used in Encrypt() and Decrypt() functions. Sarge, Date created: February 9, 2005 ####---> <cfsetting enablecfoutputonly="no"> <!DOCTYPE HTML PUBLIC -//W3C//DTD HTML 4.0 Transitional//EN> <html> <head> <title>ColdFusion MX 7 Encryption Test</title> </head> <body> <h2>ColdFusion MX 7 Encrypter</h2> <cfform name="encrypter"> <table border="0"> <tr><td>String: </td><td><cfinput type="text" name="plainText" size="25" visible="true" required="yes" message="You must provide a string to encrypt."></td></tr> <tr><td>Seed/Password:</td><td><cfinput type="text" name="seed" size="10" visible="yes">< /td></tr> <tr><td>Algorithm:</td><td><cfselect name="algo"> <option value="AES">AES</option> <option value="Blowfish">Blowfish</option> <option value="DES">DES</option> <option value="DESEDE">Triple DES</option> <option value="PBEWithMD5AndDES">Password With DES</option> <option value="PBEWithMD5AndTripleDES">Password With TripleDES</option> </cfselect></td></tr> <tr><td>Encoding:</td> <td><cfselect name="encode"> <option value="UU">UUencode</option> <option value="Base64">Base64</option> <option value="Hex">HEX</option> </cfselect></td></tr> <tr><td> </td><td><input type="submit" name="Submit" value="Submit"> <input name="Reset" type="Reset"></td></tr> </table><br /> <a href="index.cfm">Back to index</a> </cfform> <cfsetting enablecfoutputonly="yes"> <cfif isDefined('FORM.algo')> <!---#### Set a default Seed/Password value in case user does not submit one. ####---> <cfif NOT len(Trim(Form.seed))> <cfset FORM.seed = "simpleseed"> </cfif> <!---#### Perform encryption with default ColdFusion Compatible algorithm (CFMX_Compat). ####---> <cfset variables.compatText = encrypt(FORM.plainText, form.seed)> <!---#### Scope for Block or Password Based Encryption. ####---> <cfif NOT ListFindNoCase("PBEWithMD5AndDES, PBEWithMD5AndTripleDES", FORM.algo)> <!---#### Use generateSecretKey to create a secure, random key for the chosen Block Encryption algorithm. ####---> <cfset variables.key = generateSecretKey(FORM.algo)> <!---#### Encrypt() and Decrypt() must use same key, algorithm, and encoding values. ####---> <cfset variables.cipherText = encrypt(FORM.plainText, variables.key, FORM.algo, FORM .encode)> <cfset variables.origText = decrypt(variables.cipherText, variables.key, FORM.algo, FORM.encode)> <cfelse> <!---#### Use Password Based Encryption (PBE) algorithms with submitted seed/password value (FORM.seed). ####---> <cfset variables.cipherText = encrypt(FORM.plainText, FORM.seed, FORM.algo, FORM.encode)> <cfset variables.origText = decrypt(variables.cipherText, FORM.seed, FORM.algo, FORM .encode)> </cfif> <cfoutput> <hr> <table border="0"> <tr><th align="left">Original String:</th><td>#FORM.plainText#<br></td></tr> <tr><th align="left">Seed/Password:</th><td>#FORM.seed#<br></td></tr> <tr><th align="left">CF Encrypted:</th><td style="color:##FF0000">#variables.compatText#< /td></tr> <tr><th align="left">#FORM.algo# Encrypted:</th><td style="color:##009900">#variables .cipherText#</td></tr> <tr><th align="left">Encoding:</th><td style="color:##009900">#FORM.encode#</td></tr> <tr><th align="left">Decrypted:</th><td style="color:##0099CC">#variables.origText#</td></tr> </table> </cfoutput> </cfif> <cfsetting enablecfoutputonly="no"> </body> </html> The code in Listing 7.1 displays a form that allows the user to submit a string to encrypt, a password or seed value, the encryption algorithm, and encoding. The string is encrypted using the seed, algorithm, and encoding values. The Block Encryption algorithms will use generateSecretKey() to create a secure, random key. Only the CFMX_Compat and PBE algorithms will use the submitted seed/password value. The decrypt function requires that all parameters be the same as the values used to encrypt the string. Finally, the original string, encrypted string, encoding, and decrypted string are output. Figure 7.1 shows the original ColdFusion-compatible-encrypted, strong-algorithm encrypted, and decrypted strings, and encoding shown in Listing 7.1. Figure 7.1. The Encrypt() and Decrypt() functions are useful for setting sensitive data into a cookie because a user won't need to interact with it directly, but it will be sent as cleartext (with some exceptions) on each request to the site.NOTE The embedded 1.4.2 JVM uses the /dev/random device to seed the PRNG (pseudo-random number generator) used by the Java SecureRandom() calls that generate secure, random values. Random JVM hangs may occur if the seed data source runs out of entropysee Java bug 4705093 at http://developer.java.sun.com/developer/bugParade/bugs/4705093.html. ColdFusion does not normally use this device, but the encryption functions now rely upon it. Read more about SeedGenerator errors in ColdFusion in TechNote 19127 at http://www.macromedia.com/cfusion/knowledgebase/index.cfm?id=tn_19127. The workaround for this is to alter the URL to the entropy device in the java.security file; change it from /dev/random to /dev/urandom. Encrypt() and Decrypt() FunctionsListing 7.1 illustrates how to use Encrypt() and Decrypt() to secure plaintext data. This section will describe the parameters for these functions. Both have two required parameters: string and key. The first required parameter is the plaintext string to be encrypted; the second is a key or seed value used to encrypt the string. CFMX 7 adds four optional parameters: algorithm, encoding, IVorSalt, and iterations. Here is the new syntax of for each function: Encrypt(string, key, [algorithm ,encoding ,IVorSalt ,iterations]) Decrypt(string, key, [algorithm ,encoding ,IVorSalt ,iterations]) Following are descriptions of the parameters for Encrypt() and Decrypt(). StringRequired. This is the plaintext string to encrypt, or ciphertext string to decrypt. (Always interpreted as a UTF-8 string for ColdFusion.) keyRequired. This is the encryption key (seed) or password (salt). Can be:
algorithmOptional. This is the algorithm used to decrypt the string. ColdFusion includes a backward-compatible algorithm as well as the default algorithms supported by the SunJCE provider:
EncodingOptional; you must specify the algorithm parameter in order to use encoding. This is the binary encoded representation of the encrypted string. Can be:
IVorSaltOptional; you must specify the algorithm parameter in order to use IVorSalt. This is Initialization Vector or Salt, for Block or PBE algorithms, respectively.
IterationsThis is the number of times to hash the password and salt to produce the encryption key for PBE algorithms. Must be a positive, nonzero number (default value is 1000). Optional; you must specify the algorithm parameter with a PBE algorithm in order to use iterations. NOTE The ColdFusion MX 7 documentation does not fully cover all the enhancements and parameters to the encryption functions. See the "Macromedia Encryption" TechNote for greater detail, at http://www.macromedia.com/go/e546373d. CAUTION You will receive the following error if you try to use some of the stronger algorithms (e.g. PBEWithMD5andTripleDES) or key size lengths:
For unlimited strength cryptography download the JCE Unlimited Strength Jurisdiction Policy Files 1.4.2 at http://java.sun.com/j2se/1.4.2/download.html#docs. Backup the current local_policy.jar and US_export_policy.jar in cf_root/runtime/jre/lib/security, and replace them with the jar files in the downloaded jce_policy-1-4-2.zip. ColdFusion's Hash() FunctionThe other function in ColdFusion for obfuscating data is the Hash() function. Hash() provides one-way encryption, meaning there is no way to decrypt a string after it has been hashed. In previous versions of ColdFusion, this worked by taking using the MD5 algorithm to convert a plaintext into a 32-byte, hexadecimal string. In CFMX 7, the Hash() function also leverages the message digests supplied by the SunJCE provider. The syntax for Hash() is: Hash(string[, algorithm[, encoding]] ) Following are descriptions of the parameters and algorithms for Hash(). StringRequired. This is the plaintext string to hash. AlgorithmOptional. This is the algorithm used to decrypt the string. ColdFusion includes a backward-compatible algorithm, as well as the default algorithms supported by the SunJCE provider:
encodingOptional; you must specify the algorithm parameter in order to use encoding. The encoding used when converting the string into byte data; used by the hash function. Default is UTF-8 (or the value specified by the defaultCharset entry in cfroot\lib\neo-runtime.xml. Must be a value recognized by the JRE. TIP The encoding value is ignored when using the CFMX_COMPAT algorithm, which always produces a hexadecimal string. Specify the MD5 algorithm if you want to use a hash similar to CFMX_COMPAT but produce a different encoded string. Listing 7.2 shows how to use the Hash() function. Listing 7.2. Encrypting with the Hash() Function[View full width] <cfsetting enablecfoutputonly="yes"> <!---#### Name of file: hasher.cfm Description: Demonstrates strong algorithms used in the Hash() function. Sarge, Date created: February 9, 2005 ####---> <!---#### Set the default encoding. ####---> <cfparam name="FORM.encode" default="UTF-8" type="string"> <!---#### Create a object to hold all of the charsets available to the JVM. ####---> <cfobject type="java" name="cs" action="create"> <cfset variables.charSets = cs.availableCharsets()> <cfsetting enablecfoutputonly="no"> <!DOCTYPE HTML PUBLIC -//W3C//DTD HTML 4.0 Transitional//EN> <html> <head> <title>ColdFusion MX 7 Hash Test</title> </head> <body> <h2>ColdFusion MX 7 Hasher</h2> <cfform name="hasher"> <table border="0"> <tr><td>String: </td><td><cfinput type="text" name="plainText" size="25" required="yes" message="You must provide a string to hash."></td></tr> <tr><td>Algorithm:</td><td><cfselect name="algo"> <option value="MD5">MD5</option> <option value="SHA">SHA-1</option> <option value="SHA-256">SHA-256</option> <option value="SHA-384">SHA-384</option> <option value="SHA-512">SHA-512</option> </cfselect></td></tr> <tr><td>Encoding:</td> <td><cfselect name="encode"> <cfoutput> <cfloop collection="#charSets#" item="set"> <option value="#charSets[set]#" <cfif findNoCase(FORM.encode, set)>selected< /cfif>>#charSets[set]#</option> </cfloop></cfoutput> </cfselect></td></tr> <tr><td> </td><td><input type="submit" name="Submit" value="Submit"> <input name="Reset" type="Reset"></td></tr> </table><br /> </cfform> <a href="index.cfm">Back to index</a> <cfsetting enablecfoutputonly="yes"> <cfif isDefined('FORM.algo')> <!---#### Perform the hash using submitted algorithm and encoding. ####---> <cfset variables.theHash = hash(FORM.plainText, FORM.algo, FORM.encode)> <cfoutput> <hr> <table border="0"> <tr><th align="left">Original String:</th><td>#FORM.plainText#<br></td></tr> <tr><th align="left">CF Hash:</th><td style="color:##FF0000">#hash(FORM.plainText)#</td></tr> <tr><th align="left">#FORM.algo# Hash:</th><td style="color:##009900">#variables .theHash#<br></td></tr> <tr><th align="left">Hash Length:</th><td style="color:##0099CC">#len(Trim(variables .theHash))# characters</td></tr> <tr><th align="left">Encoding:</th><td style="color:##009900">#FORM.encode#</td></tr> </table> </cfoutput> </cfif> <cfsetting enablecfoutputonly="no"> </body> </html> The code in Listing 7.2 shows how to hash a string with strong algorithms. Figure 7.2 shows the output of this code. Because it provides one-way encryption, Hash() creates a fingerprint of the original string. This is most useful for storing sensitive data into a database in such a way that even if the database security were compromised, the data itself would not be. You'd then compare a hash of a user-submitted string to the fingerprint in the database. This is particularly useful for things like passwords: <cfquery name="checkuser" datasource="#dsn#"> SELECT userID FROM user WHERE username ='#FORM.username#' and password ='#Hash(FORM.password, FORM.algorithm)#' </cfquery> Figure 7.2. The original ColdFusion-compatible, and strong-algorithm-hashed string output from Listing 7.2. Encoding display will vary depending on system-supported character sets.TIP As with the Encrypt() and Decrypt() functions, you must use the same algorithm when comparing hashed strings. Of course, neither Hash() nor Encrypt() will protect data being sent from the client's browser to the server. For this, you'll need to use SSL, and we'll take a look at that in the next section. SSL is a commonly used protocol for securing message transmission across the Internet. It operates between the Application (HTTP) and Transport (TCP) layers of the OSI (Open Systems Interconnectivity) model. SSL clients are included as part of most major browsers, including Microsoft Internet Explorer and Mozilla Firefox, and the SSL protocol is built into (or can be added to) most modern Web servers. SSL uses the public-and-private key encryption system from RSA (www.rsasecurity.com), which also includes the use of digital certificates. As such, the responsibility of securing data as it travels across the Internet is not the responsibility of the ColdFusion Application Server. Installing Third-Party JCE ProvidersThe JCE allows you to specify multiple cryptographic service providers. You can install third-party Java security providers to extend ColdFusion's algorithms, feedback modes, and padding methods. ColdFusion MX 7 installs the Sun 1.4.2_05 JVM, which is automatically configured to use the SunJCE providers. One popular third-party security provider is the Bouncy Castle Crypto API from the Legion of the Bouncy Castle. To enable a third-party provider you need to place the provider's libraries (typically packaged in a jar or Java Archive file) into the JRE Libraries Extension directory (jre/lib/ext). Then add the provider's package name to the provider list in the security properties file (java.security). Use the following steps to install, configure, and use the Bouncy Castle Crypto API in CFMX 7:
The following Bouncy Castle Block Encryption algorithms will be available to Encrypt() and Decrypt():
The following Password Based Encryption algorithms will be available to Encrypt() and Decrypt():
The following algorithms will be available to Hash():
Enabling SSL on a ServerSSL uses a public key/private key combination to securely send data between client and server. After the decision has been made to use SSL, a system administrator must obtain an SSL certificate and install it on the server. NOTE Certificates have a definitive life cycleusually six months to a year. Some CAs will automatically send you a renewed certificate. Needless to say, SSL cannot be used on a Web server where it is not installed. The steps for enabling SSL on various Web servers will vary. Listed here are instructions for enabling SSL on three popular Web servers: Microsoft Internet Information Server (IIS), Sun ONE Web Server, and Apache Web Server. IISSecuring IIS is a two step process: first installing an SSL server certificate, and then requiring secure communications. The Internet Services Manager for Windows 2003 contains a Security Wizard for creating requests for and installing a SSL certificatefrom your own Certificate Authority (CA) or from a reputable third-party authority such as VeriSign. TIP VeriSign is one of many certificate authorities available. You can find a comprehensive list of available certificate authorities at http://dir.yahoo.com/Business_and_Economy/Business_to_Business/Computers/Security_and_Encryption/Software/Encryption/. Follow these steps to activate the Security Wizard:
The first step of securing IIS, installing the SSL server certificate, is completed as soon as you have imported your valid certificate or key file. You can now import the same certificate or key file into other virtual servers. Next, you must require secure access to your virtual server. Follow these steps to enable SSL communications:
Sun ONESecuring the Sun ONE Web Server (IWS) is also a multistep process. First, you must create the trust database, where the certificates will be stored. Then you can submit a certificate request and install the issued certificate in your server. Follow these steps to create a trust database:
The server will generate your certificate request and send it to the CA using the submittal method you chose. Typically, no matter which method you chose, the CA will send a receipt confirmation by email. If the CA grants your certificate request, it will email your certificate encrypted with your public key. You can either save the email to a file or copy the certificate text in the email for pasting into the Install Certificate form. Use the Trust Database password and the following steps to arrange for the server to decrypt your new certificate and install it:
Your server certificate is stored in the virtual server's certificate database: sunone_root\alias\<server alias>-cert7.db. You can now enable SSL on your server, as follows:
ApacheThe Apache Foundation's Apache HTTP Server (httpd.apache.org/) does not ship with SSL capabilities because of governmental export policies as well as RSA licensing restrictions (Apache is intended for free worldwide distribution). However, SSL packages are available for Apache:
In addition, there are full versions of Apache that include SSL distributed by other vendors, including:
NOTE This chapter focuses on implementing SSL in the freeware Apache HTTP Server. For implementing SSL in one of the commercial flavors of Apache, see the vendor's documentation. You can enable SSL in the Apache HTTP Server with one of the SSL modules. The most common module to use is mod_ssl, which supplies an interface to the OpenSSL package. After installing Apache, compile and link the mod_ssl library.source with OpenSSL. See www.apache.org/docs for details on applying, compiling, and linking the Apache source code. To create an SSL certificate with OpenSSL, follow these steps:
For more information on configuring, administering, and using Apache, see www.apache.org. Forcing a Page Request to Use SSLAlthough ColdFusion has no part in the SSL handshake (it is strictly a function between the browser and Web server), an astute developer can take precautions to ensure that secure pages are only accessed via SSL: <CFIF FindNoCase("off", CGI.HTTPS)> <CFLOCATION URL="https://#cgi.server_name##cgi.script_name#?#cgi.query_string#"> <CFABORT> </CFIF> This code begins by checking the HTTPS variable of the CGI scope. When a connection is coming across the SSL, this variable is set to "on". If CGI.HTTPS is set to "off", the <CFLOCATION> tag redirects the user to the same page using the HTTPS protocol rather than HTTP. SSL LiabilitiesAlthough SSL is great for encrypting communications between the client and Web server, handling the encrypting and decrypting puts an enormous burden on the Web server, impeding performance. For this reason, it's important only to use SSL when sensitive data is being passed. SSL accelerators are a hardware-based solution that off-loads the SSL processing from the Web server, which can vastly improve performance. Unfortunately, these accelerators can be quite expensive and are often too costly for use in many applications. Securing ColdFusion in Distributed ModeIf you are concerned about snooping on your wire, consider encrypting the connections between the major parts of your application: the Web server, ColdFusion server, and database server. Typically, the Web server and ColdFusion reside on the same machine, so you only need to worry about the network connection to the database. However, ColdFusion is capable of running in Distributed mode, where the Web server is on a completely separate machine. In this configuration, you may also want to encrypt the connections between all machines: ColdFusion to Web server, ColdFusion to database server, and Web server to database server. You can do this with SSL, with hardware, or with a Virtual Private Network (VPN). As mentioned in "SSL Liabilities," SSL communications tend to be slow, and hardware accelerators are expensive. VPNs are widely used in server farms, where each machine has at least two NICsone with a publicly accessible IP Address, the other with the private address. All internal interserver communication happens on the private addressthe VPN.
For more information on configuring ColdFusion in Distributed mode (versions 6.x7), see the "Running Macromedia ColdFusion in Distributed Mode" article in Macromedia ColdFusion Developer Center, at www.macromedia.com/support/coldfusion/administration/cfmx_in_distributed_mode/. For more information on encrypting the Distributed mode connection with SSL, see Macromedia TechNote 18203, "JRun 4: Using SSL in JRun Web Server Connector" at http://www.macromedia.com/go/tn_18203. |