DEV Community

Cover image for areBracesValid UDF for ColdFusion/CFML
James Moberg
James Moberg

Posted on

areBracesValid UDF for ColdFusion/CFML

Useful to determine if braces are correctly matched before processing. Helps reduce SQLi.

I was using a version of smartSearch from CFLib.org that I had updated with some simple regex detection for SQLi strings, but it wasn't catching everything. I considered disabling the bracket matching feature and rejecting any query search terms that attempted to use ( or ), but then considered that I should validate so that the feature could still be used since it is beneficial when not being exploited.

I couldn't find any UDFs on CFLib or other ColdFusion/CFML snippets to validate brackets in a string. (If there's existing code, let me know. I wasn't able to find it.) I read a couple recommendations on StackOverflow indicating that it shouldn't be validated using regex, so I wrote a UDF that reduces & validates braces in a string and returns a Boolean response. This allows us to determine whether we can safely use the string when generating a SQL search string (or use 1=0 as a fallback).

Source Code

https://gist.github.com/JamoCA/a35ffaabc00e0339a9996e27825159a7

<!--- areBracesValid ColdFusion/CFML UDF (2022-09-16)
Useful to determine if braces are correctly matched before processing. Helps reduce SQLi.
By James Moberg - SunStar Media https://www.sunstarmedia.com/
Gist: https://gist.github.com/JamoCA/a35ffaabc00e0339a9996e27825159a7
Blog: https://dev.to/gamesover/arebracesvalid-udf-for-coldfusioncfml-21fg
Tweet: https://twitter.com/gamesover/status/1570911352138641408
20220918 Updated to use single refind/replaceAll expressions
20221108 Updated to use "while" instead of cfloop/condition (which isn't supported by Lucee in cfscript.)
--->
<cfscript>
boolean function areBracesValid(required string string) hint="Validates if braces are correctly matched" {
local.string = javacast("string", arguments.string).replaceAll("[^\[\]\{\}\(\)]", "");
if (!len(local.string)) return true; // no braces
if (len(local.string) mod 2) return false; // odd number of braces
local.bracketFound = 1;
while (local.bracketFound) {
local.bracketFound = refind("(\(\))|(\[\])|(\{\})", local.string);
if (local.bracketFound){
local.string = local.string.replaceAll("(\(\))|(\[\])|(\{\})", "");
}
}
return (len(local.string)) ? false : true;
}
</cfscript>
<cfset tests = [
"1') AND 5410=3868 AND ('tVgF'='tVgF"
,"1') AND 3265=DBMS_PIPE.RECEIVE_MESSAGE(CHR(90)||CHR(76)||CHR(98)||CHR(98),5) AND ('wIxt'='wIxt"
,"(1=0) and (R.ID = 2)"
,"(([R].[Name] LIKE '%a%') OR ([R].[First] LIKE '%a%') OR ([R].[Last] LIKE '%a%') OR ([R].[Company] LIKE '%a%')) AND (([R].[Name] LIKE '%b%') OR ([R].[First] LIKE '%b%') OR ([R].[Last] LIKE '%b%') OR ([R].[Company] LIKE '%b%')) AND (([R].[Name] LIKE '%c%') OR ([R].[First] LIKE '%c%') OR ([R].[Last] LIKE '%c%') OR ([R].[Company] LIKE '%c%')) AND (([R].[Name] LIKE '%d%') OR ([R].[First] LIKE '%d%') OR ([R].[Last] LIKE '%d%') OR ([R].[Company] LIKE '%d%'))"
]>
<cfoutput>
<cfloop array="#tests#" index="test">
<fieldset>
<legend>#encodeforhtml(test)#</legend>
VALID = #areBracesValid(test)#
</fieldset>
</cfloop>
</cfoutput>

Postmark Image

Speedy emails, satisfied customers

Are delayed transactional emails costing you user satisfaction? Postmark delivers your emails almost instantly, keeping your customers happy and connected.

Sign up

Top comments (3)

Collapse
 
bennadel profile image
Ben Nadel

I was about to ask if you were using cfqueryparam for your search; but, I just looked at the Smart Search UDF, and it looks like it uses some SQL generation, which somewhat rules-out the parameterization.

Collapse
 
gamesover profile image
James Moberg

I use an internally updated version of SmartSearch. I've added logic to identify SQLi and return 1=0 if any is detected. (I'm planning on sharing my UDF updates, but will be releasing it on a new CFML resource website that I'm building.)

Collapse
 
bennadel profile image
Ben Nadel

Sounds exciting! Looking forward to seeing what you've got in store.

A Workflow Copilot. Tailored to You.

Pieces.app image

Our desktop app, with its intelligent copilot, streamlines coding by generating snippets, extracting code from screenshots, and accelerating problem-solving.

Read the docs

👋 Kindness is contagious

Dive into an ocean of knowledge with this thought-provoking post, revered deeply within the supportive DEV Community. Developers of all levels are welcome to join and enhance our collective intelligence.

Saying a simple "thank you" can brighten someone's day. Share your gratitude in the comments below!

On DEV, sharing ideas eases our path and fortifies our community connections. Found this helpful? Sending a quick thanks to the author can be profoundly valued.

Okay