Notes: Application Security on ColdFusion

Presented by Pete Freitag.

Unchecked Input

Cause of most security problems. Recommend at least doing server-side validation: isValid(), using RegEx, etc. Client-side validation is good and more convenient for the user, but server-side validation is vital for true application security. For a web application, inputs are forms, URL, cookies, HTTP Request headers (the CGI scope in CF). Beware the values from all of these.

Uploading Files

A common task that can be very dangerous. People can upload a file and then execute that file on your server. In <cffile>, many peole use the accept="" attribute to limit the kinds of files you can upload, but this isn't the greatest approach. A hacker can spoof the mime type. So, could upload a ColdFusion page, spoof the mime type, and execute the ColdFusion page. This spoofing can easily be done with ColdFusion.

Best practices: Upload to a directory outside the web root or to a static content server. Always check the file extension (cffile.serverFileExt), although this is obviously not reliable, but it would stop someone from executing a ColdFusion page when it has an image mime type (as an example). Use the accept="" attribute, just don't rely on it. Also check the filename to avoid XSS. Otherwise, a person could have JavaScript in the filename that could be executed. The combination of these things would make it very challenging to exploit uploading.

Cross Site Scripting (XSS)

Doesn't just have to be JavaScript. Can be Flash, a Java applet, etc.

What's so bad about it? You can steal someone's cookies. Using their cookies, you can steal their session and effectively be logged in as them on the websites they've visited. Phishing: Very tricky to a user; it truly appears as if the page is coming from the company (it basically is), yet the behavior is changed.

Example of a very easy way to test XSS exploitability of a site, you can do a <script>alert("XSS");</script> into a field that will be displayed on an action page. For instance, a search form's action page may say, "Your search for xyz found n results." If xyz is a script tag with some JavaScript, they can be exploited with XSS!

When phishing, it is common to modify the behavior without the user knowing, even after the modified behavior has taken place. For instance, on a login form, the JavaScript would send the credentials to the phisher's server and then continue to pass the credentials as the form originally was written, so that the login would continue without the user being aware that their credentials were just stolen.

An attacker can use String.fromCharCode(ascii,values,for,the,chars,they,want,to,use). They can use this to write scripts that don't use quotes. Sometimes people try to prevent XSS by escaping the quotes or apostrophes, but this code can avoid that.

<cfapplication> has a scriptProtect="" attribute. But this can be easily averted as well.

Preventing XSS. Escape HTML tags and quotes with XMLFormat() and HTMLEditFormat().  Even better than just escaping characters is just stripping them out completely. Validate your inputs, including on the server-side. Also enforce maximum string lengths (again, not just on the HTML side, but on the server side). This can be very effective because often XSS requires an unusually large amount of characters compared to the expected amount.

SQL Injection

Fortunately, easy to prevent, but it is very dangerous when it isn't prevented.

A common query that has:

SELECT * FROM News WHERE id=#URL.ID#

May have a URL like this to hack it:

/news.cfm?id=8;DELETE+FROM+News

Somebody might try to find this out by running a spider that will do requests that will cause errors, like having alpha characters when a URL parm is expecting a number. If ColdFusion error handling isn't set up well, you might even get the default error message, which may even show the code causing the error! This will also give you insight into the name of the table that the query uses. You could then see very easily if the code is susceptible to SQL Injection, and do it.

The solution is easy. Just use <cfqueryparam value="" cfsqltype="">. This puts a placeholder in the query saying, "This is variable #1. And here's the value for value #1." Because this approach is typed, mistyped data will cause an error.

You want to beware of SQL Injection in ALL query types, not just your SELECTs! Put it in your DELETE/UPDATE/INSERT statements as well.

Cross Site Request Forgery (CSRF)

A script on a website can execute in the background, perhaps with Ajax, in behalf of a logged-in user, to do things on that website for that user without their knowledge. Nasty.  "Samy" on MySpace did this to make 1 million friends in less than 20 hours. When people visited his page, JavaScript would use Ajax to have them add him to their profile as a friend.

How to mitigate CSRF? Have server-side confirmations. Require HTTP POST when performing operations, although this isn't a great way to stop it. Don't allow foreign HTTP referrers, although this also can be spoofed. Perhaps require reentry of a password for very sensitive operations. Finally, here's a good one: Include a hash in the form as a hidden field, a hash of the credentials. That way, you know for sure if the action came from your form. This obviously couldn't be spoofed without knowing it.

CRLF (Carriage Return) Injection in the HTTP Header

Injecting CRLFs into the header (for instance, with <cfheader> in ColdFusion), you can add your own headers. Additionally, two empty headers indicates that the body of the page should begin. So if you inject two empty headers, you could then put in whatever content you wanted, for instance, some JavaScript that would redirect the cookies somewhere to use them later.

Session Hijacking

We've touched on this a bit with previous methods. When passing in CFID/CFTOKEN, if they are put in the URL scope, this can be very dangerous! Can be seen in the "Referred" by other sites leaving your page. Also, with traffic sniffing, you could see what the requesting URL and POST data is, and hijack the session in that way. Especially with insecure wifi, this is very dangerous.

How to prevent? Use SSL.  Don't put session IDs in the URL. Use long session IDs in ColdFusion Administrator ("Use UUID for CFTOKENS"). If someone is sniffing, that won't help, but when your CFTOKEN isn't a long UUID, people could just increment through values and try to get valid ones via automated trial/error requests. UUIDs will just make it more random. And you could do integrity checking. Ask: Is this session suddenly changing their user agent? That wouldn't make sense, and reset session.

Best Practices for Security

Don't disclose server details. Don't show file paths, source code, database tables in error messages. So have <cferror> or site-wide error handling.

Require SSL/HTTPS. Prevents sniffing. Browsers may run at a higher security level, so the browser can help you. Use secure cookies when on SSL. Just add secure="true" to your <cfcookie> tag. Will make the cookie never be sent unless you're on a secure connection.

Validate everything! That's what the hackers are looking for, places where inputs/outputs aren't being validated.

ColdFusion Content Management Systems

While at CFUnited 2007, these are some of the ColdFusion content management systems I have seen.

Commercial

Open Source

Paper|Thin has a whitepaper available for download that discusses how to choose a CMS.

Notes: Continuous Testing With Flex and ColdFusion Projects

Presented by Thomas Burleson.

Unit testing: Testing functionality of a single unit of code. Could be a webservice, component, UI component, etc.

Continuous testing: Testing all your units in every cycle. Maybe not every time you save, but every time you're done and you're about to commit to the repository. Done on the local development machine. Then, automated tasks can connect to subversion and deploy code to the shared dev server.

So why continuous testing? Improve your development style. You will give the perception that you are a great developer because people will see your apps with less bugs, even in beta testing stages. Can save time in the long run.

Traditional approach: Create CFCs, then create CFML pages to test and debug the CFC calls. This is the same even if you are using an MVC framework. Ends up being a bit ad-hoc. How do you make sure you test all methods of all CFCs? Also, doesn't promote tests of "boundary conditions". Cannot (or harder) to build a suite of tests. And no regression testing.

Testing frameworks: CFUnit (ColdFusion), cfcUnit (ColdFusion), FlexUnit (Flex), ASUnit (Flash).

Model your test hierarchy after your application hierarchy for a one-to-one reference.

  • MyProject
    • CFML
    • test
      • traditionalTests (Standard CFML page)
      • tdd (Continuous Test-Driven Development tests using frameworks)

If you know you have a bug, write a test that proves you have the bug! Then fix the bug, and the test will prove that the bug was fixed.

Common misconceptions. Don't like writing your test code first? Fine. Don't. Get your hands dirty and then go back and write tests. Don't like the thought of writing tests for all your code. Fine. Don't. Do it incrementally.

Why resistant? Not having the time. Or CFCs are changed but test cases are not updated. Or test cases are updated but forgot to update the test runner to run the new test case.

The Synchronizer can help with these complaints. Universal Mind will make this open source, but not available yet. Watches business components, always synchronizes the test case class and methods. Builds the CRUD "shells". And auto-updated the test runner. So it isn't intelligent enough to write your tests, but it does that dirty work to make it easier to always include the test.

Conclusion. Use a testing framework. Use Eclipse Ant. Use Synchronizer. Use Subversion. Check out Sean Corfield's post(s) on automating testing tasks with Ant.

Notes: Testing ColdFusion Apps

Presented by John Paul Ashenfelter.

What is testing?

  • Verify the software works.
  • Validate the reliability and stability. May work on your dev machine but what about when getting hit by 500 people?
  • Ensure the software solves the problem it is supposed to solve.
  • Make sure the user can use the software (usability).

People remember bad software a lot longer than they remember late software. So don't skip the testing stage. Better to test it and get it right. May take a number of versions to undo perception of bad software that was just released too soon.

Good testers are developers, QA staff, help desk, internal staff. Bad testers are users, customers, the public.

When test? All the time. When you write code, change code, fix a bug, integrate code, deploy code, think of a new edge case. Click "Run" on your test suite when you're taking a break.

How should I test? (1) Code tests (Unit testing). (2) Application tests (functional testing). (3) System (load/performance testing). This can be a nasty black art. (4) If possible, also do user acceptance testing.

Functional Testing

Tests verify the application is working from the users' piont of view. A "Test Case" is then a single step with a single outcome. You need at least one test per requirement/use case. You will have preconditions and postconditions, known inputs and expected outputs.

Selenium. Can help with functional testing. Especially when used with Firefox, there is a plugin that provides a nice GUI for setting up tests. Really easy. But even if you don't use Firefox, you just need to type some simple HTML to generate the tests. Selenium will then run through the tests through its HTML/JavaScript interface.

Really neat trick: Your Selenium test case file can be a ColdFusion file, and you can embed bits of ColdFusion to do various things. For instance, John used the ColdFusion Rand() function when generating the text to enter into some of the app's form fields, to make the fields unique (for instance, in a field that requires a unique value, perhaps an email field). Could also embed ColdFusion to do queries or CFC calls that would autodelete any database records before running your tests.

Unit Testing

A developer writes a unit test to verify an extremely specific area (unit) of functionality (code) behaves as they expect. One unit test isn't good enough. Have tests with good data, bad data, edge cases (zero, etc). Takes a little time, but can be addicting and extremely useful during development and maintenance phase of an application. Also tests for: Negative numbers, duplicates, normal sets of values (the "good" data), empty arrays, single values.

Test cases will eventually become test suites. A bunch of individual but related test suites. You can then automate the tests with Ant. Even can do commit hooks in your source control (i.e. Subversion). Then there are commercial "continuous integration" tools like CruiseControl. This will improve the quality of your code, because everything is constantly being tested.

Spend your time setting up good automated repository and testing tools rather than running your tests manually over and over again. Subversion commit hooks set up to send emails, including emails with diffs. Can also do automated testing on commit.

Load Testing

"Premature optimization is the root of all evil in programming." -- C.A.R. Hoare

Don't spend too much time on writing efficient right off the bat. Write for code readability and maintainability. If you really do have a problem in some areas once load testing, start the optimizations. But don't bother load testing until after you have done functional and unit tests.

Flavors of load testing: Load test expected usage patterns; performance testing known workloads; stress testing to the breaking point. Load testing is WYTIWYM (what you test is what you measure).  But recognize that results rarely (i.e. never) scale as expected to different hardware configurations. So you're really not sure what the results will be until it goes on the live server.

User Acceptance Testing

Very useful and provides insight on things. If users cannot figure out your app, the problem is somewhere on your end. We need to make the app simple and intuitive enough for them to use it with little or no guidance.

Final Thoughts

Testing is part of our job. Needs to be integrated into the entire development process, otherwise we won't keep up on it and it won't be meaningful.

  Theme Brought to you by Directory Journal and Elegant Directory.