Is there some way to improve these server-side user fields validations?
<cfif Form.LoginName EQ ""><h1>Login Name is required.</h1></cfif>
<cfif Form.Password EQ ""><h1>Password is required.</h1></cfif>
<cfif Form.Password NEQ Form.PasswordConfirmation><h1>Password confirmation does not match Password.</h1></cfif>
<cfif Form.FirstName EQ ""><h1>First Name is required.</h1></cfif>
<cfif Form.LastName EQ ""><h1>Last Name is required.</h1></cfif>
<cfif Form.LoginName EQ "" OR Form.Password EQ "" OR Form.Password NEQ Form.PasswordConfirmation OR Form.FirstName EQ "" OR Form.LastName EQ "">
<p>User has not been created</p>
<p>You can use your browser's back button to keep form fields filled and try again.</p>
<p>Return to users list.</p>
<cfabort>
</cfif>
The way you're coupling your business logic to your display leaves a bit to be desired. You could probably benefit from reading up on MVC and separation of concerns.
From the perspective of your logic, your validation rules seem fine, but you're doing the validation twice, which seems excessive: each element, then all elements. This is in part due to the problem I highlight above.
I'd give some thought to stop thinking procedurally, and think in a more OO fashion, and define the notion of a User.cfc, and have some sort of validation service (see ValidateThis). Or something like that.
Lastly, this is not really the sort of question best asked on Stack Overflow, but would be good for Code Review. There's no one answer for this question, so people will be inclined to suggest closing it for being "primarily opinion-based".
I'm also gonna retag this as just "ColdFusion" rather than "ColdFusion 10", as it really has nothing specifically to do with CF10, it's just a CFML question. You'll get a bigger audience with it marked as just "ColdFusion".
Instead of sharing code with you, I would like to introduce the concepts to you. The first thing you should do is read the OWASP recommendations for Data Validation. In it they suggest that there are four strategies for validating data, and they should be used in the following order. I will post some excerpts here but I strongly recommend you read the entire article.
Accept known good
This strategy is also known as "whitelist" or "positive" validation. The idea is that you should check that the data is one of a set of tightly constrained known good values. Any data that doesn't match should be rejected.
Reject known bad
This strategy, also known as "negative" or "blacklist" validation is a weak alternative to positive validation. Essentially, if you don't expect to see characters such as %3f or JavaScript or similar, reject strings containing them. This is a dangerous strategy, because the set of possible bad data is potentially infinite. Adopting this strategy means that you will have to maintain the list of "known bad" characters and patterns forever, and you will by definition have incomplete protection.
Sanitize
Rather than accept or reject input, another option is to change the user input into an acceptable format
No validation
This is inherently unsafe and strongly discouraged. The business must sign off each and every example of no validation as the lack of validation usually leads to direct obviation of application, host and network security controls.
The article goes on to discuss each of these in greater detail and much more.
This is another way. You can decide for yourself whether or not it is better.
Step 1 - create an error message variable.
<cfset ErrorMessage = "">
Step 2 - Do your checks. If you see something you don't like, append text to your variable.
<cfif len(trim(form.LoginName)) gt 0>
<cfset ErrorMessage &= "<h3>Login Name is required</h3>">
</cfif>
more checks
Step 3 - Check the length of your error message variable
<cfif len(ErrorMessage) gt 0>
display it
<cfelse>
code for no errors
</cfif>
In addition to all this, you probably want to check to see if the page request actually came from your form page. You can use cgi.http_referrer for that.
One more thing. Instead of an anchor tag back to the form page like this,
<p>Return to users list.</p>
You can use javascript so that page does not have to reload in the browser.
<p>Return to users list.</p>
Related
I'm calling a web service through ColdFusion which returns an object, and I want to verify if one of the methods of this object exists as it won't always exist.
I found this source which seemed promising however based on my tests I can see the results are always negative and the method is never found when it's clearly there.
<cfif structKeyExists("#Result.getNotifications().getValidationResult(0)#","getField")>
Result is my underlying object, and my end goal is to verify if the method getField() exists.
Is there a clean way to do this as opposed to a try/catch?
Update:
Unfortunately, I am not sure IsInstanceOf() works with web services, due to the fact that CF uses a Proxy object to "wrap" the underlying web service class. If not, another simple option is to check class name. That avoids the ambiguity of checking for method name only (which could potentially exist in many different classes). Plus I suspect it may be more light-weight than IsInstanceOf() anyway.
<cfif compare(yourObject.getClass().name, "org.tempuri.ValidationResultField") eq 0>
Found ValidationResultField. do something
</cfif>
It looks like the dump contains several different types of objects/classes: ArrayOfValidationResult, ValidationResultField, etecetera. It sounds like what you are really trying to determine is which of those classes you are working with, so you know exactly what fields and methods will be available, per the web service definitions. Given that, I think IsInstanceOf() would be a more appropriate test, than checking for method names. More accurate as well. Nothing prevents two different classes from having the same method name. So even if method X or Y exists, there is still a possibility it may be a different class than expected.
<cfif IsInstanceOf(yourObject, "org.tempuri.ValidationResultField")>
do something
</cfif>
As far as I know, the mentioned structKeyExists approach only works if CF wraps the class internally, e.g. all instances of cfcomponent.
The only option left is to actually reflect the class:
<cftry>
<cfset Result.getNotifications().getValidationResult(0).getClass().getMethod("getField", javaCast("null", ""))>
<!--- method does exist --->
<cfcatch type="coldfusion.runtime.CfJspPage$UnsupportedBaseTypeException">
<!--- method does not exist --->
</cfcatch>
</cftry>
If the method doesn't exist, it throws UnsupportedBaseTypeException, which seems to be a follow-up of NoSuchMethodException.
Honestly, you might as well just invoke the method and catch it. Reflection comes with an additional overhead and you have to catch it anyway.
Like Miguel-F, I think this is something for getMetadata(). The following should return an array containing the respective functions of the object:
<cfset funcs = getmetadata(nameOfObj).functions>
The names of the functions are then funcs[1].name, funcs[2].name, and so on.
In general, you may obtain the metadata of all the functions of a webservice, given the URL of the WSDL, with something like
<cfhttp method="get" url="http://www.webservicex.net/globalweather.asmx?WSDL" result="res">
<cfset wsXml=xmlparse(res.filecontent)>
<cfset wsOperations = xmlsearch(wsXml,"//wsdl:operation")>
<cfdump var="#wsOperations#">
Another method you could look at (perhaps undocumented) is to get the method names from the class names in the stubs directory.
The code to run is:
<cfscript>
wsargs = structnew();
wsargs.savejava="yes";
</cfscript>
<cfset convert=createobject("webservice","url_of_wsdl",wsargs)>
Then figure out how to fish out the names from the stubs directory, {CF_INSTALL}/stubs. In my case, CF_INSTALL is C:/ColdFusion2016/cfusion/
I have a SERVER variable, a structure of structures, which is highly accessed by all users (concurrency). Values are added and deleted very very frequently. Here is a small example of my SERVER variable. The real one has much more data.
<cfset SERVER.structure = StructNew()>
<cfset s = StructNew()>
<cfset StructInsert(s, 'test11', 'value11', true)>
<cfset StructInsert(s, 'test12', 'value12', true)>
<cfset StructInsert(SERVER.structure, 'test1', s, true)>
<cfset s = StructNew()>
<cfset StructInsert(s, 'test21', 'value21', true)>
<cfset StructInsert(s, 'test22', 'value22', true)>
<cfset StructInsert(SERVER.structure, 'test2', s, true)>
Every couple of hours, I loop this structure to clean expired data. However, I am getting the error "null null" while looping the variable like this:
<cfloop collection="#SERVER.structure#" item="key">
<cfif StructKeyExists(SERVER.structure, key)>
<cfloop collection="#StructFind(SERVER.structure, key)#" item="key2">
<!--- And some code here --->
</cfloop>
</cfif>
<cfif StructCount(StructFind(SERVER.structure, key)) eq 0>
<cfset StructDelete(SERVER.structure, key, false)>
</cfif>
</cfloop>
I'm receiving the error in the first line of the example. In this line, exactly:
<cfloop collection="#SERVER.structure#" item="key">
So I tried another approach. Instead of looping one by one, I created an array of keys and looped it. Unfortunately, the "null null" error was also happening there, in this exact line:
<cfset arrayOfKeys = StructKeyArray(SERVER.structure)>
My first theory is that ColdFusion can't handle the concurrency level that this SERVER variable has. I tried to use a <cflock> here, while clearing the variable, but it didn't work either. And I can't have this <cflock> where the variable is actually being used and modified by users because of the extra load that it would add (I believe).
I don't know... I'm out of ideas. Does anyone now why is this happening or have suffered this problem before? And a solution or workaround to this problem, or even a suggestion to make my code better, would be more than welcome too.
Thank you very much.
I tried to use a <cflock> here, while clearing the variable, but it
didn't work either. And I can't have this <cflock> where the variable
is actually being used and modified by users because of the extra load
that it would add (I believe).
This is your problem. If you are using the server scope, you must lock all access to it (read and write). Otherwise you will get errors. That's the long and the short of it.
My first theory is that ColdFusion can't handle the concurrency level that this SERVER variable has
Well: no. ColdFusion will synchronise individual operations to the server scope (well: it's handled at Java level), and that's where its job begins and ends. It's just that your approach doesn't handle it. Namely that you don't take steps to mitigate race conditions in your own code. This assertion of yours:
I am not locking access when I work with the variable because collisions can't happen
Is just wrong. There's a race condition in your loop.
As others have hinted at, this is very poor application architecture, and the code is facile.
Just put the data in a database. That's what databases are for, and they're written in such a way to optimise the sorts of operation you are trying to (but not succeeding, obviously) to achieve here.
I think this is probably a case of premature optimisation: have you had this data in a properly provisioned and designed DB? Or are you second-guessing that it will be a problem? I suspect it's the latter. Or that the DB server was not properly provisioned.
Over and above the database tier, you could also use a caching tier like others have suggested.
But just don't reinvent the wheel, like others have said.
The bottom line answer to your question is that you're getting the errors because you are not correctly locking the data, and you have race conditions in your code, making ColdFusion trying to access data that you have told it is there, but could subsequently have been changed. This is due to your code, not a shortcoming in ColdFusion.
In our index files, at the top of the file we will generally <cfparam> out the variables that will come from the URL, form or wherever. However, we are getting a lot of bots hitting us with things like www.example.com/survey/index.cfm?nPageNumber=-1 meaning a cfparam like this:
<cfparam name="request.parameters.nPageNumber" default="1" type="numeric" />
will fail due to the nonsense a bot is putting into the querystring.
I find myself increasingly having to write my cfparams like this:
<cfif structKeyExists(request.parameters,"nPageNumber") AND isNumeric(request.parameters.nPageNumber)>
<cfparam name="request.parameters.nPageNumber" default="1" type="numeric" />
<cfelse>
<cfset request.parameters.nPageNumber = 1>
</cfif>
While this solves the issue, I can't help but feel this solution is not the best/most efficient. Am I using cfparam correctly or are there better ways of doing this?
Ensuring the existence of a variable, and validating its value are two separate tasks.
In the case of URL and Form your existence code should be something like:
<cfparam name="URL.nPageNumber" default="1" type="string">
The use of type there is just to ensure that nothing truly bizarre has happened such as the value is a struct or query, etc. You don't want to get specific at this point since you want a graceful error and not at 500 for the user.
Once you've made sure that the value exists, you then need to validate the value.
<cfif isNumeric(URL.nPageNumber) EQ false OR URL.nPageNumber LT 1 OR URL.nPageNumber GT Variables.MaxPages>
<cfset ArrayAppend(Variables.ErrorArray, "Incorrect page number requested.")>
</cfif>
You could force the value to something sane, but see Martian Headsets for a counter argument to the robustness principle.
Providing an error message instead of "displaying something sane" will inform your users that they are doing something wrong, and means you're not forced to use canonical urls if you're not already (although you should be).
Yes, it's more work. You can devise some abstraction for it all, but at the raw level, that's what you should be doing with your cfparams and validation.
In the situation where you don't need to have a friendly response, such as a bot or a request that is obviously a hack or probing, there's the additional option to serve a "400" response code. The w3c defines the response as "The request had bad syntax or was inherently impossible to be satisfied." here and "The request could not be understood by the server due to malformed syntax. The client SHOULD NOT repeat the request without modifications." here.
As it currently stands, this question is not a good fit for our Q&A format. We expect answers to be supported by facts, references, or expertise, but this question will likely solicit debate, arguments, polling, or extended discussion. If you feel that this question can be improved and possibly reopened, visit the help center for guidance.
Closed 11 years ago.
In the spirit of my other questions regarding "common programming mistakes ... to avoid"
What are some common programming mistakes for a ColdFusion programmer to avoid?
set <cffile> upload path to a web accessible, CF-enabled directory!!!
isStruct() before isObject() in a series of <cfif>'s expecting isStruct only catches struct (cfc component returns True from isStruct() as well)
no HtmlEditFormat() when displaying user-generated content (XSS)
forgot to add output=false on CFC methods
not using <cfqueryparam> inside <cfquery>
not scoping not-so-evident variables like cfquery name or loop index in a method
use <cfform> when all they need is plain-vanilla HTML <form>
forgot to UrlEncodedFormat() user-defined URL
use <cffeed> without sanitizing the content
trust isDate() too much (any number would return true)
expect string comparison to be case-sensitive (IS and EQ operators are case-insensitive)
sending strings "yes" or "no" to SerializeJSON() without appending a whitespace to preserve the string (otherwise SerializeJSON() or DeserializeJSON() will translate them to "true" and "false")
not putting singletons services in application scope
blindly create as much CFCs as one wants like one would do in JAVA
putting complex value/object into a list (can't, list is just a string of comma-seperated values)
writing functions that takes array as an argument and modify that array expecting that array will be modified (array in CFML is passed by value)
blindly changes access="remote" on a method and expect it to work (when remote proxy is generally more appropriate)
use a lot of WriteOutput() in cfscript when CFML is more appropriate
blindly uses IsDefined() when StructKeyExists() can generally do it more efficiently
blindly uses Iif() and De() without knowing they're as nasty as Evaluate()
update some code in onApplicationStart() and not seeing the difference on refresh (restart the app!)
<cfloop> or '' outside of <cfquery> causing multiple new query connections to be opened. 99% of the time it's better to have multiple statements inside of one cfquery to perform multiple actions, or to UNION data together.
hardcoding absolute path when ExpandPath() is generally better
forgot to turn on Unicode support in DSN (Unicode becomes '????')
not upgrading to the latest JRE and Hotfixes
misusing Client scope and blow up Windows registry...
uses depreciated/obsolete functions/features (i.e. flash form aka flex 1.x alpha, cftable, Verity full-text search, etc...)
passing CFCATCH to a function as argument type Struct (CFCATCH behaves like a Struct, but it is not. Just pass it as type 'Any').
Not reading CFC Best Practices from ColdBox wiki.
buying in the mindset of .ASP(X) or .JSP or [insert web technology] are always better.. ;)
not use PrecisionEvaluate() and getting all sort of floating point rounding error especially when calculating money.
Inappropriate use of #
SELECT *
Not scrubbing URL/form inputs
Debugging on in production environment (even if output is suppressed)
Shamelessly stealing Henry's formatting...
it is faster and more accurate to check explicit boolean instead of implied; use <cfif query.recordCount GT 0> instead of <cfif query.recordCount>
do not use evaluate(), de(), or iif()... ever. there is always a way around these slow functions
understand structures, keys, values and how to access query and structure data using array notation. (this will usually get around your need for evaluate())
do not use pound signs unless you are outputting data or otherwise creating a string (don't do this: myFunction(arg = #myVar#) )
read and understand the difference between THIS and VARIABLES scope in a CFC
avoid extreme overuse of <cfsilent> when you probably need to use a <cfcontent reset="true"> just before you begin your output (before doctype, xml declaration, or <html>)
don't blindly drop ColdFusion values into an HTML script block (javascript) without using jsStringFormat()
if you are not using <CDATA> text in your XML, you may want to use xmlFormat() when creating an XML document
don't use Windows registry for Client scope data. Use the database.
if your IT architecture permits, use Session data instead of Client data.
use <cflock> correctly and consistently; shared data will leak in your Application.
if you are going to use Java objects, understand the Java error messages (for example, 'method cannot be found' may not mean the method does not exist at all, it means the method does not exist for the arguments you've supplied)
if you have to read large files, either use the new CF8 "File" functions or hand off the task to Java on CF6 & 7. <cffile> is inefficient for large files.
understand pass-by-reference and pass-by-value, and how those concepts work in CF; specifically when using functions to modify XML documents
as Henry stated, always use <cfqueryparam>; also ensure that you are using the correct CFSQLType parameter for your DBMS (for date, time, timestamp, etc)
don't chain together a series of <cfif> and <cfelseif> logic blocks, use <cfswitch> and <cfcase> if you have more than three conditions you need to handle
more of an architecture note: always do some sort of server side validation to catch the nasty data the wolf-shirt-wearing user may be passing you
last architecture note: let CF do your middle layer of data retrieval and display and let your webserver do webserver things like SEO URLs (I'm looking at you ColdCourse)
SQL Injection Attacks. It seems like cfquery is just made to allow them. So you should use cfqueryparams.
In Coldfusion, all variables are global by default, unless they are declared with the var keyword. (Somewhat similar to the situation in Javascript.)
So you either have to remember to var every variable used in a function, including things like names that are using in a cfquery name, or you can just use this trick:
<cffunction name="MyFunction">
<cfset var Local = StructNew()>
<!--- Now anything Local. is automatically local --->
<cfset Local.x = 42>
<!--- Including cfquery name="" --->
<cfquery name="Local.Customers" datasource="some_datasource">
SELECT C.ID, C.Name
FROM Customers C
</cfquery>
</cffunction>
There's nothing magic about the name Local, it's just convention. Although Coldfusion 9 will add an explict local scope, so if you use Local it will probably ease upgrading to CF9 when the time comes.
Note that the situation is a tad different for CFCs: In CFCs, the variables scope (the "default" scope) isn't global like it is for normal functions but rather exists per instance of your CFC. So while forgetting to use var is not quite as dangerous in a CFC as it is in a top-level function, the best practice is still to use var all the time.
Failing to prevent users from seeing coldfusion errors.
Add a onError method to a top level Application.cfc to prevent users from seeing those all to detailed dump messages exposing your inner workings(and failings).
<cffunction name="onError" returntype="void" output="true">
<cfargument name="exception" type="any" required="true" />
<cfargument name="eventname" type="string" required="true" />
varscoper is also a great tool for automating the check for variable scoping omissions in components.
http://varscoper.riaforge.org/
Overuse of 'query of query'. That is, further filtering or sorting of query results using the cfquery tag.
This type of work is often done better by the database itself, particularly if the dataset is large.
One of the biggest mistakes would be not using cfqueryparam
Very bad:
SELECT UserName
FROM Customers
WHERE CustomerID = #URL.custid#
Very good:
SELECT UserName
FROM Customers
WHERE CustomerID = <cfqueryparam value="#URL.custid#" cfsqltype="cf_sql_integer">`
Making that mistake will cost you a website.
Putting variables in the wrong scope; even if you don't blow up the registry or crash the server, it's easy to slowly drain performance from your application by bumping variables up to the highest scope in which you think you might need them, or to lose information because you stored it in one scope and tried to access them in a different scope.
Using cfcatch without capturing and/or transmitting some information about the error so that it can be found and fixed. (It's difficult to find an error that doesn't tell you it occurred.)
Using listcontains() when you want listfind(). Especially if the list contains numbers. listfind() matches only an entire item in a list; listcontains() matches part of an item. (Yes, we made this mistake once.)
With administrator access:
Leaving the defaults for a data source set up on the server. "Least privileges" applies on the CF side as well; don't give it any more permissions than it specifically needs. (GRANT, ALTER, REVOKE, DROP ... you don't really want those checked.)
Not checking the boxes for retrieving all the contents from a CLOB/BLOB field when that's what you're expecting. (It was really interesting seeing that applied to a field in which we were storing PDFs.)
Update: Based on the answers I initially went the route of using IsInstanceOf() which was designed for this need. However it turned out to be extremely inefficient for some unknown reason. In debugging the app later I ended up just setting some properties on the object to use instead of IsInstanceOf resulting in orders of magnitude speed improvement.
What I am trying to do is test an object in ColdFusion to see what type of component it is. Something like...
<cfif isValid( "compath.dog", currentObj)>
...do something specific with dog objects...
</cfif>
I thought this was possible but receive an error saying the type I am passing does not correspond to one in the valid list of types...
Valid type arguments are: any, array, Boolean, date, numeric, query, string, struct, UUID, GUID, binary, integer, float, eurodate, time, creditcard, email, ssn, telephone, zipcode, url, regex, range , component, or variableName.
Is there a way to accomplish this in ColdFusion?
You could also use IsInstanceOf(). Though you must still use the full path, it can also be used to determine inheritance or identify components that implement a particular interface.
<cfif IsInstanceOf(obj, "compath.Dog")>
yes. it is a dog component {woof}
<cfelse>
some other type of component
</cfif>
<cfif IsInstanceOf(obj, "compath.AnimalInterface")>
yes. it implements the animal interface
<cfelse>
no. it must be vegetable or mineral ...
</cfif>
You could use GetMetaData to find the type. Some quick code:
<cfif GetMetaData(currentObj).type eq "compath.dog">
you could use name or fullname from the getmetadata() function.
<cfif GetMetaData(currentObj).name eq "compath.dog">
...do something specific with dog objects...
</cfif>
or
<cfif GetMetaData(currentObj).fullname eq "compath.dog">
...do something specific with dog objects...
</cfif>
docs are here getmetadata() on what getmetadata() returns depending on the object type.
Dan, feel free to rip the code out of MXUnit which does exactly what you need to do. We do it in our assertIsTypeOf() assertion. See here for details: http://code.google.com/p/mxunit/source/browse/mxunit/trunk/framework/MXUnitAssertionExtensions.cfc
The reason you're seeing the performance hit with isInstanceOf() most likely has to do with setting this.customTagPaths in your Application.cfc. I hit this myself and filed a bug on it recently. Hopefully it'll get fixed in CF10, whenever that is.