Effective security boundaries require conclusive checks (data is or is not valid) with well-defined outcomes (access is or is not granted). Yet the passage between boundaries is fraught with danger. As the twin-faced Roman god Janus watched over doors and gates — areas of transition — so does the twin-faced demon of insecurity, TOCTOU, infiltrate web apps.
The TOCTOU demon’s faces watch the state of data or resources within an app. The two sides are named
- Time of check (TOC) — When the resource is inspected. For example, all data from the browser is considered “tainted” because a malicious user may have manipulated it. If the data passes a validation function, then the taint may be removed and the data permitted entry deeper into the app. For example, the app checks whether an email address is well-formed or text contains <script> tags.
- Time of use (TOU) — When the app performs an operation on the resource. For example, inserting the data into a SQL statement or inserting text into a web page. Weaknesses occur when the app assumes the state of the resource has not changed since the last check; vulnerabilities occur when the state change relates to a security control.
Boundaries are intended to protect web apps from unauthorized access and malicious data. They may be enforced by programming patterns like parameterized SQL statements that ensure query data cannot corrupt query grammar, or access controls that ensure a user has permission to view data. We see security boundaries when encountering invalid certs. The browser blocks the request with a dire warning of “bad things” might be happening, then asks the user if they want to continue anyway. (As browser boundaries go, that one’s probably the most visible and least effective.)
Ideally, security checks are robust enough to prevent malicious data from entering the app and being used to the attacker’s benefit. But there are subtle problems to avoid in the time between when a resource is checked (TOC) and when the app uses that resource (TOU), specifically duration and transformation.
One way to illustrate a problem in the duration of time between TOC and TOU is in an access control mechanism. User Alice has been granted admin access to a system on Monday. She logs in on Monday and keeps her session active. On Tuesday her access is revoked. But the security check for revoked access only occurs at login time. Since she maintained an active session, her admin rights remain valid.
Another example would be bidding for an item. Alice has a set of tokens with which she can bid. The bidding algorithm requires users to have sufficient tokens before they may bid on an item. In this case, Alice starts off with enough tokens for a bid, but bids with a lower number than her total. The bid is accepted. Then, she bids again with an amount far beyond her total. But the app failed to check the second bid, having already seen that she has more than enough to cover her bid. Or, she could bid the same total on a different item. Now she’s committed more than her total to two different items, which will be problematic if she wins both.
In both cases, state information has changed between the TOC and TOU. The security weakness was not marking the resource as newly tainted upon each change, thereby assuming the outcome of a previous check remained valid. You might apply a technical solution to the first problem: conduct the privilege check upon each use rather than first use (the privilege checks in the Unix sudo command can be configured as never, always, or first use within a specific duration). You might solve the second problem with a policy solution: punish users who fail to meet bids with fines or account suspension. One of the challenges of state transitions is that the app doesn’t always have omniscient perception.
Transformation of data between the TOC and TOU is another potential security weakness. A famous web-related example was the IIS “overlong UTF-8” vulnerability from 2000 (famous because it was successfully exploited by worms for months after Microsoft released patches). Web servers must be careful to restrict file access to the web document root. Otherwise, an attacker could use a directory traversal attack to gain unauthorized access to the file system. For example, the IIS vuln was exploited to reach the cmd.exe command if the app’s pages were stored on the same volume as the Windows system32 directory. All the attacker needed to do was submit a URL like the following:
Normally, IIS knew enough to limit directory traversals to the document root. However, the %c0%af combination did not appear to be a path separator to the security check, which was unaware of the overlong UTF-8 encoding for the forward slash (/). Thus, IIS received the URL, accepted the path, decoded the characters, then served the resource.
Unchecked data transformation also leads to HTML injection vulnerabilities when the app doesn’t normalize data consistently upon input or encode it properly for output. For example, %22 is a perfectly safe encoding for an href value. But if the %22 is decoded and the href’s value created with string concatenation, then it’s a short step to busting the app’s HTML. Normalization needs to be done carefully to avoid security weaknesses.
TOCTOU problems are usually discussed in terms of file system race conditions, but there’s no reason to limit the concept to file states. Reading source code can be as difficult as decoding Cocteau Twins lyrics. But you should still review your app for important state changes or data transformations and consider whether security controls are sufficient against attacks like input validation bypass, replay, or repudiation:
- What happens between a security check and a state change?
- Is the resource a “global”? How are concurrent read/writes handled?
- How long does the resource live? Is it checked throughout its lifetime, or only on first use?
- When is data considered tainted?
- When is it considered safe?
- When is it normalized?
- When is it encoded?
January was named after the Roman god Janus. As you look ahead to the new year, consider looking back at your code for situations where TOCTOU problems might occur.