ColdFusion Security Framework
Besides the operating system and Web server security services, administrators also have ColdFusion's security framework available to them. The migration to the Java platform means a change in ColdFusion's security infrastructure. ColdFusion now
ColdFusion MX introduced a new security framework that completely
ColdFusion offers security in the following areas:
This portion of the chapter focuses on development and user security. CFML security enhancements are discussed in Chapter 7, and resource security (the server sandbox) is covered in Chapter 9, "Creating Server Sandboxes."
ColdFusion's security implementation begins with the ColdFusion Administrator. The Security section of the Administrator allows you to configure the following: the ColdFusion Administrator password, the RDS password, and Resource/Sandbox security. By default, ColdFusion protects Administrator and RDS access with the passwords you enter during installation. The ColdFusion Administrator Password page (Figure 8.24) allows you to disable the ColdFusion Administrator password, or enter and confirm a new one.
Figure 8.24. Use the ColdFusion Administrator Password page to change the Administrator password. To completely disable the password, clear the check box.
Figure 8.25 shows the RDS Password page, which is used to control access to ColdFusion from visual tools (Dreamweaver, HomeSite+, and ColdFusion Studio 5). Disabling RDS security means relying on the Web server and individual database servers for file and data source security.
Figure 8.25. Use the RDS Password page to control the password for Dreamweaver, HomeSite+, or ColdFusion Studio access, or to completely disable the password.
Disabling either the Administrator or RDS password can
User security gives you granular control over your application. This control goes beyond that of the operating system and Web server. The operating system controls local and share access to files and directoriesin other words, NTFS permissions. The Web server's ACLs grant access to files and directories containing code, based upon an authenticated user's credentials. However,
You should already be familiar with authentication and authorization. Authentication is the process of validating a user's identity. The typical paradigm is a user name/login ID and password stored in a user table of a back-end relational database (RDBMS). A user submits a user name and password via the proverbial login form, and its action page fires a SQL query that matches the user's input with the entries in a user table. Some enterprise solutions replace the RDBMS with an LDAP (Lightweight Directory Access Protocol) user directory such as Microsoft's Active Directory, the Sun ONE/iPlanet Directory Server, or Novell's NDS. Some
ColdFusion recognizes two
In ColdFusion security, authorization ensures that the authenticated user has the appropriate credentials to access resources. Rolesgroup memberships defined in a user directorydictate which users have access to what resources. This is undoubtedly similar to some of the models with which you are already familiar. Consider the personnel structure of a typical Web department:
Each individual in the department
In ColdFusion, the
Security Tags and Functions
As previously mentioned, ColdFusion includes tags and functions with which to implement security and access control. Table 8.4 describes the new ColdFusion security tags and functions.
Table 8.4. ColdFusion Security Tags and Functions
Authenticating with <cflogin>
Code all of your authentication logic between
tagsincluding database user name/password lookups, Windows authentication, LDAP logins, and so forth. The
tag creates a container for storing user security informationthe
scope. This scope contains two
User name and password are sent in cleartext using a simple login form. Flash Remoting sends the user name/password over the binary-encoded AMF (Action Message Format) protocol. HTTP Basic authentication sends the user name and password in a Base64-encoded string with each request. Consider using SSL (HTTPS) to secure the user name and password when authenticating with these methods.
The <cflogin> tag accepts three optional attributes:
If authentication is successful, specify the authenticated user's user ID, password, and roles to the <cfloginuser> tag to log the user into the ColdFusion application. The GetAuthUser() function returns the user ID specified in <cfloginuser>. The IsUserInRole() function checks the specified role against the list of roles specified in <cfloginuser> .
If Web server security is used instead of ColdFusion security ( CFLOGIN ), GetAuthUser() returns the value of CGI.Remote_User , which is set by the Web server. If using both Web server security and CFLOGIN , pass the web server's authenticated user ID (for instance, CGI.Remote_User or CGI.Auth_User ) to the <cfloginuser> name attribute to keep Web server security and ColdFusion security in synch. The IsUserInRoles() function requires <cfloginuser> .
Storing Login Information
Login credentials are stored either in a cookie or in the
scope, as determined by the
value as either an
initialization variable or in the
attribute. By default,
sets a nonpersistent cookie in the user's browser, called
. The cookie value is a Base64-encoded string containing the user ID, password, and application name. This in-memory cookie is not written to disk (for example, the
file) and is
Because ColdFusion sends this cookie with every request, users must allow in-memory cookies in their browsers. If the browser disables cookies, then the effect of the <cfloginuser> tag exists only for the current page request. In this scenario, ColdFusion allows you to code the <cfloginuser> outside of the <cflogin> tag in every template you want to secure, in order to persist the login information across page requests.
When storing login information in the Session scope, ColdFusion stores the Base64-encoded user ID, password, and application name in the SESSION.cfauthorization variable. ColdFusion stores this variable in its internal memory space and uses the browser's session cookies ( CFID and CFTOKEN , or JSESSIONID ) for user identification. This is more secure than using cookies for login storage because ColdFusion does not pass SESSION.cfauthorization with every page request. The user's login and session share the same timeout valueand ColdFusion ignores the IdleTimeout <cflogin> attribute.
To use the Session scope to store login information, ensure the following:
login variable is available to all
Best Practice: ColdFusion Sessions and CFLOGIN
Session scope variables are held in ColdFusion memory space. Storing the CFLOGIN authorization variable ( SESSION.cfauthenticate ) in the Session scope ( LoginStorage=Session ) will persist the value for the duration of the user's session. If the user closes the browser without logging out with CFLOGOUT , the authorization value will still persist in ColdFusion memory until the Session scope is cleared when the session times out or the server is restarted. If another user logs in with the same Session ID ( CFID and CFTOKEN or JSESSIONID ) as the authenticated user, that user can impersonate the previously authenticated user.
ColdFusion identifies browser sessions by cookies and URL parameters. A ColdFusion Session ID comprises the CFID , CFTOKEN , and Application name ( applicationname_CFID_CFTOKEN ). When J2EE Sessions are enabled, the Session ID is the JSESSIONID value. A ColdFusion session can be impersonated by passing existing Session ID values on the URL or in cookies.
The following are best-practice steps to prevent session impersonation:
There are several ways to log out a user and remove their login information from ColdFusion. The primary method is to use the <cflogout> tag. ColdFusion MX did a poor job of destroying session information after a user logged out. Table 8.5 lists the circumstances in which ColdFusion logs out the current user and destroys the <cfloginuser> authentication credentials.
Table 8.5. ColdFusion User Logout
does not clear the login information if you authenticate users via Web server security or the HTTP Authorization header. These security
<cfif IsDefined('URL.Logout') and URL.Logout> <cflogout> <cfset StructClear(Session)> </cfif>
Calling StructClear(Session) will not generate a new session id but it will completely empty the SESSION structure.
Basic ColdFusion Login Example
The following code
Listing 8.1. Application.cfm
[View full width]
<cfsilent> <!---#### File name: Application.cfm Description: Demonstrates coldfusion user security with <cflogin>, <cfloginuser>, and <cflogout> Tags. Assumptions: None Author name and e-mail: Sarge (email@example.com) Date Created: July 24, 2002 Change Log: Updated February 20, 2005 ####---> <cfapplication name="OWS" sessionmanagement="yes" sessiontimeout="#createTimeSpan(0,0,0 ,30)#" loginstorage="cookie"> <!---#### Display a nice title in the browser title bar ####---> <cfhtmlhead text="<TITLE>ColdFusion: User Security Test</title>"> <!---#### Set a REQUEST variable to check the login status. ####---> <cfparam name="REQUEST.loggedin" default="true" type="boolean"> <!---#### If the logout URL variable is passed, log off the current user, clear the session, and set the login status to false, then return the user to the login screen. ####---> <cfif IsDefined('URL.logout') and URL.logout> <cflogout> <cfset StructClear(Session)> <cfset REQUEST.loggedin = "false"> <cfinclude template="loginform.cfm"><cfabort> </cfif> <!---#### Call <cflogin> to create the CFLOGIN scope/container. Idle timeout is set to 30 minutes or 1800 seconds. ####---> <cflogin idletimeout="1800"> <!---#### CFLOGIN.name and CFLOGIN.password automatically assume the j_username and j_password values from the login form. If you use some other field naming conventions, you will have to manually set CFLOGIN.name and CFLOGIN.password equal to the corresponding values. ####---> <cfif IsDefined("CFLOGIN.name") and Len(Trim(CFLOGIN.name)) and Len(Trim(CFLOGIN.password))> <!---#### Authenticate the user. For this example, the only valid user is "admin," whose password is "password." CompareNoCase will return a zero (0) if the two strings are identical. ####---> <cfif not CompareNoCase('admin', Trim(CFLOGIN.name)) and not CompareNoCase(Trim (CFLOGIN.password), "password")> <!---#### Pass the authenticated user's name, password, and role to <cfloginuser>, and set login status to true ####---> <cfloginuser name="#CFLOGIN.name#" password="#CFLOGIN.password#" roles="admin"> <cfset REQUEST.loggedin = "true"> <cfelse> <!---#### if the login fails, set bad login notice, set login status to false, and return to the login form. ####---> <cfset REQUEST.badlogin = "true"> <cfset REQUEST.loggedin = "false"> <cfinclude template="loginform.cfm"><cfabort> </cfif> <cfelse> <!---#### If no login is provided, set login status to false and return to the login form. ####---> <cfset REQUEST.loggedin = "false"> <cfinclude template="loginform.cfm"><cfabort> </cfif> </cflogin> </cfsilent>
The Application.cfm checks to see if a user is logged in, and redirects the request to the login page ( loginform.cfm ) if needed.
Listing 8.2. loginForm.cfm
[View full width]
template contains the actual form that submits the user name and password. These are
Listing 8.3. index.cfm
[View full width]
<cfsetting enablecfoutputonly="yes"> <!---#### File Name: index.cfm Description: Index page secured by <cflogin> in the Application.cfm. This page also shows how to use the ColdFusion security functions: GetAuthUser() and IsUserInRole. Assumptions: None Author name and e-mail: Sarge (firstname.lastname@example.org) Date Created: July 24, 2002 Change Log: Updated February 20, 2005 ####---> <cfsetting enablecfoutputonly="no"> <!doctype html public "-//w3c//dtd html 4.01 transitional//en"> <html> <body> <!---#### Use the GetAuthUser function to display the authenticated id ####---> <p><b>Welcome, <span style="color: green"><cfoutput>#GetAuthUser()#</span> </cfoutput>!< /b></p> <!---#### Use the IsUserInRole function to add conditional logic based on the user's group membership (role). ####---> <cfif IsUserInRole("admin")> <p>Based on your login ID, you are permitted to access this section of the site.</p> Please proceed to the <a href="index.cfm" title="This link is for demonstration purposes only">Administrator's section</a>. <!---#### Display the log out link. ####---> <p><a href="index.cfm?logout=yes">Log Out</on></p> </cfif> </body> </html>