What do you mean don't hard code your path in ColdFusion ? ... use ExpandPath()!

Many years ago, I was told "Don't hard code your path" in ColdFusion when reading or writing files to your server.

 

So, I DID NOT "hard code" my paths. Or so I thought. Sample below of what I considered "hard coded"

 

<cffile destination="C:\Inetpub\wwwroot\myfiles\">

Instead I used application variables to hard code my paths.

 

<cffile destination="#application.myfilesPath#">

 

What a mistake! that i recently had to rectify.

 

My move to a Mac and setting up a local development environment brought this mistake to a head. I'm running ColdFusion Developer Edition, Apache, Eclipse, and Subversion. Fire up my browser to test out my local.domain.com and noticed that file upload is broken.

 

Those paths set as application variables work fine on Windows with backslashes, but won't work on my UNIX based Mac which wants /Applications/xampp/xampfiles/htdocs/myfiles

 

Enter the function I'd used before, but not committed to my daily life.

 

ExpandPath()

 

Many ... many ... hours later the site now runs on my mac AND on the windows server.

 

Point to the webroot #ExpandPath('/')#

 

Point to the "myfiles" a subdirectory of the webroot #ExpandPath('/myfiles')#

 

Point to the "otherfiles" not in the webroot #ExpandPath('../otherfiles')#

 

 

ColdFusion 8 date chooser image doesn't appear in CFDIV or CFWINDOW

I've been using the nifty date chooser widget in ColdFusion 8 and love it. Using the <cfform> tag and a <cfinput> tag you simply add the type="datefield" and mask="MM/DD/YYYY". You'll see a small image of a calendar appear next to your input form and when you click on it a nice calendar date chooser will appear.

 

My problems begain when I tried to use this same code inside a .cfm page and used the bind (cfdiv) or source (cfwindow) attribute to point to this separate page. The small calendar image would not appear. I thought this had something to do with the asynchronous nature of cfdivs and cfwindows.

 

But, I've descovered the problem.

 

1. I did not map the CFIDE directory and instead copied all the content of /CFIDE/scripts/ into a directory off the root called /js/cf8/. Then I used <cfajaximport scriptSrc="/js/cf8" tags="cfform,cfdiv,cfinput-datefield">. This SHOULD work. But it didn't. Thanks to the FireBug plug-in (Love this plug-in, if you don't have it running in Firefox 3 get it now). Firebug allowed me to see the source of my external.cfm file. I found the problem.

 

Here is the image tag for my main page calendar icon.

 

<img id="myDatemyForm_cf_button" src="/js/cf8/ajax/resources/cf/images/DateChooser.png"/>

 

And here is the image tag for my external page calendar icon.

 

<img id="myExternalDatemyExternalForm_cf_button" src="/CFIDE/scripts/ajax/resources/cf/images/DateChooser.png"/>

 

No good!

 

So, my solution. Create the directory "/CFIDE/scripts/ajax/resources/cf/images/" off my webroot and copy the image contents.

 

Voila! the calendar image appears and the date chooser works great.

Happy coding.

 

cfmodule displays content twice

I was a bit baffled when I encountered this error. While generating multiple pdfs I used the cfcontentsave wrapped around a cfmodule tag and passed in an id as an attribute. I thought simple enough. But my cfmodule would output the content twice.

 

As we all drift towards XHMTML compliance we begin adding a slash at the end of tags. For example, <img src="foo.jpg" />. In the past we didn't worry about that ending slash.

 

So, my cfmodule was <cfmodule template="foo.cfm" id="1" />

 

It was the darn closing slash that told ColdFusion to output the content twice.

 

ColdFusion.setSubmitChecked Javascript Error

I recently encountered the error "ColdFusion.setSubmitChecked" when loading a page that contained a cfform inside a cfdiv. Below is an example of the code I was using.

 

<cfdiv>

<cfform>

<cfinput type="submit" name="thisButton" id="thisButton" value="submit">

</cfform>

</cfdiv>

 

I had recently updated to version 8.01 of ColdFusion. The thought of that update jogged my memory. This project is using copy of the "scripts" in the root directory. I was NOT pointing to the "scripts" directory under the CFIDE directory. I thought why not? So I archived my old ajax files and moved a fresh copy over from /CFIDE/scripts/. What do you know that solved the problem.

 

That's two bugs I've found AFTER they have been fixed. Guess I'm just lucky that way.

 

 

I'm the new BACFUG Co-Manager

Last week I accepted Sean Corfield's generous offer to be the co-manager for the Bay Area Cold Fusion User Group. As co-mananger I'll run the meetings if Sean can't make it. Help out with finding sponsoers and speakers.

Very excited to have this chance to give back to the community

 

failed: DDXM_S18005: An error occurred in the PrepareTOC phase while building .

I encountered this bug while using ddx and the cfpdf tag in ColdFusion to generate a table of contents (TOC) for my pdf.

 

If you are having the same problem, don't panic there is a solution.

 

Install the ColdFusion 8.01 (or later) update from Adobe.

 

I found the following in the release notes.

 

Issue Number 69567

When the cfpdf tag prepares to generate a table of contents, if any font that is required to create the output PDF is unavailable, the assembler processing fails. The error message is cryptic and only says "cause given". To get more information, enable robust debugging in the ColdFusion Administrator. The full stack trace should show the cause.

 

This could be a separate issue, but it sounds somehow related to the error message I was receiving. Either way, the problem was resolved by version 8.01

 

Securing your ColdFusion Application Part 2

You can find part one of securing your ColdFusion applications here. Part two will focus on securely storing your data.

Step 5 - Use Secure Socket Layer

Use the SSL and https when passing sensitive data to and from your server. This is a no-brainer, but I mention it since passing data insecurely will defeat the purpose storing data securely.

Step 6 - Encrypt your passwords

ColdFusion provides one-way encryption using the hash() function. You won't be able to decrypt the passwords but neither can any hackers. When a user submits their password you'll use the hash function then compare the password with the hashed password value in your database. ColdFusion 7 improved the hash function by adding multiple levels of encryption. Pete Freitag has a nice write up on it at http://www.petefreitag.com/item/270.cfm.

Step 7 - Help users reset forgotten password

In the past developers have used the "forgot password" feature to email users their password or ask them a "secret question/answer". Both methods are a security risk. If you email their existing password, and someone gains access to that email other accounts that use the same password would be compromised. The secret question/answer method may ask the user "the street they grew up on, or high school mascot". This method of password retrieval has gotten more insecure as we share more personal information through social networks. The method I chose is to set a temporary password or reset key in the database and email that to the user. I also insert the date/time of the request so the temporary password/reset key will expire after a period of time (4 to 24 hours).

Step 8 - Encrypt and Decrypt sensitive specifically credit card numbers.

Now, let me start off by saying storing credit card data is risky business. So, unless you really need to store it, you shouldn't. A situation where you might want to store credit card data would be a subscription service. With ColdFusion you can use the encrypt() and decrypt() functions. There are different encryption methods.

 

Application.cfc

 

<cfset request. mySecretKey = GenerateSecretKey('WhateverYouWant')>

 

process.cfm

 

<cfset stringtoDecrypt = "4111111111111111">
<cfset key = request.mySecretKey>
<cfset algorithm = "AES">
<cfset encoding = "hex">

 

#encrypt(stringtoDecrypt, key, algorithm, encoding)#
#decrypt(stringtoDecrypt, key, algorithm, encoding)#

Of course, you could store the secret key in a location other than the application.cfc. This is just an example of how to generate and save the secret key.

Step 9 - Don't use the SA account in the CF administrator

When you create your database, also create a new login user and grant this new user access to your database. But limit access to only database functions you want your application to use. For example insert, update, delete records, but leave out add and dropping tables.

Step 10 - Use Captcha

Add a captcha image on pages that are potential hacking targets. For example you could add captcha to your login page.

 

Well that does it. Happy Coding.

 

Secure ColdFusion Application from hackers – Part 1

Recently, I received a phone call from a former client about an application I worked on in 2001.  The e-commerce site was written during the ColdFusion 5 days and has been running ever since.  Unfortunately, he was calling to say they'd been hacked.  Below are the steps I took to secure the application against sql injection, cross-site scripting attacks and general probing by hackers.

Step 1 - Upgrade to ColdFusion 7 or higher


Running ColdFusion applications on pre-ColdFusion MX (6.1) servers poses some security risks.  Upgrade to ColdFusion 7 or 8 to take advantage of the security measures in this post.  One caveat before you upgrade.  Test out your application on the new version of ColdFusion before deploying it to your production server.  I can't stress this enough.  You don't want your customers seeing errors because you haven't tested out your old code on the new version of ColdFusion. 

 

One error I found with my client was the use of dot notation when naming application variables.  For example, we set common email addresses in the Application.cfm file and used names like application.email.service = "jim@acme.com".  This works fine under ColdFusion 5, but throws a java.exception in ColdFusion MX and higher.  Why is this? Newer versions of ColdFusion added dot notation for simple assignment of structure values "object.property" is a value for the structure called "object". Read more about Structures.

Step 2 – Move from Application.cfm to Application.cfc


Ben Nadel does a great job breaking down the features of Application.cfc in this post.

 

Hackers want information about your application, code, database, etc.  "Oh, the better to hack you with my pretty." (said in your best evil witch voice).

 

Use the OnError() function of Application.cfc to do a few things.  See the code below

<cffunction name="onError">
    <cfargument name="Except" required=true/>
    <cfargument type="String" name = "EventName" required=true/>

  <!--- Throw validation errors to ColdFusion for handling. --->
    <cfif Find("coldfusion.filter.FormValidationException",Arguments.Except.StackTrace)>
        <cfthrow object="#except#">
    <cfelse>

        <!--- First, display a generic message for anyone who encounters an error. --->
        <cfoutput>
        <div>
            Opps, an application error has occured. The webmaster has been notified.</a>.
        </div>
        </cfoutput>

        <!--- Second, fire off an email alerting you an error was generated.--->
        <cfmail to="myname@mydomain.com" from="myname@mydomain.com" subject="Application Error" type="html">
            <cfdump var="#except#" label="Error Details">
         </cfmail>

    </cfif>

    <!--- Third, log all errors in an application-specific log file for later review. --->
     <cflog file="#This.Name#" type="error" text="Event Name: #Eventname#" >
    <cflog file="#This.Name#" type="error" text="Message: #except.message#">
</cffunction>

The less hackers know about your application the better.

Step 3 – Secure any variables passed via Forms or URLs.


Variables passed via URLs are especially vunerable to hackers.  Two ways you can secure them.  First use <cfparam>  and set the type for any numeric values. 

 

For example, foo.cfm?id=1 can easily be modified to foo.cfm?id=1 and 1 = convert(int,(select top table_name from information_schema.tables)). 

 

Add cfparam at the top of your page to prevent non-numeric values.

<cfparam name="id" default="0" type="numeric">

You should also secure all values passed into the cfquery tag.  ColdFuion MX and higher support the <cfqueryparam> tag.  Use it at all times. 

 

Here is the non-secure query

<cfquery name="login"  datasouce="#application.dsn#">
         select *
         from Users
         where UserName = #form.username#
         and Password = #form.password#
</cfquery>

 

Here is the secure query

<cfquery name="login"  datasouce="#application.dsn#">
         select *
         from Users
         where UserName = <cfqueryparam value="#form.username#" cfsqltype="CF_SQL_VARCHAR">
         and Password = <cfqueryparam value="#form. password #" cfsqltype="CF_SQL_VARCHAR">
</cfquery>

STEP 4 – Protect against malicious html code (cross-site scripting attacks).


Hackers will try to insert html code to attack you and/or your users.  They will use the <script>, <object>, <embed> and other tags to run malicious code through your site.

 

ColdFusion 7 Administrator has a setting you can turn on to protect against such an attack.  Login to the ColdFusion Administrator,  and click on Settings.  Near the bottom is a check box for Specify whether to protect Form, URL, CGI, and Cookie scope variables from cross-site scripting attacks.  Check that box!

 

If you want extra protection or can't access the ColdFusion Administrator, there is a great custom tag called CodeCleaner.  Download CodeCleaner here and place it with your other customtags.  Then add this code at the top of your page.

<CF_CodeCleaner  INPUT="#form.UserName#"><cfset form. UserName =clean_code>
<CF_CodeCleaner  INPUT="#form.Password#"><cfset form. UserName =clean_code>

This will remove any "bad" html a hacker may try to insert into pages or a database.

 

That's it for Part 1 of securing your ColdFusion Applications.

 

If you have suggestions for Part 2, please let me know and Happy Coding.

 

Can not login to ColdFusion 8 Administrator

What happens if you forget your ColdFusion Administrator password or for some reason your CF Admin password won't work?  This actually happened the other day.  After moving all my data from my iMac onto an Intel MacBook Pro running Leopard, I found ColdFusion 8 was not starting up.  Decided to uninstall and reinstall ColdFusion hoping this would solve my problems. 

After a couple failed attempts, the install worked and I saw the beautiful Cold Fusion Administrator Setup/Migration screen.  For those not familiar, this is not the regular login screen, but the final step of the install process.  At this point, you enter the ColdFusion administrator password you just created during the installation.  Well, my password would not work.  CF kept returning "Invalid password". 

Hmmmm, I'm "this" close to finishing the install and my password won't work.  Is this some cosmic joke?

Well, I did some poking around my hard drive and discovered a solution.

  1. Shut down ColdFusion 8.  On the mac I launch the Terminal located in the Utilities folder.
    • Enter  sudo /Applications/JRun4/bin/jrun ‚Äìstop cfusion
  2. Use Spotlight to search for the file "neo-security.xml"
    • On my Mac ...
      /Applications/JRun4/servers/cfusion/cfusion-ear/
      cfusion-war/WEB-INF/cfusion/lib/neo-security.xml
  3. Select the file and do Command – I to bring up the Info panel
  4. You'll need to make sure you have Read-Write permissions.


     


     

  5. Open neo-security.xml in any Text Editor
  6. Look for the line
    • <var name='admin.security.enabled'>
                 <boolean value='true'/>
      </var>
  7. Change the value to false
  8. Restart ColdFusion 8
  9. Browse to the http://127.0.0.1/CFIDE/administrator/
  10. Click on "security" on the left side.
  11. Make sure you turn the Administrator Authentication back on and enter a new password.


     


     

Happy coding...

How to perform a cflocation when a session times out using a cfdiv

If you are using the cfform tag inside a cfdiv to submit the form without refreshing the page, then the short answer is you can't do a cflocation outside the cfdiv.

 

This problem cropped up on a recent project. The OnRequestStart function in application.cfc redirects to the login screen when a session times out. This works fine when submitting a form in the main page, but not when the cfform is inside a cfdiv and uses AJAX to refresh the contents of the cfdiv.

 

What does happen? The login screen appears inside the cfdiv. What I want to happen is to redirect the main page (which contains the cfdiv) to the login screen. How cfform functions inside the cfdiv tag is covered in a blog post by Ray Camden.

 

To sum up Ray's post, a cfform inside the cfdiv tag uses ajax to submit the form and return the results inside the cfdiv without reloading the container page. This feature is great and I'm using it extensively, but presents a challenge when using the OnRequestStart function to redirect.

 

The solution is to use javascript for your redirect instead of cflocation. You can download the example code. Below are the main points.

 

See a live example

 

Download the code

 

First you need to modify your application.cfc file.

 

application.cfc

<cffunction name="onRequestStart" returnType="boolean" output="false">
  <cfargument name="thePage" type="string" required="true">

  <cfset request.LogoutNow="false">
  <cfif session.login eq 0>
    <cfset request.LogoutNow = "true">

    <cfset CurrentPage=#gettoken(cgi.CF_TEMPLATE_PATH,listlen(cgi.CF_TEMPLATE_PATH,"/"),"/")#>
    <cfif listfindnocase("index.cfm", CurrentPage)>
      <cflocation url="login.cfm" addtoken="no">
    </cfif>
  </cfif>
  <cfreturn true>
</cffunction>

 

Next, you need to add a hidden form field called LogoutNow to your cfdiv page. You'll also add the AjaxOnLoad function. What does the AjaxOnLoad function do? It's very similar to the onLoad method which you put in the body tag. It fires the javascript function name passed as it's parameter. It only fires after the cfdiv contents are done loading.

 

mycfdiv.cfm

 

<cfparam name="LogoutNow" default="false">
<cfif isDefined('form.SubmitButton')>
  <cfset LogoutNow = "#request.LogoutNow#">
</cfif>

<cfform method="post" name="myForm" action="#cgi.SCRIPT_NAME#">
<p>
This form is a CFFORM inside a CFDIV tag.
</p>
<p>
It will submit asynchronously using AJAX.
</p>
<cfinput type="hidden" name="LogoutNow" id="LogoutNow" value="#LogoutNow#"/>
<cfinput type="submit" name="SubmitButton" value="Submit Form">
</cfform>

<cfset AjaxOnLoad("InitDiv")>

 

In the main page (index.cfm), my javascript function InitDiv is called when the cfdiv is done loading. The CheckLogout function is called and if LogoutNow is true, then reload the main page. This will fire the OnRequestStart function in application.cfc and redirect us to the login screen since our session is expired.

 

index.cfm

<script>
InitDiv = function() {
   CheckLogout();
}

CheckLogout = function() {
   if(document.getElementById('LogoutNow').value =='true') {
     window.location.href = 'index.cfm';
   }
}
</script>

 

Feedback, thoughts or suggestions always welcome.

 

 

More Entries