/** * Removes potentially nasty HTML text. * Version 2 by Lena Aleksandrova - changes include fixing a bug w/ arguments and use of REreplace where REreplaceNoCase should have been used. * version 4 fix by Javier Julio - when a bad event is removed, remove the arg too, ie, remove onclick="foo", not just onclick. * * @param text String to be modified. (Required) * @param strip Boolean value (defaults to false) that determines if HTML should be stripped or just escaped out. (Optional) * @param badTags A list of bad tags. Has a long default list. Consult source. (Optional) * @param badEvents A list of bad HTML events. Has a long default list. Consult source. (Optional) * @return Returns a string. * @author Nathan Dintenfass (nathan@changemedia.com) * @version 4, October 16, 2006 */ function safetext(text) { //default mode is "strip" var mode = "strip"; //the things to strip out (badTags are HTML tags to strip and badEvents are intra-tag stuff to kill) //you can change this list to suit your needs var badTags = "STYLE,SCRIPT,OBJECT,APPLET,EMBED,FORM,LAYER,ILAYER,FRAME,IFRAME,FRAMESET,PARAM,META"; var badEvents = ".toString,:expr,:expression,.fromCharCode,String.,.cookie,vbscript:,onLoad,onClick,onDblClick,onKeyDown,onKeyPress,onKeyUp,onMouseDown,onMouseOut,onMouseUp,onMouseOver,onBlur,onChange,onFocus,onSelect,javascript:"; var stripperRE = ""; //set up variable to parse and while we're at it trim white space var theText = trim(text); //find the first open bracket to start parsing var obracket = find("<",theText); //var for badTag var badTag = ""; //var for the next start in the parse loop var nextStart = ""; //if there is more than one argument and the second argument is boolean TRUE, we are stripping if(arraylen(arguments) GT 1 AND isBoolean(arguments[2]) AND arguments[2]) mode = "strip"; if(arraylen(arguments) GT 2 and len(arguments[3])) badTags = arguments[3]; if(arraylen(arguments) GT 3 and len(arguments[4])) badEvents = arguments[4]; //the regular expression used to stip tags stripperRE = "]*>"; //Deal with "smart quotes" and other "special" chars from MS Word theText = replaceList(theText,chr(8216) & "," & chr(8217) & "," & chr(8220) & "," & chr(8221) & "," & chr(8212) & "," & chr(8213) & "," & chr(8230),"',',"","",--,--,..."); //if escaping, run through the code bracket by bracket and escape the bad tags. if(mode is "escape"){ //go until no more open brackets to find while(obracket){ //find the next instance of one of the bad tags badTag = REFindNoCase(stripperRE,theText,obracket,1); //if a bad tag is found, escape it if(badTag.pos[1]){ theText = replace(theText,mid(TheText,badtag.pos[1],badtag.len[1]),HTMLEditFormat(mid(TheText,badtag.pos[1],badtag.len[1])),"ALL"); nextStart = badTag.pos[1] + badTag.len[1]; } //if no bad tag is found, move on else{ nextStart = obracket + 1; } //find the next open bracket obracket = find("<",theText,nextStart); } } //if not escaping, assume stripping else{ theText = REReplaceNoCase(theText,stripperRE,"invalid","ALL"); } //now kill the bad "events" (intra tag text) theText = REReplaceNoCase(theText,'(#ListChangeDelims(badEvents,"|")#)[^ >]*',"invalid","ALL"); //return theText return theText; } /** * Tests a string, one-dimensional array, or simple struct for possible SQL injection. * * @param input String to check. (Required) * @return Returns a boolean. * @author Will Vautrain (vautrain@yahoo.com) * @version 1, July 1, 2002 */ function IsSQLInject(input) { /* * The SQL-injection strings were used at the suggestion of Chris Anley [chris@ngssoftware.com] * in his paper "Advanced SQL Injection In SQL Server Applications" available for downloat at * http://www.ngssoftware.com/ */ var listSQLInject = "char,declare,cast,exec,execute,sp_sqlExecute,select,insert,update,delete,drop,--,alter,xp_"; var arraySQLInject = ListToArray(listSQLInject); var i = 1; for(i=1; i lte arrayLen(arraySQLInject); i=i+1) { if(findNoCase(arraySQLInject[i], input)) return true; } return false; } function safeSQLtext(str) { var i = 1; var newval = "INVALID"; var list1 = "CHAR,DECLARE,CAST,EXEC,EXECUTE,SP_SQLEXECUTE,SELECT,INSERT,UPDATE,DELETE,DROP,--,ALTER,XP_"; var list2 = ",,,,,,,,,,,,"; for(; i lte listLen(list1); i=i+1) { if(i gt listLen(list2)) newval = "INVALID"; else newval = listGetAt(list2,i); str = ReplaceNoCase(str,listGetAt(list1,i),newval,"all"); } return str; } /** * Strip xml-like tags from a string when they are within or not within a list of tags. * * @param stripmode A string, disallow or allow. Specifies if the list of tags in the mytags attribute is a list of tags to allow or disallow. (Required) * @param mytags List of tags to either allow or disallow. (Required) * @param mystring The string to check. (Required) * @param findonly Boolean value. If true, returns the first match. If false, all instances are replaced. (Optional) * @return Returns either a string or the first instance of a match. * @author Isaac Dealey (info@turnkey.to) * @version 2, September 22, 2004 */ function stripTags(stripmode,mytags,mystring) { var spanquotes = "([^"">]*""[^""]*"")*"; var spanstart = "[[:space:]]*/?[[:space:]]*"; var endstring = "[^>$]*?(>|$)"; var x = 1; var currenttag = structNew(); var subex = ""; var findonly = false; var cfversion = iif(structKeyExists(GetFunctionList(),"getPageContext"), 6, 5); var backref = "\\1"; // this backreference works in cf 5 but not cf mx var rexlimit = len(mystring); if (arraylen(arguments) gt 3) { findonly = arguments[4]; } if (cfversion gt 5) { backref = "\#backref#"; } // fix backreference for mx and later cf versions else { rexlimit = 19000; } // limit regular expression searches to 19000 characters to support CF 5 regex character limit if (len(trim(mystring))) { // initialize defaults for examining this string currenttag.pos = ListToArray("0"); currenttag.len = ListToArray("0"); mytags = ArrayToList(ListToArray(mytags)); // remove any empty items in the list if (len(trim(mytags))) { // turn the comma delimited list of tags with * as a wildcard into a regular expression mytags = REReplace(mytags,"[[:space:]]","","ALL"); mytags = REReplace(mytags,"([[:punct:]])",backref,"ALL"); mytags = Replace(mytags,"\*","[^$>[:space:]]*","ALL"); mytags = Replace(mytags,"\,","[$>[:space:]]|","ALL"); mytags = "#mytags#[$>[:space:]]"; } else { mytags = "$"; } // set the tag list to end of string to evaluate the "allow nothing" condition // loop over the string for (x = 1; x gt 0 and x lt len(mystring); x = x + currenttag.pos[1] + currenttag.len[1] -1) { // find the next tag within rexlimit characters of the starting point currenttag = REFind("<#spanquotes##endstring#",mid(mystring,x,rexlimit),1,true); if (currenttag.pos[1]) { // if a tag was found, compare it to the regular expression subex = mid(mystring,x + currenttag.pos[1] -1,currenttag.len[1]); if (stripmode is "allow" XOR REFindNoCase("^<#spanstart#(#mytags#)",subex,1,false) eq 1) { if (findonly) { return subex; } // return invalid tag as an error message else { // remove the invalid tag from the string myString = RemoveChars(myString,x + currenttag.pos[1] -1,currenttag.len[1]); currenttag.len[1] = 0; // set the length of the tag string found to zero because it was removed } } } // no tag was found within rexlimit characters // move to the next block of rexlimit characters -- CF 5 regex limitation else { currenttag.pos[1] = rexlimit; } } } if (findonly) { return ""; } // return an empty string indicating no invalid tags found else { return mystring; } // return the new string discluding any invalid tags }