Since Michael Howard moved from Redmond to Austin, I’ve had the privilege to see him present several times now. This is the guy who literally wrote the book on writing secure code and the secure development lifecycle. He is a fantastic speaker and I’d highly recommend checking him out if you every get the opportunity. Yesterday, I heard that he was speaking on securing your code at the San Antonio OWASP meeting so I decided it was worth making the drive down to see his presentation. So, I give to you Michael Howard’s Top 10 Strategies to Secure Your Code straight out of one of his Microsoft TechNet presentations.

Michael began by giving us the definition of a secure system. He said “A secure system does what it’s supposed to do and no more.” It’s such a simple concept, but in practice such a hard thing to achieve. Here are his suggestions on how to accomplish that:

1. Remember: You will never get your code right!

  • Attacks get better, not worse
  • Action: Reduce your attack surface by implementing the concept of least privilege, authenticed connections by default, disable less-used functionality (the 80/20 rule), and use as many defenses as possible.

2. Use All Possible Defenses

  • A large portion of the Security Development Lifecycle focuses on defenses.
  • Extra defenses help to protect customers if attacked
  • Defenses either stop the attack or make life harder for an attacker
  • Action: Add XSS defenses (always HTMLEncode output), add SQL Injection defenses, add buffer overrun defenses, etc.

3. Leverage Threat Models

  • Threat models not only benefit the design
  • They help you understand your code more by analyzing where data comes from, what trust level it runs at, and gives special attention to external dependencies and assumptions.
  • What data are you storing? (privacy concerns)
  • Action: Build effective threat models that help identify entry points (local vs local subnet vs remote) and rank accessibility (admin vs user vs anonymous). A higher attack surface means that you better have good code. Consider reducing your attack surface. Review code extra along anonymous data paths.

4. Never Trust Data

  • “All data is evil until proven otherwise.”
  • The most heinous bugs are because of too much trust in your data.
  • ~49% of security bugs tracked by CVE’s between 2001 and 2007 were due to too much trust in data.
  • Action: Don’t solely use “blocklists”. Constrain data to only what you know to be good. Reject data which you know is bad. Sanitize by encoding if possible (HTML encode).

5. Fuzz!

  • Fuzzing is designed to find reliability bugs, but reliability bugs = security bugs
  • A buffer overrun may crash an application
  • The right payload could execute malicious code
  • Fuzzing is a strategy to prove you messed up strategy #4.
  • Distinguish between dumb (random data) and smart (targeted data) fuzzers.
  • Action: If you consume files or network data, you MUST fuzz! Microsoft’s SDL mandates at least 100,000 iterations per file format. Fuzzing especially important with anonymous network users and remote endpoints. You can buy or build fuzzers, but you have to automate the fuzzing (dedicate a computer or three). Add a “layer of pain” to your application. Michael talked about adding a “fuzz” flag to your code which you can turn on to set NULL to non-NULL, flip adjacent bytes, toggle upper bits, write junk, truncate strings, extend streams, etc.

6. Stop The Bleeding

  • Attackers attack all code.
  • Don’t add insecure code to your product.
  • “Friends don’t let friends write insecure code”
  • Action: Security training for all engineers (instructor-led with knowledgeable instructors or “just in time” training before you begin a specific project. Create a “Security Quality Gate” where you check for banned API’s, lousy crypto, and make sure the code passes all code analysis tools.

7. Recognize The Asymmetry

  • “The Attacker’s Advantage, the Defender’s Dilemma”
  • The odds are against you. You have to get 100% of your features right 100% of the time with many constraints.
  • The odds are in favor of the bad guys. They can spend as long as they want to find one bug.
  • Action: Stop the bleeding, but cure the patient too. The bad guys “whack” all code. Review and fix legacy code too. Deprecate old features.

8. Use The Best Tools At Your Disposal

  • Tools are not a panacea, but they do help.
  • Tools do something that humans cannot…they scale
  • Tools can give you a feel for how bad your code might be. Lots of warnings may indicate poor quality code.
  • Action: Use all of the tools that you have at your disposal. Use static analysis tools on every build. Run your tools an all code.

9. Stay One Step Ahead

  • The security landscape is constantly changing
  • There might be bugs in code that hasn’t had patches released yet.
  • Action: Stay one step ahead. Learn from your past mistakes. Read! Nominate a security champion who can distill and disseminate security intelligence to your organization. Sign up for bugtraq, read, etc.

10. Security of the Software is Up to (Singular) You

  • Secure products are made from secure code. Secure code is written by an individual. You cannot be replaced by a tool. Therefore, the security of a product is totally up to you.
  • Your code will be scrutinized and attacked, but will it be compromised? The difference is totally up to you.
  • Action: Take pride in your code. Use all of the tools at your disposal. Take advantage of every language construct that leads to greater safety and security. Have your code peer-reviewed. Don’t be scared or too vain to ask for help. Do not pass the buck.

So, there are obviously a ton of things to take away from this presentation. Remember that we’re all human and nobody expects us to be perfect, but there are a lot of things that we can do to minimize those effects of our imperfections. It’s kinda like the old story about the two guys walking in the jungle when a lion attacks them. You don’t need to run faster than the lion, you just need to run faster than the other guy. Start by writing good code and a potential attacker will likely move on to an easier target.