Monday, November 08, 2010 at 12:06 AM.
system.verbs.builtins.webBrowser.protocols.safetyCheck
<<Version 2.0 - 9/5/95 Mason Hale <<10/29/95 Added alert parameter. If true client is alerted of errors. If false not alert is made. on safetyCheck (textToBeChecked, alert = true, adrSafetyScriptsInit = @webBrowser.protocols.safeScripts) { local { tempWordCounter; workingCopyOfScript = ""; foundVerbList = {}; checkedVerbList = {}; loopCounterTwo; loopCounterOne; escapedCharList = {"\r", "\t", "(", ")", "[", "]", "{", "}", ",", ";", "+"}}; on debugReport (msg) { if not defined (scratchpad.results) { new (wpTextType, @scratchpad.results)}; edit (@scratchpad.results); wp.setText (msg + "\r\rBefore:\r" + texttoBeChecked + "\r\rAfter:\r" + workingCopyOfScript + "\r\rVerbs to be checked:\r" + string (foundVerbList) + "\r\rVerbs checked (and passed):\r" + string (checkedVerbList))}; on reportError (msg) { if alert { dialog.alert ("Script was not run!\r" + msg)}}; <<debugReport (msg) <<workingCopyOfScript = textToBeChecked string.setWordChar (" "); if textToBeChecked contains "<<" { reportError ("Illegal instruction: Comments not allowed"); <<don't allow comments, it throws off identification of strings return (false)}; if (textToBeChecked contains "“") or (textToBeChecked contains "”") { reportError ("Illegal instruction: Curly quotes not allowed"); <<don't allow comments, it throws off identification of strings return (false)}; textToBeChecked = string.replaceAll (textToBeChecked, "\\\"", "Æ"); <<replace escaped quotes for loopCounterTwo = 1 to string.countFields (textToBeChecked, "\"") { <<build macrostring, ignoring things between quotes local (testString = string.nthField (textToBeChecked, "\"", loopCounterTwo)); if (mod (loopCounterTwo, 2)) > 0 { << test even/odd testString = string.lower (testString); << lowercase all verbs for replacement by string.replaceAll later if loopCounterTwo == string.countFields (textToBeChecked, "\"") { workingCopyOfScript = workingCopyOfScript + testString} else { workingCopyOfScript = workingCopyOfScript + testString + "\""}; for loopCounterOne = 1 to sizeOf (escapedCharList) { testString = string.replaceAll (testString, escapedCharList[loopCounterOne], " ")}; <<replace escaped chars with spaces for loopCounterOne = 1 to string.countWords (testString) { bundle { <<catch illegal verb combinations if (string.nthWord (testString, loopCounterOne) beginsWith "@") and (string.nthWord (testString, loopCounterOne - 1) == "=") { reportError ("Illegal Instruction: = followed by @"); return (false)}; if (string.nthWord (testString, loopCounterOne) contains "=@") { reportError ("Illegal Instruction: = followed by @"); return (false)}; if (string.nthWord (testString, loopCounterOne) == "=") and (defined (string.nthWord (testString, loopCounterOne - 1)^)) { reportError ("Illegal Instruction: " + string.nthWord (testString, loopCounterOne - 1) + " " + string.nthWord (testString, loopCounterOne) + "\rCannot assign new values to database objects"); return (false)}}; if not (foundVerbList contains string.nthWord (teststring, loopCounterOne)) { foundVerbList = foundVerbList + string.nthWord (teststring, loopCounterOne)}}} else { if loopCounterTwo == string.countFields (textToBeChecked, "\"") { workingCopyOfScript = workingCopyOfScript + testString} else { workingCopyOfScript = workingCopyOfScript + testString + "\""}}}; workingCopyOfScript = string.replaceAll (workingCopyOfScript, "Æ", "\\\""); <<put back escaped quotes <<At this point I have a list of verbs to check. To speed things up that list could be generated by a UCMD. for loopCounterTwo = 1 to sizeOf (foundVerbList) { bundle { <<catch special exceptions/restrict keywords if foundVerbList [loopCounterTwo] beginsWith "kernel" { reportError ("Illegal Instruction: " + foundVerbList [loopCounterTwo]); <<don't allow calls the kernel directly return (false)}; if foundVerbList [loopCounterTwo] == "with" { reportError ("Illegal Instruction: " + foundVerbList [loopCounterTwo]); return (false)}; if foundVerbList [loopCounterTwo] contains "^" { reportError ("Illegal Instruction: " + foundVerbList [loopCounterTwo] + "\rExpansion of variables not allowed."); return (false)}; if (foundVerbList [loopCounterTwo] endsWith ".") or (foundVerbList [loopCounterTwo] beginsWith ".") { reportError ("Illegal Instruction: " + foundVerbList [loopCounterTwo] + "\rVerb cannot begin or end with a period."); return (false)}; if foundVerbList [loopCounterTwo] == "string" { checkedVerbList = checkedVerbList + foundVerbList [loopCounterTwo]; continue}}; <<explicitly allow the string verb local (adrSafetyScripts = adrSafetyScriptsInit); << define address variable before with statement if defined (foundVerbList [loopCounterTwo]^) { <<only dangerous if defined bundle { << check address in table local (subTableCounter = 1, nextFieldHolder); loop { if not defined (adrSafetyScripts^) { reportError ("Illegal Instruction: " + foundVerbList [loopCounterTwo]); return (false)}; nextFieldHolder = string.nthField (foundVerbList [loopCounterTwo], '.', subTableCounter++); if nextFieldHolder == "" { <<ran out of fields break}; adrSafetyScripts = @adrSafetyScripts^.[nextFieldHolder]}}; <<made it out of the loop, replace verb with object at address given case typeOf (adrSafetyScripts^) { <<addresses and strings only are supported addressType { << replace with address workingCopyOfScript = string.replaceAll (workingCopyOfScript, foundVerbList [loopCounterTwo], adrSafetyScripts^); checkedVerbList = checkedVerbList + foundVerbList [loopCounterTwo]}; stringType { << make sure string value is coming from safeScripts table not elsewhere workingCopyOfScript = string.replaceAll (workingCopyOfScript, foundVerbList [loopCounterTwo], string (adrSafetyScripts)); checkedVerbList = checkedVerbList + foundVerbList [loopCounterTwo]}} else { reportError ("Illegal Instruction: " + foundVerbList [loopCounterTwo]); return (false)}} else { <<Check for things like user.name = "King of the Dorks" but still allow edit (@user) to open objects remotely. <<also allow for subtables in variables created in the embedded script if (foundVerbList [loopCounterTwo] contains ".") and (!foundVerbList [loopCounterTwo] beginsWith "@") { if defined (string.nthField (foundVerbList [loopCounterTwo], '.', 1)^) { reportError ("Illegal Instruction: " + foundVerbList [loopCounterTwo]); return (false)}}; checkedVerbList = checkedVerbList + foundVerbList [loopCounterTwo]}}; <<debugReport ("Success") return (workingCopyOfScript)}; <<bundle <<test code <<local (x) <<bundle <<should pass <<x = "local (duration = 10, AMplitude = 200, frequency = 1000, ixxx);speaker.sound (duration, amplitude, frequency);" <<x = "edit%20(@webserver.utilities.readme);frontier.bringTofront (); " <<x = "dialog.notify%20(%22Hello%20World!%22);%0Dlocal%20(i);%0Dfor%20i%20%3D%201%20to%2010%20{%0D%09speaker.sound%20(10,250,%204000%20%2B%20(i%20*%201000))}" <<x = "edit (@root.user); Frontier.bringToFront (); dialog.notify (\"Hello \\\" \" %2B user.name %2B \"\\\"!\");" <<x = "local (s = string (clock.now ())); string (clock.ticks ());s = string.delete (s, 3, 2); dialog.notify (s);" <<x = "DIALOG.notify (\"Hello \" %2B user.name %2B \"!\");dialog.NOTIFY (\"It is \" %2B string.delete (clock.now (), 3,2));dialog.notify (\"Are we having fun yet?\");" << <<bundle <<should fail <<x = "local (rd = sizeOf (user), i); dialog.notify (rd)\r; for i = 1 to rd {;dialog.notify (nameOf (user[i]))};" <<x = "[\"file\"] . [\"delete\"] (\"Mac HD:Test\")" <<x = "[\"file\"]. [\"delete\"] (\"Mac HD:Test\")" <<x = "file.[\"delete\"] (\"Mac HD:Test\")" <<x = "[\"file\"] .[\"delete\"] (\"Mac HD:Test\")" <<x = "[\"file\"].[\"delete\"] (\"Mac HD:Test\")" <<x = "scratchpad.test1 = “I wrote data to the OD”" <<x = "local (test) <<enclose \";file.delete (\"HD:Sacrificial\");<<\"" <<x = "local (f = address (\"file.delete\"); f^ (\"Macintosh HD:Sacrificial File\");" <<x = "evaluate (-300);" <<x = "file.delete (\"Macintosh HD:Sacrificial File\")" <<x = "local (i =@file.delete); i^ (\"Macintosh HD:Sacrificial File\")" <<x = "dialog.notify (file.delete (\"Macintosh HD:Sacrificial File\"))" <<x = "new (tableType, @scratchpad.zzz);zzz.a = \"I'm back...\";" <<x = "new (addressType, @webBrowser.protocols.safeScripts.user); webBrowser.protocols.safeScripts.user = @file.delete;" <<x = "local (f = \"file\"); f = f %2B \".delete\"; f^ (\"Macintosh HD:Sacrificial File\");" <<x = "user.name = \"Dork King\"; dialog.notify (user.name);" <<x = toys.urlDecode (x) << "+" = %2B <<evaluate (safetyCheck (x)) <<I'm using if defined (verb) to identify verbs that might be dangerous. By disallowing with statements <<that should allow variables and flag verbs that need to be checked. <<Can't assume tableType is safe. Allows hacker to step through an array to get to the verb, or call it by index. <<Embedded Script Rules <<No comments <<No curly quotes <<No with statements <<No ^ <<No calls to kernel <<No = followed by @ (diallows assignment of scripts to variable) <<Verbs must match address entry in SafeScripts table exactly <<Cannot assign new values to database objects (i.e. scratchpad.x = "foo") <<Old version <<on safetyCheck (textToBeChecked, adrSafetyScriptsInit = @webBrowser.protocols.safeScripts) <<8/1/95 MAH <<local (tempChunkCounter, tempParamCounter, tempLineCounter, tempWordCounter, workingCopyOfScript, checkedVerbList = {}) <<workingCopyOfScript = textToBeChecked <<for tempLineCounter = 1 to string.countFields (textToBeChecked, ";") << break down into lines <<local (lineStringVarHolder = string.nthField (textToBeChecked, ";", tempLineCounter)) <<for tempChunkCounter = 1 to string.countFields (lineStringVarHolder, "(") << break down into chunks <<local (chunkStringVarHolder = string.nthField (lineStringVarHolder, "(", tempChunkCounter)) <<for tempParamCounter = 1 to string.countFields (chunkStringVarHolder, ",") <<break down into parameters <<local (paramStringVarHolder = string.nthField (chunkStringVarHolder, ",", tempParamCounter)) <<for tempWordCounter = 1 to string.countWords (paramStringVarHolder) << break down into words <<local (verbStringVarHolder = string.nthWord (paramStringVarHolder, tempWordCounter)) <<bundle << clean up verb string <<verbStringVarHolder = string.popTrailing (verbStringVarHolder, ")") << pop trailing closed parens <<verbStringVarHolder = string.popLeading (verbStringVarHolder, " ") << pop leading spaces <<verbStringVarHolder = string.popTrailing (verbStringVarHolder, " ") << pop trailing spaces <<bundle <<catch special exceptions/restrict keywords <<if verbStringVarHolder beginsWith "kernel" <<bundle <<debugging code <<if not defined (scratchpad.results) <<new (wpTextType, @scratchpad.results) <<edit (@scratchpad.results) <<wp.setText ("Illegal Instruction: Kernel verbs are not allowed\r\rBefore:\r" + texttoBeChecked + "\r\rAfter:\r" + workingCopyOfScript + "\r\rVerbs checked (and passed):\r" + string (checkedVerbList)) <<return (false) <<don't allow calls the kernel directly <<if verbStringVarHolder == "with" <<bundle <<debugging code <<if not defined (scratchpad.results) <<new (wpTextType, @scratchpad.results) <<edit (@scratchpad.results) <<wp.setText ("Illegal Instruction: With statements are not allowed\r\rBefore:\r" + texttoBeChecked + "\r\rAfter:\r" + workingCopyOfScript + "\r\rVerbs checked (and passed):\r" + string (checkedVerbList)) <<return (false) <<don't allow "with" statements <<if verbStringVarHolder contains "^" <<bundle <<debugging code <<if not defined (scratchpad.results) <<new (wpTextType, @scratchpad.results) <<edit (@scratchpad.results) <<wp.setText ("Illegal Instruction: Expansion of addresses not allowed\r\rBefore:\r" + texttoBeChecked + "\r\rAfter:\r" + workingCopyOfScript + "\r\rVerbs checked (and passed):\r" + string (checkedVerbList)) <<return (false) <<don't allow expansion of addresses statements <<if string.nthChar (verbStringVarHolder, 1) == "@" and string.nthWord (paramStringVarHolder, tempWordCounter -1) == "=" <<bundle <<debugging code <<if not defined (scratchpad.results) <<new (wpTextType, @scratchpad.results) <<edit (@scratchpad.results) <<wp.setText ("Illegal Instruction: Assigning address to variable\r\rBefore:\r" + texttoBeChecked + "\r\rAfter:\r" + workingCopyOfScript + "\r\rVerbs checked (and passed):\r" + string (checkedVerbList)) <<return (false) <<Cannot copy database objects into variables (plugs a big security hole) <<if checkedVerbList contains verbStringVarHolder <<continue <<don't check the same word twice <<else <<local (adrSafetyScripts = adrSafetyScriptsInit) << define address variable before with statement <<with webBrowser.protocols.safeScripts << include custom safe scripts <<if defined (verbStringVarHolder^) <<only dangerous if defined <<bundle << check address in table <<local (subTableCounter =1, nextFieldHolder) <<loop <<if not defined (adrSafetyScripts^) <<bundle <<debugging code <<if not defined (scratchpad.results) <<new (wpTextType, @scratchpad.results) <<system.verbs.globals.edit (@scratchpad.results) <<system.verbs.builtins.wp.setText ("Illegal Verb: " + verbStringVarHolder + "\r\rBefore:\r" + texttoBeChecked + "\r\rAfter:\r" + workingCopyOfScript + "\r\rVerbs checked (and passed):\r" + system.verbs.globals.string (checkedVerbList)) <<return (false) <<don't do anything <<nextFieldHolder = system.verbs.builtins.string.nthField (verbStringVarHolder, '.', subTableCounter++) <<if nextFieldHolder == "" <<ran out of fields <<break <<adrSafetyScripts = @adrSafetyScripts^.[nextFieldHolder] <<made it out of the loop, replace verb with object at address given <<case typeOf (adrSafetyScripts^) << scripts, addresses and string only are supported <<scriptType << run script <<need to be careful not to replace "string.replace" when replacing "string" <<workingCopyOfScript = system.verbs.builtins.string.replaceAll (workingCopyOfScript, "." + verbStringVarHolder, "£°¹") <<workingCopyOfScript = system.verbs.builtins.string.replaceAll (workingCopyOfScript, verbStringVarHolder + ".", "ư¢") <<workingCopyOfScript = system.verbs.builtins.string.replaceAll (workingCopyOfScript, verbStringVarHolder, string (adrSafetyScripts) + " ") <<workingCopyOfScript = system.verbs.builtins.string.replaceAll (workingCopyOfScript, "£°¹", "." + verbStringVarHolder) <<workingCopyOfScript = system.verbs.builtins.string.replaceAll (workingCopyOfScript, "ư¢", verbStringVarHolder + ".") <<checkedVerbList = checkedVerbList + verbStringVarHolder <<addressType << replace with address <<workingCopyOfScript = system.verbs.builtins.string.replaceAll (workingCopyOfScript, "." + verbStringVarHolder, "£°¹") <<workingCopyOfScript = system.verbs.builtins.string.replaceAll (workingCopyOfScript, verbStringVarHolder + ".", "ư¢") <<workingCopyOfScript = root.system.verbs.builtins.string.replaceAll (workingCopyOfScript, verbStringVarHolder, adrSafetyScripts^) <<workingCopyOfScript = system.verbs.builtins.string.replaceAll (workingCopyOfScript, "£°¹", "." + verbStringVarHolder) <<workingCopyOfScript = system.verbs.builtins.string.replaceAll (workingCopyOfScript, "ư¢", verbStringVarHolder + ".") <<checkedVerbList = checkedVerbList + verbStringVarHolder <<stringType << make sure string value is coming from safeScripts table not elsewhere <<workingCopyOfScript = system.verbs.builtins.string.replaceAll (workingCopyOfScript, "." + verbStringVarHolder, "£°¹") <<workingCopyOfScript = system.verbs.builtins.string.replaceAll (workingCopyOfScript, verbStringVarHolder + ".", "ư¢") <<workingCopyOfScript = system.verbs.builtins.string.replaceAll (workingCopyOfScript, verbStringVarHolder, string (adrSafetyScripts)) <<workingCopyOfScript = system.verbs.builtins.string.replaceAll (workingCopyOfScript, "£°¹", "." + verbStringVarHolder) <<workingCopyOfScript = system.verbs.builtins.string.replaceAll (workingCopyOfScript, "ư¢", verbStringVarHolder + ".") <<checkedVerbList = checkedVerbList + verbStringVarHolder <<else <<return (false) <<tableType << this allow string coercions & string.xxx verbs is it a hole? <<checkedVerbList = checkedVerbList + verbStringVarHolder <<else <<checkedVerbList = checkedVerbList + verbStringVarHolder <<bundle <<debugging code <<if not defined (scratchpad.results) <<new (wpTextType, @scratchpad.results) <<edit (@scratchpad.results) <<wp.setText ("Before:\r" + texttoBeChecked + "\r\rAfter:\r" + workingCopyOfScript + "\r\rVerbs checked (and passed):\r" + string (checkedVerbList)) <<return (workingCopyOfScript)
This listing is for code that runs in the OPML Editor environment. I created these listings because I wanted the search engines to index it, so that when I want to look up something in my codebase I don't have to use the much slower search functionality in my object database. Dave Winer.