ColdFusion Best Practices

The following are ColdFusion best practices and recommendations I have used and published in various places and compiled since around 1995 when I first started using ColdFusion. Included in this […]

The following are ColdFusion best practices and recommendations I have used and published in various places and compiled since around 1995 when I first started using ColdFusion. Included in this document are guidelines for performance, security, and readability.

Generally, performance issues will not be a concern unless run repeatedly, such as in a loop, a large data set, or heavily loaded server. Code readability should be the priority in most cases to ensure ease of maintenance and correct logic. The items below are not necessarily in any particular order.

Many of these guidelines have been previously compiled and published by Paul Hassinger at his personal site and others.

Avoid IIF

  • IIF runs about twice as slow as a <cfif>/<cfelse> block
  • Slow performance is compunded when used in conjunction with a delayed evaluation DE function.

Avoid Evaluate

  • Evaluate slows processing since it is determined at runtime. Avoid using it unless there is absolutely no other way to accomplish the task.

Avoid structFind

  • Use struct.key or struct[key] instead for better performance.

Use <cfswitch> instead of <cfif>

  • Using <cfswitch> instead of <cfif> when evaluating a specific expression will perform faster.
  • Performance also increases when using <cfswitch> instead of more than three <cfelseif> clauses.
  • <cfswitch> is also often easier to read.

Use <cfscript> instead of three or more <cfset> statements

  • When using <cfscript> the entire block of code is sent to the ColdFusion engine at once instead of separately with <cfif> statements making it perform much faster.
  • A <cfscript> block is also often easier to read.

Use compareNoCase for comparing two strings

  • Using compareNoCase is a true string comparison. Using compareNoCase should be used unless you can guarantee that the data will not contain a leading 0. For example, using IS or EQ will return true when comparing the two strings of “001” and “0001”
  • Using compareNoCase or compare is significantly faster than using IS NOT

Use listFindNoCase for OR comparisons

  • Using listFindNoCase or listFind is significantly faster than using IS and OR with five or more options

Use arrays instead of lists

  • Lists suffer from slow Java string processing
  • Do not, however, convert an existing list to an array. The processing time to first convert that list to an array will outweigh the advantages of accessing the data as an array.

Use Stored Procedures

  • Performance is increased with the use of stored procedures since it is pre-compiled.
  • Using stored procedures prevents SQL injection since code is pre-compiled and not able to normally change at runtime providing for a more secure environment.
  • Business data logic is separated from the controller and display when using stored procedures. Changing a stored procedure will update data in all applications rather than having to modify each individual one providing for easier code maintenance along with sharing among other applications.

Use <cfqueryparam> for inline queries

  • Using <cfqueryparam> in inline queries will help to prevent SQL injection making sure to use the CFSQLType to verify the data being passed is of the expected type for the database.
  • Using <cfqueryparam> will optimize the query for multiple repetitions. A SQL bind variable is created with some database implementations which will help to optimize database performance.

Avoid <cfmodule>

  • The preferred method is to use a CFC since it is the fastest and most readable.
  • Using cfmodule is slower and less readable than invoking a custom tag with a prefix and a regular custom tag invocation. If not using a CFC, use cfimport to invoke a tag with a prefix or simply include the file.

Don’t use incrementValue

  • Using x = x + 1 is typically more readable and slightly faster than incrementValue(x)

Do not rely on client information

  • As a general rule, do not rely on any client information. This includes URL, FORM, and COOKIE variables. It also includes CGI variables pre-pended with “HTTP_” such as HTTP_REFERRER and in some cases “REMOTE_”. These variables can be spoofed by the client and provide an access point for a security breach.

Use multiple variable scopes away from client to access data

  • Sensitive data should be stored and accessed via a local source such as the database so that the client does not have the ability to modify the data. For example, do not set a cookie which stores whether a user is authenticated or has access to your page. Instead, set a cookie as a hash you create that can access the database to lookup whether that user has access.
  • Make sure that you check for expired data from the database and IP address from the CGI scope for additional security in the CGI scope.
  • To help prevent cross-site scripting (XSS) attacks where a user can manipulate form data, use CGI.HTTP_REFERRER as an added step to prevent a form submission from an invalid location. While the referrer can be overridden by the client, it obscures the ability to submit a form trivially.

Validate client data server-side

  • Even if validating data with JavaScript, all data should be validated server-side. For example, a form that checks for required fields with JavaScript, should also check with ColdFusion upon submission.
  • Variables should be checked for type when possible and verified. Use <cfparam>, <cfargument>. Don’t allow, for example, a float when you want an integer, or even worse, a string when you expect a float.

Use blockFactor to increase query performance

  • Setting the blockfactor may allow ColdFusion to retrieve data from a database in a more efficient manner.
  • Determine the maximum size (in bytes) of each row of returned data and divide that into 32k. That number is your blockFactor.
  • The max blockFactor is 100.
  • Not necessary for queries with less than 100 rows returned.

Scope all variables

  • All variables except for local (var) variables, should be scoped explicitly. Scoping all variables will prevent an unexpected variable from being used in place of the intended one. If the variable is un-scoped, a user could submit a url, form or use a cookie variable in its place to override an un-scoped variable. It also makes code easier to read and maintain since developers can view and link variables directly without confusing them.
  • The following are valid scopes to be set: (variables, form, URL, attributes, caller, thistag, request, CGI, cffile, cookie, client, session, application, server, flash, arguments, this, others such as a database query)

Scope local (var) variables in functions

  • Variables only used in a single function should be scoped locally. This can be done by using the var keyword in a <cfset> or <cfscript> block.
  • Scoping locally will create better management of memory, especially in recursive and nested loops and avoid corrupt variables.

Develop functions for re-use

  • Functions should be autonomous and remain agnostic of other data. Arguments should be used to pull in data from outside of the functions, not other scopes of data.
  • Some exceptions may exist, such as using an application.datasource variable if desired.
  • URL, form, cookie, client, and other variables, however, for the most part should be passed in for function re-use. This is healthy object-oriented coding.

Functions should return a valid type

  • Functions should explicitly set the returntype to catch data problems.
  • No other output should appear. Output should be set to “no” for component functions. Instead, call the function and place the result in a variable. The display of the returned result can be done separately.

Avoid large Query of Query objects

  • Avoid the overhead from a memory and processor utilization aspects of large QoQ objects. Determine if it can be better handled using the database.
  • Manipulate data at the database level whenever possible. This increases performance, maintainability and enables the separation of business logic from display.

Use proper case in filenames and components

  • Name Application.cfc, Application.cfm, or OnRequestEnd.cfm using proper case since this could affect migration to case-sensitive systems
  • Component names should be MixedCaseWords and should match their filenames and all instances where they are called to prevent issues with case-sensitive migrations.
  • All component method names, instance names, and property names should be mixedCaseInitialLower and match in all instances where they are called to prevent issues with case-sensitive migrations. Often it works well to use the format of verbNoun such as getUser or addProduct.
  • URL-accessible components should have lowercase filenames for greatest compatibility with other systems and URLs.

Use lowercase for code

  • Use lowercase for ColdFusion tags to be consistent with the XHTML coding standards
  • Ex: <cfset myVariableName = myNewValue> or <cfif 1 eq 2>

Avoid pound (#) overuse

  • When using a variable in a string, such as a set or invoking as an argument, where possible, use the variable name instead of enclosing it in a string with pound signs.

Include Application files

  • Always include an Application.cfc file or an Application.cfm and OnRequestEnd.cfm file in the root of the site to prevent transversal up the directory path on each request and to prevent any calling of files up the directory tree from the site root. This is a performance and security issue.
  • Also include these files in non-accessible directories to prevent script execution such as an include or configuration directory that only contains settings.

Parse all user input for file paths

  • Tags such as <cffile>, <cfpop>, and <cfftp> need special care in regard to the file paths. Any user input text or non-trusted variable source being used as part of a file path should be parsed and cleaned.
  • Strip the input of all “..”, “/”, “\”, “’”(single quote) unless explicitly needed. If needed, parse the data to retrieve only what is needed to prevent directory transversal or other issues.

Prevent whitespace

  • Use <cfsetting enablecfoutputonly=”true”> to only allow explicit output
  • Excessive whitespace generates additional bytes to be transferred to the client
  • CF 8 is good at whitespace management, however, since business logic is separate from the view it is still best practice.

Avoid <cfdump>

  • <cfdump> is meant as a debugging and development tool not as a display for a production environment. It contains excessive overhead and is a probable pointer for memory issues especially with large object dumps.
  • Error emails and other data dumps should be explicitly defined not using <cfdump>. Use <cfoutput> to only display the information that is needed.

Execute CFCs as objects

  • Components should be placed in a single structure location so they are easy to find. Categorize cfcs in single structure location such as: application.cfc.myComponent.cfc or application.cfc.security.mySecurity.cfc
  • Components should be placed into scope as objects. Use the CreateObject method.
  • If an object doesn’t need to be instantiated, don’t save into scope using its Init() method (don’t create an init method in the CFC for that matter)
  • Do not invoke components manually when called, instead, use the object that was created in scope.

Avoid built-in sessions

  • Do not use the built-in ColdFusion session management. sessionManagement for an application should be set to “false”.
  • Session management is not cluster and load-balanced friendly.
  • <cfsession> and <cfauthenticate> may not be portable across systems during migrations.
  • Note that this guideline may vary depending on requirements and systems used. Even so, it is not as portable if using built-in sessions.

Do not display system information to users

  • Security may be compromised if a user is shown details of a production system. Never display error details such as DSN, table names, and directory paths.
  • If displaying a system error message, it is safer to display from a lookup of error messages from within your code instead of an actual error message from the system.
  • Do not hide the error message in comments on a production system.

Encrypt stored data

  • All sensitive data such as passwords should be stored in a hashed and/or encrypted format.
  • If a system is compromised, hashed or encrypted data will delay and make additional unauthorized entry more difficult.
  • If salting data, do not use the same salt for all records, each element of data should get its own salt.
  • One-way hashes should be used when possible, such as for passwords.

Provide an audit trail

  • Data for systems should provide for an audit trail, at a minimum a logged in user and their action.
  • Depending on circumstances, a full audit trail can be kept to trace back exact data changed.
  • Full audit trails should be stored separately from the production live data. For example, don’t just use the same table and deactivate old records. Instead, put them in another table. This will help with performance for retrieval of those records.

Prevent multiple simultaneous logins

  • For security conscious applications, when managing sessions and authentication through ColdFusion, logins should be limited to a single session, if that is not desired it should be at least kept to a single IP address.
  • This option should be flexible in case users are behind a proxy environment where some information may change such as an IP address and the functionality is no longer desired.

Don’t use WDDX for hardcoded data

  • It is always faster to <cfinclude> a CFML file than to deserialize a WDDX packet of that datastructure.
  • Dynamic data is best implemented using a well-designed XML file.

Store components outside of a publicly accessible directory

  • Holding the components in a web-accessible directory unnecessarily, allows for malicious invocation, a security breach.
  • Only components with functions having access set to “remote” should exist in a publicly-accessible directory, such as web services or flash remoting.
  • Be aware of the risk of making data manipulation publicly accessible. You may desire that a delete record function, for example, requires a hashed key that was created on a previous page in order to complete successfully for additional security.

Don’t use CFX tags

  • Instead use Java tag libraries and use <cfimport>

<cfoutput> should be used for display

  • Only use <cfoutput> for areas of display. Most queries and business logic should be placed outside of a <cfoutput> block.
  • If using queries inside of a loop, consider the possibility of using <cfoutput>’s “group by” feature and run as one query.
  • Minimize <cfoutput> instantiation. For example, do not include a <cfoutput> inside of a loop. Instead, place the <cfoutput> outside of the loop.

Validate HTML and CSS

  • All code should be validated, mostly to XHTML compliant or other similar standards depending on the project.
  • Several browser plug-ins allow for validation from W3C and others which allows for easy validation during development.

Browser tests

  • Applications should be tested in all supported browsers, especially for client side scripting and CSS issues.
  • Microsoft has free time-limited virtual PC images available for download to allow for IE6/IE7/IE8 testing on the same computer. Other browser setups can be done with those images as well.
Share

About ipaul

My name is Paul Hassinger, the founder of ipaul.com. I have been an avid user of computers since a child. I started when I was about 10 years old working on an Atari computer. Since then, I grew and have had exposure to all types of technologies. I started using FIDONet on a BBS as a child and grew to the Internet. My first graphical world wide web experience was in 1993 using Mosaic. Over time I've worked with both small and large computing systems even maintaining systems serving millions of users on some of the largest social networking sites. I hope to use this blog to capture what I've learned over the years and what I do in my daily life so that others and myself may find the information useful.