Using regular expressions, or regex, was once a convenient and powerful way for web application firewalls (WAFs) to find malicious code in web requests.Sadly, it doesn't work that well anymore. Regular expressions need far too much tuning, require overly complex matching rules and fail to understand context, resulting in a high rate of false positives and an unacceptable rate of letting actual malicious code get through.Regex still has a place, yet its limitations compel modern WAFs to rely on other methods to filter out malicious content. One of the most reliable is context-aware parsing, which can analyze the environment around a text string to gauge its possible maliciousness. The same string of characters that's part of a news story in one context can be part of an attack in another.Context-aware parsing also makes it harder for attackers to escape detection by nesting commands from different languages and protocols inside one another, a classic way to fool regex detection."Regex is useful for the copy-and-paste stuff beloved by novice attackers — when the attacker doesn't understand how the attack works because someone else built it for them," said Kelly Shortridge, VP of Security Products at Fastly, in a company blog post. "The people who craft the reusable bits of the attack know they could morph any of it to circumvent the simplistic pattern matching mechanism regex offers."Fastly's SmartParse, part of the company's own web application firewall, uses several different parsing engines to determine the context of a text string, such as whether the text is used as part of a command or just as part of human speech."You have OS commands that overlap with the English language," explains Xavier Stevens, Staff Security Researcher at Fastly, "The command 'ID' and the word, just 'ID,' that might come up in technical text, they're the same.""You have to start to look for patterns beyond that to determine what was the intent of this word," he adds, "maybe looking at the symbols that came prior to that, or maybe came after that, to try to make some sort of assertion as to whether this might be an attempted attack or not."
The virtues of regex, and why it's now out of date
A regular expression is just a way for a computer to find a piece of text in a document. If you've ever used the find function in a Microsoft Word document, for example to mark all instances of "cat", then you've used a very basic regular expression.But regexes can get complex very fast. Even when searching for "cat", you may need to specify whether you're looking for the word "cat" by itself or all instances of the letter sequence "c-a-t".If you want to exclude words like "concatenate" or "catamaran," then you should add a space, e.g. "cat ". But if you do that, you'll accidentally exclude true instances of "cat" when they're followed by a punctuation mark, such as "cat," "cat?" and, well, "cat."Then you'll need to take your first step into regex madness and specify that "cat" can be followed by a punctuation mark or a space, but NOT a letter or numeral. Your regex may then look likecat[ ,.?/*<>"'!@#$%^&*()_-+={}[]]where the "[" and "]" brackets indicate the beginning and end of the permitted characters.But you're not done, because some of those punctuation marks themselves are used to modify regular expressions. You'll need to introduce "escape" characters such as "\", which specify that the following character is part of the text being searched for rather than part of the regex command.That leaves you with something likecat[ ,\.\?/\\*<>"'!@#\$%\^&*/(/)_\-\+=\{\}\[\]]and I've probably missed a few characters.If it gets this messy just looking for the word "cat," imagine what it looks like when you're using regex to search for potentially malicious strings of text in a web page.In her blog post, Shortridge gives an example, borrowed from a discussion on the developer forum Stack Overflow, of a regular expression designed to find standard email addresses.It looks like this:(?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*|"(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])*")@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|\[(?:(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9]))\.){3}(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9])|[a-z0-9-]*[a-z0-9]:(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21-\x5a\x53-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])+)\])That's a short one, relatively speaking.




