• CSRF and Beyond

    Two Trees

    Identifying CSRF vulns is more interesting than just scraping HTML for hidden fields or forging requests. CSRF stems from a design issue of HTTP and HTML. An HTML form is effectively vulnerable to CSRF by default. That design is a positive feature for sites – it makes many types of interactions and use cases easy to create. But is also leads to unexpected consequences.

    A passive detection method that is simple to automate looks for the presence or absence of CSRF tokens. However, scraping HTML is prone to errors and generates noisy results that don’t scale well for someone dealing with more than one app at a time. This approach just assumes the identity of a token. It doesn’t verify that it is valid or relied upon by the app. And unless the page is examined after JavaScript has updated the DOM, this technique misses dynamically generated tokens, form fields, and forms.

    An active detection method that can be automated is one that replays requests under different user sessions. This approach follows the assumption that CSRF tokens are unique to a user’s session, such as the session cookie or other pseudo-random value. There’s also a secondary assumption that concurrent sessions are possible. It also requires a browser to deal with dynamic JavaScript and DOM manipulation.

    This active approach basically swaps forms between two sessions for the same user. If the submission succeeds, then it’s more likely request forgery is possible. If the submission fails, then it’s more likely a CSRF countermeasure has blocked it. There’s still potential for false negatives if some static state token or other form field wasn’t updated properly. The benefit of this approach is that it’s not necessary to guess the identity of a token and it’s explicitly testing whether a request can be forged.

    Once more countermeasures become based on the Origin header, the replay approach might be as as simple as setting an off-origin value for this header. A server will either reject or accept the request. This would be a nice, reliable detection as well as a simple, strong countermeasure). Modern browsers released after 2016 support an even better countermeasure – SameSite cookies.

    WhiteHat Security described one way to narrow the scope of CSRF reporting from any form whatsoever to resources carry risk for a user. I’ve slightly modified their three criteria to be resources:

    • with a security context or that cross a security boundary, such as password or profile management
    • that deliver an HTML injection (XSS) or HTTP response splitting payload to a vulnerable page on the target site. This answers the question for people who react to those vulns with, “That’s nice, but so what if you can only hack your own browser.” This seems more geared towards increasing the risk of a pre-existing vuln rather than qualifying it as a CSRF. We’ll come back to this one.
    • where sensitive actions are executed, such as anything involving money, updating a contact list, or sending a message

    There’s an interesting aspect in WhiteHat’s “benign” example. To summarize, imagine a site with a so-called non-obvious CSRF, one XSS vuln, one Local File Inclusion (LFI) vuln, and a CSRF-protected file upload form. The attack uses the non-obvious CSRF to exploit the XSS vuln, which in turn triggers the file upload to exploit the LFI. For example, the attacker creates the JavaScript necessary to upload a file and exploit the LFI, places this payload in an image tag on an unrelated domain, and waits for a victim to visit the booby-trapped page so their browser loads <img src=”https://target.site/xss_inject.page?arg=payload”>.

    This attack was highlighted as a scenario where CSRF detection methods would usually produce false negatives because the vulnerable link, https://target.site/xss_inject.page, doesn’t otherwise affect the user’s security context or perform a sensitive action.

    Let’s review the three vulns:

    • Ability to forge a request to a resource, considered “non-obvious” because the resource doesn’t affect a security context or execute a sensitive action.
    • Presence of HTML injection, HTTP Response Splitting, or other clever injection vuln in said resource.
    • Presence of Local File Inclusion.

    Using XSS to upload a file isn’t a necessarily a vuln (the XSS is, but not the file upload). There’s nothing that says JavaScript within the Same Origin Rule (under which the XSS falls once it’s reflected) can’t use XHR to POST data to a file upload form. In this case it also doesn’t matter if the file upload form has CSRF tokens because the code is executing under the Same Origin Rule and therefore has access the tokens.

    I think these two recommendations would be made by all and accepted by the site developers as necessary:

    • Fix the XSS vulnerability using recommend practices (let’s just assume the arg variable is just reflected in xss_inject.page)
    • Fix the Local File Inclusion (by verifying file content, forcing MIME types, not making the file readable)

    But it was CSRF that started us off on this attack scenario. This leads to the question of how the “non-obvious” CSRF should be reported, especially from an automation perspective:

    • Is a non-obvious CSRF vuln actually obvious if the resource has another vuln like XSS? Does the CSRF become non-reportable once the other vuln has been fixed?
    • Should a non-obvious CSRF vuln be obvious if it has a query string or form fields that might be vulnerable?

    If you already believe CSRF should be on every page, then clearly you would have already marked the example vulnerable just by inspection because it didn’t have an explicit countermeasure. But what about those who don’t follow the tenet that CSRF lurks everywhere? For example, maybe the resource doesn’t affect the user’s state or security context.

    Think about pages that use “referrer” arguments. For example:

    https://web.site/redir.page?url=https://from.here

    In addition to possibly being an open redirect, these are prime targets for XSS with payloads like

    https://web.site/redir.page?url=javascript:arbitrary_payload()

    It seems that in these cases the presence of CSRF just serves to increase the XSS risk rather than be a vuln on its own. Otherwise, you risk producing too much noise by calling any resource with a query string vulnerable. In this case CSRF provides a rejoinder to the comment, “That’s a nice reflected XSS, but you can only hack yourself with it. So what.” Without the XSS vuln you probably wouldn’t waste time protecting that particular resource.

    Look at a few of the other WhiteHat examples. They clearly fall into CSRF vulns – changing shipping address, password reset mechanisms.

    What’s interesting is that they seem to require race conditions or to happen during specific workflows to be successful, e.g. execute the CSRF so the shipping address is changed before the transaction is completed. That neither detracts from the impact nor obviates it as a vuln. Instead, it highlights a more subtle aspect of web security: state management.

    Let’s set aside malicious attackers and consider a beneficent CSRF actor. Our scenario begins with an ecommerce site. The victim, a lucky recipient in this case, has selected an item and placed it into a virtual shopping cart.

    1. The victim (lucky recipient!) fills out a shipping destination.

    2. The attacker (benefactor!) uses a CSRF attack to apply a discount coupon.

    3. The recipient supplies a credit card number.

    4. Maybe the web site is really bad and the benefactor knows that the same coupon can be applied twice. A second CSRF applies another discount.

    5. The recipient completes the transaction.

    6. Our unknown benefactor looks for the new victim of this CSRF attack.

    I chose this Robin Hood-esque scenario to take your attention away from the malicious attacker/victim formula of CSRF to focus on the abuse of workflows.

    A CSRF countermeasure would have prevented the discount coupon from being applied to the transaction, but that wouldn’t fully address the underlying issues here. Consider the state management for this transaction.

    One problem is that the coupon can be applied multiple times. During a normal workflow the site’s UI leads the user through a check-out sequence that must be followed. On the other hand, if the site only prevented users from revisiting the coupon step in the UI, then the site’s developers have forgotten how trivial it is to replay GET and POST requests. This is an example of a state management issue where an action that should be performed only once can be executed multiple times.

    A less obvious problem of state management is the order in which the actions were performed. The user submitted a discount coupon in two different steps: right after the shipping destination and right after providing payment info. In the UI, let’s assume the option to apply a discount shows up only after the user provides payment information. A strict adherence to this transaction’s state management should have rejected the first discount coupon since it arrived out of order.

    Sadly, we have to interrupt this thought to address real-world challenges of web apps. I’ve defined a strict workflow as (1) shipping address required, (2) payment info required, (3) discount coupon optional, (4) confirm transaction required. A site’s UI design influences how strict these steps will be enforced. For example, the checkout process might be a single page that updates with XHR calls as the user fills out each section in any order. Conversely, this single page checkout might enable each step as the user completes them in order.

    UI enforcement cannot guarantee that requests be made in order. This is where decisions have to be made regarding how strictly the sequence is to be enforced. It’s relatively easy to have a server-side state object track these steps and only update itself for requests in the correct order. The challenge is keeping the state flexible enough to deal with users who abandon a shopping cart, or decide at the last minute to add another item before completing the transaction, or a multitude of other actions that affect the state. These aren’t insurmountable challenges, but they induce complexity and require careful testing. This trade-off between coarse state management and granular control leads more to a balance of correctness rather than security. You can still have a secure site if steps can be performed in order of 3, 1, 2, 4 rather than the expected 1, 2, 3, 4.

    CSRF is about requests made in the victim’s session context by the victim’s browser on behalf of the attacker (initiated from an unrelated domain) without the victim’s interaction. If a link, iframe, image tag, or JavaScript causes the victim’s browser to make a request that affects that user’s state in another web site, then the CSRF attack succeeded. The conceptual way to fix CSRF is to identify forged requests and reject them. CSRF tokens are intended to identify legitimate requests because they’re a shared secret between the site and the user’s browser. An attacker who doesn’t know the secret can forge a legitimate request.

    These attacks highlight the soft underbelly of web app state management mechanisms.

    Automated scanners should excel at scaleability and consistent accuracy, but woe to those who believe they fully replace manual testing. Scanners find implementation errors like forgetting to use a prepared statements or not encoding output placed in HTML, but they struggle with understanding design flaws. Complex interactions are more easily understood and analyzed by manual testing.

    CSRF stands astride this gap between automation and manual testing. Automation identifies whether an app accepts forged requests, whereas manual testing can delve deeper into underlying state vulns or chains of exploits that CSRF might enable.

    • • •
  • The biggest threat to modern web applications is the API – Advanced Persistent Ignorance. Developers rely on all sorts of APIs to build complex software. This one makes code insecure by default. API is the willful disregard of simple, established security designs.

    First, we must step back into history to establish a departure point for ignorance. As one example, almost seven years ago on July 13, 2004 PHP 5.0.0 was officially released. It included this new feature:

    A new MySQL extension named MySQLi for developers using MySQL 4.1 and later. This new extension includes an object-oriented interface in addition to a traditional interface; as well as support for many of MySQL’s new features, such as prepared statements.

    Of course, any new feature can be expected to have bugs and implementation issues. Even with an assumption that serious bugs would take a year to be worked out, that means PHP has had a secure database query mechanism for the past six years.1

    The first OWASP Top 10 list from 2003 mentioned prepared statements as a countermeasure.2 Along with PHP and MySQL, .NET and Java supported these, as did Perl, Python, and Ruby On Rails. In fact, PHP and MySQL trailed other languages and databases in their support for prepared statements.

    SQL injection itself predates the first OWASP Top 10 list by several years. One of the first description of the general class of injection attacks was the 1999 Phrack article, Perl CGI problems. SQL injection was a specialization of these problems to database queries.

    So now we’ve established the age of injection attacks at over a dozen years old and reliable countermeasures at least six years old. These are geologic timescales for the Internet.

    SQL injection vulns shouldn’t exist in 2011.

    Coding mistakes most often imply implementation errors – bugs due to typos, forgetfulness, or syntax. People are fallible, they make mistakes.

    But modern SQL injection vulns are a symptom of bad design. For six years, prepared statements have offered a way to eradicate a class of vulns. It takes actual effort to make them insecure.

    In practice, prepared statements can’t handle every complex query that app owners might want to create, but it can handle the majority of them. And we still see vulns appear in simple queries that could have started out as prepared statements.

    Maybe one of the two billion PHP hobby projects on Sourceforge could be expected to still have these vulns, but not real web sites. Let’s review the previous few months:

    The list may seem short, but there’s an abundance of sites that have had SQL injection vulns. We just don’t have a crowdsourced equivalent for it like xssed.org tracks cross-site scripting.

    XSS is a little more forgivable, though no less embarrassing. HTML injection flaws continue to plague sites because of implementation bugs. There’s no equivalent of the prepared statement for building HTML or HTML snippets. This is why the vuln remains so pervasive: No one has figured out the secure, reliable, and fast way to build HTML with user-supplied data. This doesn’t imply that attempting to do so is a hopeless cause. On the contrary, JavaScript libraries can reduce these problems significantly.

    For all the articles, lists, and books published on SQL injection one must assume that developers are being persistently ignorant of security concepts to such a degree that five years from now we may hear yet again of a database hack that disclosed unencrypted passwords.

    There may in fact be hope for the future. The rush to scaleability and the pious invocation of “cloud” has created a new beast of NoSQL datastores. These NoSQL datastores typically just have key-value pairs with grammars that aren’t so easily corrupted by a stray apostrophe or semi-colon in the way that traditional SQL can be corrupted. Who knows, maybe security conferences will finally do away with presentations on yet another SQL injection exploit and find someone with a novel, new NoSQL Injection vulnerability.

    Advanced Persistent Ignorance isn’t limited to SQL injection vulns. It has just spectacularly manifested itself in them. There are many unsolved problems in information security, but there are also many mostly-solved problems. Big unsolved problems in web security are password resets (overwhelmingly relying on email) and using static credit card numbers to purchase items.

    SQL injection is a mostly-solved problem. Using prepared statements isn’t 100% secure, but it makes a significant improvement. User authentication and password storage is another area of web security rife with errors. Adopting a solution like OpenID can reduce the burden of security around authentication. As with all things crypto-related, using well-maintained libraries and system calls are far superior to writing your own hash function or encryption scheme.

    On the other hand, what does it mean that a mostly-solved problem remains so prevalent? Maybe it’s because software development is more complex than function calls and appsec needs to take more action than just awareness.

    Not all security has to be hard. Nor does it have to impede the developer experience or speed of development. There are crypto and JavaScript libraries that provide design patterns and reuseable components for web sites.

    Education about current development practices can go far, but it needs to be grounded in constructive patterns to follow rather than just mistakes to avoid. In other words, give developers examples of secure design principles and how to adopt those principles. It’s the subtle difference between “Don’t make this list of mistakes” vs. “Here’s how to securely design software.”


    1. MySQL introduced support for prepared statements in version 4.1, whose first alpha release was April 3, 2003. 

    2. “A6 Command Injection Flaws” from OWASPWebApplicationSecurityTopTen-Version1.pdf 

    • • •
  • Electric Skillet

    Of John Brunner’s novels, I recommend reading Stand on Zanzibar first. It’s a well-known classic. Follow that with The Sheep Look Up. If you’re interested in novelty, Squares of the City has the peculiar attribute of being written to the rules of a chess game (the book’s appendix maps each character’s role to its relevant piece).

    The Shockwave Rider

    Two of Brunner’s books contain computer security concepts and activities. The first one, The Shockwave Rider, was written in 1975 and is largely responsible for generating the concept of a worm. A character, Sandy, explains:

    What you need is a worm with a completely different structure. The type they call a replicating phage.

    The character continues with a short history of replicating phages, including one developed at a facility called Electric Skillet:

    …and its function is to shut the net down and prevent it being exploited by a conquering army. They think the job would be complete in thirty seconds.

    The main character, Nick Halflinger, creates a variant of the self-replicating phage. Instead of devouring its way towards to the destruction of the net, the program grows off data as a virtual parthenogenetic tapeworm. Nick is a smart computer sabotage consultant (among other things). His creation “won’t expand to indefinite size and clog the net for other use. It has built-in limits.” No spoilers, but the tapeworm has a very specific purpose.

    In his 1988 novel, Children of the Thunder, Brunner mentions a logic bomb as he introduces a freelance writer who had been covering a computer security conference. Brunner didn’t coin this term, though. Malicious insiders were creating logic bombs at least since 19851, famously described by a computer scientist in 1984, and known in the late 70s 2 (including a U.S. law covering cybercrime in 1979).

    The history of the term is almost beside the point because the whimsical nature of the fictional version deserves note 3:

    Two months ago a logic bomb had burst in a computer at British Gas, planted, no doubt, by an employee disgruntled about the performance of his or her shares, which resulted in each of its customers in the London area being sent the bill intended for the next person on the list – whereupon all record of the sums due had been erased.

    A paragraph later we’re treated to a sly commentary embedded in the description of the newspaper who hired the journalist:

    The paper…was in effect a news digest, aimed at people with intellectual pretensions but whose attention span was conditioned by the brevity of radio and TV bulletins, and what the [editor] wanted was a string of sensational snippets about his readers’ privacy being infringed, bent programmers blackmailing famous corporations, saboteurs worming their way into GCHQ and the Ministry of Defense…”

    The fictional newspaper is called the Comet, but it sounds like an ancestor to El Reg (with the addition of pervasive typos and suggestive puns). It’s amusing to see commentary on the attenuation of attention spans due to radio and TV in 1988. It provides a multi-decade precursor to contemporary screeds against Twitter, texting, and Facebook.

    Should you have any remaining attention left to continue reading, I encourage you to try one or more of these books.


    1. “Man Guilty in ‘Logic Bomb’ Case.” Los Angeles Times 4 July 1985, Southland ed., Metro; 2; Metro Desk sec.: 3. “[Dennis Lee Williams], who could face up to three years in prison when sentenced by Los Angeles Superior Court Judge Kathleen Parker on July 31, was convicted of setting up the program designed to shut down important data files.” 

    2.  Communications of the ACM: Volume 22. 1979. “…logic bomb (programmed functions triggered to execute upon occurrence of future events)…” 

    3.  Brunner, John. Children of the Thunder. New York: Ballantine, 1989. 8-9. 

    • • •