The Most Dangerous Programming Mistakes
snydeq writes "Fatal Exception's Neil McAllister discusses the most dangerous programming mistakes, and what can be done to avoid them. 'Even more than input validation errors, this year's list is rife with application security blunders of all kinds. Some of them sound fairly esoteric, such as "inclusion of functionality from untrusted control sphere." But of all such errors, the highest-ranking one on the list is "missing authentication for critical function" — in other words, the attacker was able to gain access because there was no lock on the door to begin with,' McAllister writes. 'With the pace of Internet attacks accelerating, now is not the time to cut QA staff or skimp on testing and code review.'"
If you'd like to read what the mistakes *are*, instead of a fluff piece that amounts to "oh, they're so awful! And people make them all the time, too!", here's the actual original article: http://cwe.mitre.org/top25/index.html
Hopefully the increased use of frameworks that write sql will decrease that problem
Never antropomorphize computers, they do not like that
...Those are system design mistakes.
A programming mistake is one where you meant to type x+1 and instead you write x-1. Missing something like authentication or checking is a requirements or design problem, not a programming problem.
If software was a car, you wouldn't say it's a manufacturing problem if the car didn't have a place to install a lock - you'd say it's a design problem. It would only be a "programming" issue if it had a place for a lock but it was left uninstalled.
(Yes, I don't consider "programming" to include the design aspects; I consider "programming" to mean "conversion of requirements into computer code." The errors about which this article talks are mostly requirements problems, not implementation problems.
"There are a dozen opinions on a matter until you know the truth. Then there is only one." - CS Lewis (paraprhase)
Only little people are capable of error, so it must have been a programming mistake.
"Java and C# are better than PHP" wrapped in buzzwords and it mentions "SQL Injection attacks" (yawn).
The whole thing is insulting to read for everyone more competent than management. As usual.
0/10
That's how the legislators write law also.. Throw out anything, and let the courts sort it out.. a public works program for lawyers
For justice, we must go to Don Corleone
More Testers / QA is needed and stop the overtime working 80+ hour weeks just leads to more errors and bugs.
Also don't get me started on rush jobs that just become try to work around the bugs and not take the time to fix them.
it's-probably-fine,-we'll-test-it-live
Could describe every "upgrade" to slashdot that has happened since ... well probably ever.
Damn_registrars has no butt-hole. Damn_registrars has no use for a butt-hole.
The Therac-25 had some "Dangerous Programming Mistakes".
I wonder if the nudie scanners have any similar mistakes.
To work around Slashdot's brokenness, did you try double right-click, then open in new tab? It appears to work for me in Firefox 5.
No, I'm not saying programmers are lazy. It's just that there is always tension between getting a job done, and getting EVERY detail right.
They ALSO are not always as knowledgeable as they should be. How many programmers know that in 1752, when the Julian calendar was replaced by the Gregorian calendar, September 2 was followed by September 14? How many programmers care? Why should they? Yet this arcane bit of knowledge could make a difference in some software that deals with antiquities.
Just as there are arcane bits of knowledge needed to make perfectly precise date calculations, the same is true of security considerations. Programmers should HAVE TO KNOW every possible arcane exploit in order to write good code. They framework/language should take care of this.
pretty much all frameworks today have an easy and built in way to prevent sql injection.
True, parameterized queries work in most cases. But I've found a few places where they're not ideal, and I wrote a bit of framework to implement other ways to pass strings to SQL safely.
A lot of SQL APIs don't support parameterizing a query that includes a table-valued parameter, such as the anonymous single-column table on the right side of an IN expression (e.g. username IN ('bluebear', 'chief', 'filbert')). So I wrote and tested a function mysqli_escape_list($connection, $array) to escape each item in an array and then format it as such a table expression, and then I use this function every time I need a variable number of literals on the right side of IN or VALUES. A web site called bobby-tables.com strongly recommends against this method, instead preferring code that constructs a string of question marks, a string of types, and an array of reference variables in parallel and then calling $stmt->bind_param() through call_user_func_array(). This appears hairier than the method that I use.
A lot of database search user interfaces are based on the general concept of query by example: present a form representing a blank record to the user, then find records whose values match the fields that the user specified and ignore fields that the user left blank. There are two ways to implement this search in SQL. One is to include two separate parameters in the query for each field (e.g. "name", "ignore name", "town", "ignore town"). The other is to generate a WHERE expression and make sure to escape it properly. The first way is good when all fields are known up front; the second way is probably needed when the list of fields will expand in the future.
The Mitre list does include "Use of a Broken or Risky Cryptographic Algorithm" but in my experience that's far less common than improper use of a perfectly good algorithm. Many algorithms and modes have known weaknesses that require specific generation/handling of keys and initialization vectors to maintain good security. Most algorithms and modes that are secure against unauthorized *reading* of data still require an extra MAC step to prevent unauthorized *modification* of that data (including targeted bit-flips). Developers often take shortcuts in these areas because doing all of "the right things" adds a lot of extra complexity and can absolutely kill performance. Look at recent events involving Dropbox and Jungledisk for examples. I don't think the Mitre list adequately conveys that cryptographic security requires not just good low-level algorithms like AES or Blowfish but also good higher-level (usually domain-specific) algorithms governing how the low-level algorithms and their inputs are used.
Slashdot - News for Herds. Stuff that Splatters.
While TFS and TFA call them "programming" mistakes, the actual source refers to them as the "Top 25 Most Dangerous Software Errors".
No, that's a typographical error, not a programming mistake.
A programming mistake is when you incorrectly analyze the requirements and think you need to type x-1 to correctly implement them when in fact you need to type x+1.
But either one results in a "software error"; the list and the original source are fine, the fluff piece in between the original source and Slashdot (and, consequently, the Slashdot summary) is the only potential problem here.
While its fun to construct ways to point the finger somewhere else in an organization, or to pedantically categorize errors in to narrow boxes, what I'd say is that its a failure of each and every person who had sufficient contact with the product that they should have seen the relevant facts, and sufficient technical skill that they should have recognized the error, and who either did not recognize the error or who did recognize the error but did not take action to have it corrected [whether that was implementing a fix or providing notice up the line]. Plus all the people responsible for the process that produced the error.
And most of the errors on the list are things that, whether or not they should be explicitly foreseen in requirements, programmers are positioned to recognize and ought to be taking steps to prevent. Programming isn't narrowly constrained assembly-line work, at least in any organization that expects to produce quality software.
how do you generate a SanitizedString?
Via the object constructor.
SanitizedString s = UserInput; or doSQL(SanitizedString(UserInput));
If you allow implicit constructors then this: SQLfunc(UserInput); will pass a secretly sanitized version of the string to the SQL function.
Point is: If you stick to using the provided SQL library then it's impossible to pass unsanitized strings to it, the program won't even compile. This sort of thing should really be the default by now except language designers are too busy figuring out ways to let programming noobs multiply strings by fractions.
No sig today...
Microsoft's Visual C++ compiler will throw a huge number of warnings for things like strcpy, telling you to use strncpy_s or something like that.
You shouldn't even be using strcpy(). std::string has been around for more than ten years now.
Similarly arrays: Don't use them, use std::vector instead. Visual C++ vector even does range checking by default so this throws an exception instead of corrupting memory:
std::vector foo(10); // Will throw an exception in VC++...
foo[11] = 123;
A few basic changes in programming style can make C++ as safe as Java (but with none of the drawbacks). If you're still writing C code with your C++ compiler you're Doing It Wrong.
No sig today...
My compiler warns me about this if I forget...
No sig today...
Using a system where the program has to be trusted to do its job correctly is the bigger mistake. When you hand your car keys to a valet, you don't also give him power of attorney to sell your house, liquidate your stocks, savings, etc... but every operating system out there does something like that when you tell it to run a program. The program you run can do anything you are authorized to do. The default assumption is that it should have permission to do anything, no matter how stupid, dangerous, or downright evil.
This practice needs to end, about 10 years ago it should have ended... and we'll probably have to wait 10 more years because it's so freaking hard to get this idea across, nobody seems to be ready for it yet, by the way things seem to be going.
A user should be able to decide exactly which and how much of the resources they are authorized to use will be allowed to be accessed by a program they choose to run. If you want to run a program with read/write access to /sandbox, and the ability to read from the internet using a filtered http driver (one that doesn't allow puts, for example), you should be able to do so, without having to do any fancy footwork.
If put in to place, this type of system, which explicitly states what access things get, make it almost trivial to never get a virus or worm ever again. It's time to stop trusting programs, and only have to trust the hardware and OS to enforce our wishes.
I impatiently await the arrival of capability based security.
You left out some details about bounds checking that deserve some notice:
According the the C++ Standard, std::vector::operator[] does not do bounds checking -- if you want an exception to be thrown, use std::vector::at(). As an aside, I which they would have switched which one does checking and which one doesn't, but it is the way it is.
Visual C++ has an extension to do bounds checking on operator[]. Compile with _SECURE_SCL 1, which is the default. When an access goes out of bounds, the program will terminate. You can set another macro if you want an exception to be thrown, however.
I' think that Visual C++'s behavior is completely acceptable according to the standard (which only requires undefined behavior). However, it makes some C++ programmers uneasy because it's adding overhead to a very common operation that will often be found in inner loops (and with the safe option readily available). Hopefully the compiler can eliminate most of the checks by detecting loop bounds or somesuch.
Another detail about vectors: I've repeatedly heard that you can't use vectors when interfacing with C functions, as they operate on normal arrays. This isn't the case: just pass in the address of the first element (&vect[0]). Yes, this behavior is backed by the standard. The only caveat I'm aware of is that you have to be careful when doing anything to the vector that would cause it to move around in memory (such as call push_back() when it's already full) -- but that's already true of C arrays created with malloc().
However, there is one good reason to use C arrays in C++: when you need a small array allocated on the stack. As of C++0x, however, you should be using std::array for this purpose instead. The only other factor to consider are VLAs, which aren't part of standard C++ and I don't think Visual C++ supports them anyway.