Portcullis 2.0 released

Jan 04, 2010

Finally took some time to fix a few items in Portcullis that were bugging me. If you haven't heard of Portcullis or aren't currently using it, it is a ColdFusion component designed to help block and log SQL injection and Cross-site scripting (XSS) attacks. It's pretty widely used and will be included in the 3.2 release of the popular ColdFusion MVC framework - Model-Glue.

You can download it at http://portcullis.riaforge.org

The new Portcullis filter has a number of new features.

Context Aware SQL Command Word Filtering, this is a long term to describe a fairly simple problem. Many of the common sql commands words are used in everyday speech like 'select' and 'alter'. In the old version of Portcullis, you could get some annoying false-positives like 'firstname=walter' being changed to 'firstname=w[INVALID]'. The new filter is now looking for the context or use of the command word. So 'drop me from this list' will not get filtered but 'drop table users' will.

Accessors, you can now dynamically configure Portcullis through either the init() or setSettings() methods. This can allow people to dynamically alter Portcullis settings as they need it as if it were running in various 'modes'. The default settings are still within the CFC, but they can now be override them as needed.

For example, in creating an instance of Portcullis you can now do something like the following..

<cfset settings = StructNew()/>
<cfset settings.log = true/>
<cfset settings.ipBlock = false/>
<cfset settings.sqlFilter = "select,insert,update,delete,drop,alter,declare,execute"/>
<cfset request.Portcullis = createObject("component","Portcullis").init(settings)/>


And as always, the default keyword lists have been updated with some new items to search for.

If you're not using Portcullis yet, I can only say it has saved a lot of developers their time and possibly their jobs. I know some people use AntiSamy which is a simple Java based filter, but frankly it doesn't do very much in my opinion. The cool thing about Portcullis is it's written entirely in CFML so its easy to install, manage and maintain. It will also work across all the known CFML engines.

Warning - jumping on my Soapbox :)
Most ColdFusion web developers are now finally using cfqueryparam, it has taken about 10 years since that tag was introduced but I guess better late than never. Keep in mind, that cfqueryparam prevents most forms of SQL injection but not all. It also does nothing to cross-site scripting (XSS) attacks. It doesn't matter how small your site is or where it's hosted, it will experience these attack vectors. Portcullis takes maybe 5 minutes to install and configure. Nothing is perfect, but Portcullis has a solid track record - just google it. So, there's simply no reason I can think of where a ColdFusion based site shouldn't use it.

Comments

Dan Wilson

Dan Wilson wrote on 01/07/108:34 PM

John,

These are really great enhancements.

The new configuration option will help us integrate this with Model-Glue and ColdSpring.

The false-positive reduction changes really help us move ahead implementing this.

Thanks for the hard work on Portcullis, truly, these days all public facing applications must have some XSS and SQL Injection protection.
Paul Stewar

Paul Stewar wrote on 01/13/102:30 PM

Great tool! thanks a lot.
Tony Nelson

Tony Nelson wrote on 01/14/105:50 PM

I'm sure Little Bobby Tables is happy to hear about the context aware filtering.

http://xkcd.com/327/
Gabriel

Gabriel wrote on 01/14/106:26 PM

Hi John,

I didn't see a way to do this so maybe this is an enhancement request for the future.

Whether as an extra parameter in the "scan" function or as a setting, it'd be nice to be able to disable the automatic replacement of invalidMarker ([INVALID]) in the different scopes.

In other words, a way to have portcullis determine that a hit has occured but _not_ to automatically replace the hit with "[invalid]".

Use case is wanting to know that a hit has occured without affecting the input.

Thank you,
Gabriel
James Moberg

James Moberg wrote on 01/15/102:41 PM

(I'm unable to post a comment on the RiaForge project page.)

I'm getting errors (using CF8). Please test for "valid" ColdFusion variable names. The following links throw errors when the URL scope is scanned in Portcullis.
http://www.domain.com/?=1
http://www.domain.com/?1a=1

On lines 110-122, add additional logic to identify valid variable names using regex [A-Za-z][A-Za-z0-9_]* on the variable name prior to executing line 119.

If I dump the URL Class, the invalid variable name is listed and can be accessed as a struct by using URL["1A"] or URL.1A (strange... new struct feature?). But it can't be set using
<cfset "url.#itemname#" = "1a"/>.

Another solution would be to change line 119 to <CFSET StructUpdate(Object, item, temp.cleanText)>

Regarding the URL variable names, what do you think the best course of action is? Some other languages may generate illegal CF variable names (or even truncated URLs). Treating them as a "struct" seems to work properly. This variable naming behavior seems to be contradictory to the CF8 documentation:
http://livedocs.adobe.com/coldfusion/8/Variables_03.html
James Moberg

James Moberg wrote on 01/15/102:55 PM

BTW: We only discovered the error ("The string url. is not a valid ColdFusion variable name.") because of the ScanAlert.com service that we subscribed to. It performed a nightly test and generated two errors in our logfile.
John Mason

John Mason wrote on 01/15/106:00 PM

@Gabriel - I'll add a isDetected method which you can use to determine if Portcullis caught something. That'll be out on version 2.0.1

As far as not changing the submitted data, you can already do that by dumping the changes Portcullis is doing into another scope. For example..

<cfset application.Portcullis.scan(url,"changed",cgi.remote_addr)>

Is this example, I simply dump the changes into a 'changed' scope.
John Mason

John Mason wrote on 01/15/106:04 PM

@James - I'll see what I can do. Unfortunately using the structupdate or structinsert functions yields the infamous 'dereference a scalar variable' error. Hence the reason, it's setup that way inside of Portcullis.

I'll see if I can fix it so it doesn't throw an error on those scans. Yep other services or languages may throw strange url variables to CF, but CF is a bit more strict on it's variable naming in this situation.

The fixes for this will be in version 2.0.1
Gabriel

Gabriel wrote on 01/15/106:26 PM

Ah, nice tip. Works perfectly.

Thank you,
Gabriel
James Moberg

James Moberg wrote on 01/15/106:51 PM

::: CF is a bit more strict on it's variable naming in this situation.

I was actually surprised that it wasn't strict. If you pass illegal variable names in the URL and then use <CFDUMP VAR="#URL#">, you'll see the illegally-named URL-scoped variables without any error (tested in CF5 too.) You'll only get an error if you try to access it using dot notation (URL.X).

I passed "/index.cfm?1-1=hello" and use CFDUMP and URL["1-1"] without getting any illegal variable name errors. Passing "?<=1" and "?*=1" work too and can be retrieved as URL["<"] and URL["*"]. If these scopes are treated as structs, it would seem that "any" value is accepted by CF as a variable name and may need to be additionally scanned/filtered (which is what your script does already with the exception of checking to see if the name starts with a letter).

Also, don't these structs already exist even if you don't pass any FORM or URL variables? I don't think you'll get any "dereference a scalar variable" error, especially since you are looping over an existing object. You may need to use StructInsert() with the "overwrite" option enabled. (I just updated this in the script I'm using to allow new sanitized fields to be created.)
<CFSET StructInsert(URL, "*", "hello", true)>

Thanks for creating and maintaining this!
John Mason

John Mason wrote on 01/16/1012:33 AM

@James - Basically the StructInsert and StructUpdate functions require a true struct in the first parameter and not just the name of the struct. Since Portcullis allows you to write the clean text into a custom scope these two things can't mesh well. It's actually fine, the pattern used has been valid in CF since the beginning.

@everyone,
Portcullis 2.0.1 is available. It has a new isDetected() function for Gabriel and the variable naming checking is stronger now so you shouldn't see those scanning errors James. Thanks for the feedback guys.
Steve S

Steve S wrote on 03/14/1112:09 PM

Thank you for your continued work on this John!

Unfortunately, we've noticed that this and similar script protections break CFGRID because of the underlying calls that it makes. Is there a workaround or a setting in Portcullis that would allow us to use both?
John Mason

John Mason wrote on 03/17/119:14 PM

@Steve - cfgrid is working for me under Portcullis. Is there some additional information you can send to me on this?
Steve S

Steve S wrote on 03/18/118:49 AM

@John, it replaces some of the underlying GET code.

i.e.

error:http: Error invoking CFC /returns/getRecords.cfc : JSON parsing failure: Expected '"' at character 2:'&' in {"page":1,"pageSize":15,"gridsortcolumn":"","gridsortdirection":"","dropd":"","filter":"","csr":"","rto":"","status":"","date":"","date1":""}

info:http: HTTP GET /returns/getRecords.cfc?method=getRecords&returnFormat=json&argumentCollection=%7B%22page%22%3A1%2C%22pageSize%22%3A15%2C%22gridsortcolumn%22%3A%22%22%2C%22gridsortdirection%22%3A%22%22%2C%22dropd%22%3A%22%22%2C%22filter%22%3A%22%22%2C%22csr%22%3A%22%22%2C%22rto%22%3A%22%22%2C%22status%22%3A%22%22%2C%22date%22%3A%22%22%2C%22date1%22%3A%22%22%7D
Online dentist

Online dentist wrote on 03/18/1111:59 AM

great..........

Thanks
Craig B

Craig B wrote on 03/25/113:49 PM

Note on cfgrid issue:
I am currently experiencing an issue with cfgrid / portcullis - this is what I am seeing:
in the background, cfgrid is passing a hidden field (containing an empty string) the fieldname is to the effect of: __CFGRID__someGRIDFORM__someGRID
{some being some formname}... if it's not obvious, my cfgrid resides inside a cfform... so the hidden field may look different to you. Easy way to see it is to simply dump the form with and without portcullis and compare, I would bet there is a __CFGRID__something being filtered out, which in my case is resulting in a null pointer being thrown at coldfusion.filter.GridFieldProcessor.decode(GridFieldProcessor.java:40)

I have not resolved this as I have just began looking into it today, and for the sake of time am just replacing cfgrid with html as work-around, but would like to hear/read what you might know about this as it would be nice to utilize cfgrid inside cfform in certain portions of my project.
Craig B

Craig B wrote on 03/31/1111:00 AM

CF/HTML/JQuery replacement of cfgrid resolved the null pointer being thrown (as specified above), so cfgrid/portcullis was the issue in my case.

Write your comment



(it will not be displayed)