Slashdot Mirror


How Do You Know Your Code is Secure?

bvc writes "Marucs Ranum notes that 'It's really hard to tell the difference between a program that works and one that just appears to work.' He explains that he just recently found a buffer overflow in Firewall Toolkit (FWTK), code that he wrote back in 1994. How do you go about making sure your code is secure? Especially if you have to write in a language like C or C++?"

7 of 349 comments (clear)

  1. Same way you hunt bugs by Llywelyn · · Score: 5, Informative

    0) Don't "roll your own" security unless absolutely necessary. Find someone else's implementations and work with those.

    1) Design the code for security, code to that design. I've seen of security bugs creep into code because it was never designed to be secure.

    2) Use static code checkers--such as Splint for C/C++ and FindBugs for Java--that look for security vulnerabilities.

    3) Peer reviews/code audits. Sit down with your code (and have others who know how to look for security vulnerabilities sit down with your code) and do a full review.

    Nothing is foolproof, but every little bit helps. It should be noted that all of the above also improve the overall quality of the code and reduce the number of overall bugs: Finding existent implementations of features that can be used can reduce maintenance and reduce bugs; Designing the code and putting it through a proper design review can catch a lot of logic problems and ensure that the code fits the requirements list--I've seen a huge number of synchronization bugs in Java simply because the author didn't know how to use synchronization properly; static code checkers find a lot more than just security bugs; and Peer Reviews/Code Audits can help isolate a variety of problems.

    --
    Integrate Keynote and LaTeX
  2. Valgrind by chatgris · · Score: 5, Informative

    By using valgrind. It's a virtual machine of sorts that runs your code and checks for any memory problems at all, including use of uninitialized memory. Combine that with thorough test cases, and you can be virtually assured that you have no memory errors in your C/C++ code.

    However, security is a lot more than buffer overflows... but at least it brings you up to the relative security of Java, with speed to boot.

    --
    Open Your Mind. Open Your Source.
  3. Re:Avoid direct memory access by ojQj · · Score: 5, Informative

    Unfortunately stl isn't binary compatible. That means you have to make sure you've compiled with exactly the same version of the stl with all the components of your program which accept and pass strings. This in turn makes it impossible to release different parts of your program separately from each other if you are using the stl at the interface between your components.

    There are a couple of solutions to this problem:

    1.) Pass character arrays at the interfaces between your components and immediately put those character arrays under the control of your library once they come in.
    2.) Write or find your own string library and pass that string class between program components. Be careful when doing this. Mistakes will come back to byte you.

    All of it's kind of nasty. It'd be nice if C++ could standardize their binary representation, even if it's only a standard valid per platform.

    Then there's also:

    3.) Choose a language which unlike C++ already has a standardized binary representation for strings, or a system global interpreter for a varying binary representation. This is just an extension of the "higher-level library which does the memory management for you" option really.

    Don't get me wrong -- I'm agreeing with the parent post. I'm just adding a caveat.

  4. Re:I don't. by Anonymous Coward · · Score: 5, Informative

    Grammar tip: "Effect" is a verb. "Affect" is a noun.

    Um, how's that?

    Your poor grammar has a chilling effect on me. If I were you, I'd find a way to effect an improvement in your knowledge. Luckily it affects me only a little. But the fact that so few seem to understand that these two words are both verb and noun leaves me of sad affect.

  5. Re:Don't use C++ as if it was only "C with classes by shutdown+-p+now · · Score: 3, Informative
    Uh... let's see. Open the most recent ISO C++ standard, and search for all occurences of "undefined". Repeat for "implementation-defined". Make a notice of how many of those are from the sections related to the Standard Library. Then meditate on the results.

    Yes, sure, if you use STL, you need not worry about getting the buffer size wrong. And that's about it - container indexing is not bound-checked (unless you use at() instead of operator[] - and that's about the only instance of run-time safety check I remember seeing in STL!), iterators can go outside their container without notice, or can suddenly become invalid depending on what their container is and what was done to it. Even leaving library issues aside, there are some nasty things about the language itself - it's just way too easy to get an uninitialized variable or a class member, or to mess up with the order of field initializers in constructor.

    This is not to say that C++ is not a good language. All of the above are features in a sense they are there for a reason - but they certainly don't make writing secure software easier.

  6. Re:Don't use C++ as if it was only "C with classes by swillden · · Score: 4, Informative

    whereas in a highly abstracted C++ program using the STL with lots of objects being copied and references flying around it can be a LOT harder to figure out whats really going on , especially since different compilers do different things under the hood.

    Those bugs aren't harder to track down than "old-style" bugs, in fact I think they're vastly easier to track down than, say, a wild pointer. The difference is that you're less experienced at dealing with the new problems, so they seem harder to you. With time and practice, you'll see through copy/reference errors quickly. In the meantime, a little discipline can cover your lack of experience -- never store raw pointers in collections, always "objects". If you don't want to create copies, then store objects of a smart pointer class. In fact, avoid ever using raw pointers at all. *Always* assign the result of a 'new' operation to a smart pointer (auto_ptr works for a surprisingly large set of cases, but you may have to get a reference counted pointer type or similar for others -- the BOOST library has some good options if you haven't already rolled your own).

    If you really run into different behavior with different compilers, then at least one of the compilers is buggy. That does happen, but it's a lot rarer today than it was a few years ago. When you find that situation, wrap the tricky bit behind another abstraction layer and implement compiler-specific workarounds so that your application code can just use the abstraction and get consistent behavior. In most cases, someone else has already done this work for you. Again, look into BOOST.

    --
    Note to ACs: I usually delete AC replies without reading them. If you want to talk to me, log in.
  7. Re:Don't use C++ as if it was only "C with classes by Curien · · Score: 3, Informative

    And that's exactly why so many things are "implementation defined" or "undefined". Many real-world users of C++ demand that, for instance, vector::iterator be a typedef for a raw pointer for efficiency reasons. Other equally-important users would prefer an iterator type that guarantees sensible behavior in the face of real errors. The ISO standard allows for both behaviors by conforming C++ implementations.

    There's something attractive about the Java and C# languages having all constructs so well-defined. But both of those languages could afford not to support real hardware. Both target abstract machines and are happy with the results. C++ can afford no such conceit: it thrives in high-performance, customized, and otherwise exotic environments.

    --
    It's always a long day... 86400 doesn't fit into a short.