Access Control in ColdFusion - The Basics (part 1) - Security Series #7.2

OK, so I have been putting of this access control stuff for too long. So let's get to it.

In "the basics" we are going to continue our discussion of access control by focusing on controlling how our application is accessed. We are not going to worry about source code files, media or image files, servers, non-web document files, or DBMSs. We are just going to worry about accessing the application from the browser, controlling program flow, etc.

So the first thing to understand is from where we control the access. Most of us have seen attempts to control access from URL strings, cookies, hidden form fields, and other not-so-great methods. these methods are bad and they need to be dragged into the street and shot. Anyone care to guess why they are bad? That's right, friend. Your users have control over them.

Users can manipulate URL strings; they can change, add, and delete form fields; they can even have their way with the cookies you set. I repeat, your cookies are not secure! Not even if they have the secure flag set. The secure flag on a cookie helps to secure it from XSS attacks and from packet sniffing(since SSL is a requirement) but it does NOT prevent your users from changing the values of the cookies and it does not prevent malicious users with access to a machine from harvesting the cookies off of it manually or with a Trojan.

So what is secure? Well, the answer to that is the one area that is not accessible to your users' grubby little paws and each user gets their own. The SESSION scope.

Your client authentication and authorization should be done through the Session scope. You should NEVER rely on user input (after the username and password) to allow a user to gain access to a restricted asset or area.

You may remember I provided a sample of a user login page that sets a simple session variable that uses the following code:


<cfset userValid = application.userService.validateUser(form.username, form.password) />
<!--- Check to see if a valid user was returned --->
<cfif userValid>
<!--- if user was valid, reroute them to their myAccount page --->
<cfset session.isLoggedIn = true />
<cflocation url="myaccount.cfm">
<cfelse>
<!--- If not valid, set error message --->
<cfset errorMessage = "Invalid Username or Password" />
</cfif>

Now this is a very simple example, but if all your application requires is to determine whether or not your user is logged in, then this might suffice. But realistically, you will have more complex permissions in your application. You should at least have a differentiation between the administrator and standard logged in users.

So the code might change a little. Instead of application.userService.validateUser(form.username, form.password) returning a Boolean, it might return a struct:


<cfset sValidation = application.userService.validateUser(form.username, form.password) />
<!--- Check to see if a valid user was returned --->
<cfif sValidation.userValid>

<cfset session.isLoggedIn = true />

<!--- check for admin user --->
<cfif sValidation.isAdmin>
<cfset session.isAdmin = true />
</cfif>

<!--- if user was valid, reroute them to their myAccount page --->
<cflocation url="myaccount.cfm">
<cfelse>
<!--- If not valid, set error message --->
<cfset errorMessage = "Invalid Username or Password" />
</cfif>

It can get more complicated still. We can set any number of variables to the session scope and use them to control access to our application. Take the following example:


<cfset sValidation = application.userService.validateUser(form.username, form.password) />
<!--- Check to see if a valid user was returned --->
<cfif sValidation.userValid>

<cfset session.auth = StructNew() />

<cfset session.auth.isLoggedIn = true />

<!--- set user roles --->
<cfset session.auth.roles = sValidation.aRoles />
<cfset session.auth.permissions = sValidation.aPermissions />

<!--- if user was valid, reroute them to their myAccount page --->
<cflocation url="myaccount.cfm">
<cfelse>
<!--- If not valid, set error message --->
<cfset errorMessage = "Invalid Username or Password" />
</cfif>

Now here, the validation method is returning a struct again, but the struct contains some additional information. To keep my authorization information separate from other session scoped variables, I have created an "auth" struct inside of the session scope.

So our new return struct(sValidation) now contains, in addition to the userValid boolean, arrays of roles and permissions. These arrays can contain role/permission names, role/permission id, or whatever else you like. The key is that the validation method pulled the roles and permissions for that user from the database, added them to an array and inserted them into the struct before it returns it to the calling page. Now, if we need to see if a user is in a certain role, or has a certain permission, we can simple check the session scope.

Next post, we will be talking about how to go about checking the session scope. I'll give you a hint. Our code will not access the session scope directly from the calling page.

Comments
Ben Nadel's Gravatar @Jason,

I know this is not the best place to ask this, but I would definitely be interesting in a good post on the difference between "Authentication" and "Authorization". When I first started learning about security, the fact that these two "actions" were different was hugely confusion to me. Over the years, I have been to take in the idea that Authentication was simply identifiying a user based on credentials (ie. username / password). Then the Authorization was the step that took that authenticated user and assigned permissions.

In your blog post here, I think you are taking those two actions and encapsulating them in the ValidateUser() method.

Anyway, good post; this stuff has always been hacked together by me, so I would love to get a good perspective on that.
# Posted By Ben Nadel | 7/8/08 8:48 AM
Jason Dean's Gravatar @Ben - Thanks for the comment and suggestion. I will look into just such a post. I will take your explanation one step further right now though.

You said "Then the Authorization was the step that took that authenticated user and assigned permissions", and I am sure you also meant that authorization then takes place at each "secured' point in the application where those assigned permissions are compared to the allowed permissions or permission level for that asset to determine if access should be granted.
I will have to give it some thought and research and see if I can define each one in a future post.

Thanks again
# Posted By Jason Dean | 7/8/08 8:58 AM
Ben Nadel's Gravatar @Jason,

Typically, I just authorize once at login and then perhaps perform basic role-check authorization on an item (ex. session.auth.permissions in your post), but really, my security is more along the lines of logged-in / logged-out. That's why i like these posts so much :)
# Posted By Ben Nadel | 7/8/08 9:01 AM
BlogCFC was created by Raymond Camden. This blog is running version 5.9.1. Contact Blog Owner