Keep your development environment safe with tips from expert John McCormick in Builder.com's weekly Development Security Spotlight e-newsletter. Automatically subscribe to the e-newsletter now!
The Microsoft Foundation Classes static library contains flaws that make Internet Server Application Programming Interface (ISAPI) extensions vulnerable to denial of service (DoS) attacks. Fixing the problem won’t require you to rewrite any code, but you'll need to recompile any affected ISAPI code after installing Service Pack 6. (This service pack is for Visual Basic 6.0, Visual C++ 6.0 with Visual SourceSafe 6.0d.)
This illustrates a major challenge for developers who need to produce secure applications. Even if you can make any code you write secure, you're still at the mercy of all those libraries. In fact, the C language is notorious for creating software with buffer overflows because of library calls that probably shouldn't have been in the language in the first place.
Gets() is an excellent example. This function performs the common task of reading user input, but it keeps accepting the input until it sees a command ending the line or closing the file. That means that gets() can always be used to overflow any size buffer—no matter how large. If you use fgets() instead, you can set a parameter to limit the number of characters it will accept, thus preventing buffer overflows.
Strcpy() is similar in that it copies a string from a source to a buffer (again, it doesn’t limit the size of the string). There are safe ways to use strcpy(), such as adding a check; however, it’s often simpler to use strncpy(dst, src, dst_size – 1), which lets you specify a maximum number of characters. This is a particularly good alternative for many uses because it doesn’t throw an error when the input is too big—it simply terminates. If you need to generate an error when a specified string length is exceeded, you can use strcpy() along with a check, such as:
if(strln(src) >= dst_size)...
Strcat() concatenates a string onto the end of a buffer. Strncat() is a safer alternative, but it does require that you monitor the room left in the buffer. Other common functions to avoid if possible (in other words, use them very carefully and only when it's absolutely necessary) include:
- sprintf() and vsprintf()
- scanf() and sscanf()
This list names some of the worst offenders. Also, even though there are safer alternatives for most of these functions, those alternatives aren’t absolutely safe. You can still get into trouble using them—often with unterminated strings or by specifying the wrong buffer size.
Every platform will be a little different, but it will repay you for years to come to take some time to look over the various functions you normally use. Don't look at them from the viewpoint of how easy they make a certain programming task, but rather look for all the dumb mistakes they make possible. See if there aren’t better alternatives; there probably are. If there aren’t, consider making up a list so you can be especially careful when you do need to use the riskiest functions.
Some people claim to be able to program in dozens of languages, but I'm always suspicious about how secure the final product is. It isn’t difficult to learn syntax and the commands for a variety of languages, but if you don’t have an in-depth knowledge of the various functions and libraries, then you can’t know how to secure a program.
When it comes to secure coding, C is by far the worst of the commonly used languages. There are so many ways of doing things and ways to mess up that no amount of skill can really make a C application absolutely secure, especially because of vulnerabilities in those black box libraries. On the other hand, experienced C developers can come pretty close to making an app secure, especially if they religiously avoid the most dangerous functions.