Tuesday, July 31, 2012

Rules won't help …

As I mentioned earlier, mantras and empiric rules are often more misleading than helping in programming. In fact, I thought that directing your programming activities through a set of established rules is more dangerous than you can think.

It doesn't mean that you'll never achieve your goal if you follow those rules, but it will give you a false sense of security.


Rules to failure …


Using rules to conduct some activities is natural and comfortable. But, are we sure that following those rules will produce the desired effect ?

Take, for example, recipes (cooking ones.) We all experienced that before: you want to make a cake, choose one in your cook book (one with a very nice photo and not much work), you follow the recipe carefully, and end with some sort of  ugly dead creature from outer-space that taste like burned plastic.

What went wrong ? After several similar failures, it appears that changing various elements (time, quantity even ingredients … ) of the recipe provides a far more satisfactory result. Why ?

There's plenty of reasons. Of course, you can blame the book (and you may be right), but there's more. A good recipe, designed and written by a cooking expert (and maybe reviewed by some more cooking experts), is in fact a description of a chemical experiment. If you've done some, you know that too much approximation may leads to dramatic (and sometimes dangerous) unexpected results. Cooking is less dangerous (except for your taste), but the logic is the same: a wrong combination of manipulations, approximate timing and measuring leads to inedible meals and cakes.

At that point, you may think that the point is that you haven't do the job by the book and that you'll need to be more careful next time. But again, it's false. You won't be able to achieve a descent result without adapting the recipe.

Let's consider another example: on some packed sandwiches (you know that tasteless triangle things that you can buy in super-market), I've found opening instructions: « twist and pull » with a curved arrow indicating twisting direction. I've tried about 5 minutes to perform the operation and finally get a « shaken sandwich » (not without using some cutting tools to open the damned things.)

All of that because, there's the rule, the intention behind it, the way you understand it, the way you try to applied it, and the real action to perform. In fact, there's probably more than one way to do it, and some are simpler for you than the one described in rules.

So ? And what's about programming, then ?


Programming is finally no more than writing rules for the computer.

Thus, it may seems legit to apply to your self some rules when designing and programming ?

But again, there's some hidden issues there.

There's a lot of designing methodologies and software conception processes. All those tools are supposed to lead you through the best way to achieve your primary goals. They are collections of best practices and rationalized procedures, known to provides grant success in many other projects.

That's bullshit ! Success of most projects are due to people in the project, not how they organized. Of course, well suited methodology can help you and may event prevent some important mistake. But you can still get a bunch of craps, it will be the best designed bunch of craps of all time, but still a bunch of craps.

Next lesson: how to fail using programming design methodology:

  1. Choose a small random project with well known solutions (in order to compare to your production), possibly a project more directed to algorithms than data-managing. For example: « Your program will help a fictitious character lost in a maze to get out by the shortest path. You'll have access to the whole map. » You'll recognize a classic application for path-finding algorithm.
  2. Now, choose a method. I'll stay abstract on that matter (due to a lake of place.) So basically, you'll have an outer specification phase, a data model specification, then interaction specification and finally you'll get to more technical aspects and code.
  3. So, our program take what look like a map and the description of the character to somehow leads the character to the exit. The maze is provided as a bitmap with a distinct color for rooms and tunnels linking rooms.
  4. The main element that appears in the description seems to be the character (it comes first and the subject is to lead it in the maze.) We'll use it as our central element.
  5. Following our method, we will design a class diagram based on the idea that the main character is moving on an (almost) open-field (the original bitmap.)
At that point you may have notice that we're in trouble. While, a careful examination of the subject triggers some idea about path-finding in graph, we're stuck with bitmap exploration.

The error is obvious, we haven't choose the most efficient way to solve the problem. Basically, we should have notice that even if the input is in form of a bitmap, there's a notion of rooms (graph vertex) and tunnel (graph edges.) I made this mistake on purpose, to show you that a conception method won't help you to solve an issue, but help you to organize the process of building a solution.

This is a common mistake: project organization methodology, conception tools and any other software engineering processes are guidelines that kept you on track with big project, but they will never save you from bad ideas.

False security

This notion of rules guided conception provides a false sense of security. You're respecting a well establish software process, thus you shouldn't fail. Experience prove the contrary, the only things that a methodology can avoid are dispersion and diversion from the original concept: it keep you on track and help you evaluate the progression (and thus, possible delays.)

This is the main issue on relying on rules, just like the cooking recipes, following it won't lead you to success automatically.

And just like cooking, if you don't have good programmers to implement your design, even if the design is the best possible piece of conception, your project won't work.

I'm not talking about managed project against tech-lead, I'm just saying that rules, methodology (and thus management) are not guarantees of success, they're only there for keeping project on tracks.


Security, cryptography and laws.


Let's move to another related subject: security.

Playing with rules.

Non technical people often think that security can be enforce using security laws. This is somewhat related to playing some strategy game.

For example, when you play chess, you have a finite set of rules, and normally you can't play outside of these rules. These rules are constraint: at each point of the game, there's a finite set of possible moves. Based on this fact, you can use rules to protect yourself against your opponent's attack. For example, moving your king to be outside of the range of your opponent's menacing piece. Since, you both play with the same rules, he won't be able to conclude his attack (provides that you estimate all possible situation.)

If your opponent doesn't respect the rules, he's a cheater, and cheating implies loosing the game, unless no one sees it. So, rules are protecting you (you know the range of possible attacks) and still protect you when the other player is not fair.

Real life don't follow this scheme: if your opponent has an important goals, breaking rules won't stop him.

Laws against efficient technical solutions ?

There's recurring debates in many countries about regulating cryptography or software reverse engineering. The common idea is that if you forbid the use of strong cryptography, criminals and terrorist won't be able to securely exchange information. Bullshit !

Accessing strong cryptography, even when it's prohibited by laws, for someone that plans to perform criminal actions, is not impossible. In fact, it is relatively simple to find a sufficiently safe cipher with basic mathematical knowledge (an homemade cipher, based on xoring data with one time pad is quite simple as soon as you can transmit the key sequence to your buddy.)

The real result of constraining usage of strong cryptography is compromising normal users' security ! Since they can't use efficient tools (or they must rely on tools with known vulnerabilities), they expose their communication and their data to security threats !

Another common mistake is about reverse-engineering (or more generally analyzing software security.) For example, if someone decided to break a security protection of a credit card system for his own profit, it's main crime is not breaking the security protection, it's to exploit the security breach to steal money ! He is already on the wrong side of the laws, he won't care about another minor crime.

On the other hand, a security researcher that found some vulnerabilities in credit card protection is helping us ! Proving that there's a breach in a system that a lot of users trust, is far more important than prohibiting the break of the protection.

Once again, the point is that protection and safety don't come from rules or laws, they come from good and efficient software.

Secure programming recipes.

Another classical subject in software security is : secure programming. There's plenty of books on the subject, but unfortunately, most of them are recipes books: they show you well known mistakes to avoid and predefined code patterns that normally won't fail. The result is that we still have a lot of bad programs around there with plenty of (possibly yet to discover) vulnerable code.

I can sum-up what I think, secure programming should be:
  • Your program must only do what was specified in the first place
  • Your program must not do anything outside of the scope of its specification
  • Your program must be free of bugs.
The first two points imply that a program can only be safe if its specification includes what what must be done and what must not be done. A secure specification requires that you define the expected behavior in terms of authorized and unauthorized aspects.

The last point is the hard part, once again it emphasizes the need for technical qualities. But, it is also important that a program free of bug is not by itself safe. A good is example is the telnet protocol: the protocol is flawed by design (transmitting in clear text all the sufficient data for authentication is stupid) meaning that even if you're certain that your implementation is bug free, using telnet will never be safe (at least in wide open environment.)

And, again about recipes for secure programming, be aware that following them is not sufficient. For two reasons: first they not cover all possible mistakes; second, even if you follow them you can open some breach.

Let's take a basic example. When copying C strings, you should not use the infamous strcpy function and prefer strncpy. The reason is quite obvious: the first form assumes that the destination points to memory chunk that can hold all characters from the source parameters, on the other the later one take a bound for the copy. The issue is the well known buffer overflow attack (providing a very long string you can rewrite the return address of the function.)

But, using the later form is no more safe. Of course, you can pass a too small value as bound, but there's another issue: reading the manual of strncpy, we can see that if the source string is wider than the bound, no terminating null character will be added to the destination. What's the issue ? A further use of the destination string may again overflow, offering the opportunity to access sensitive data, or once again overwriting important values. This second form of error, may not lead to a new security issue, but it can, it will far more complex to track down since it won't break directly where the mistake was made.

The following toy-example will demonstrate a simple example:

#include 
#include 
#include 

void copy_and_print(char *text)
{
  char                  secret[] = "Hidden text.";
  char                  buf[32];

  // first copy the the original text in buf
  strncpy(buf,text,32);
  // Then print it using printf.
  printf("copied text: %s\n",buf);
  // use secret to avoid warning.
  fprintf(stderr, "  secret text: %s\n", secret);
}

int main()
{
  // prepare a long piece of text
  // wider than the 32bytes used in our function
  char                  text[34];
  for (size_t i=0; i<33; ++i)
    text[i] = 'a';
  text[33] = 0;

  // So try our function
  copy_and_print(text);
  // What happend ?

  return 0;
}

If your stack and compiler is similar to mine, it will print the hidden messages twice …

About constraining languages

Since I'm passionate about programming, I've tried and learnt many programming languages. While some language hasn't fit me for taste reason or because I've no use of it, some have let me a strange sensation of resistance, you know where you feel like if you're moving like molasses.

It takes me sometime to realize that it was related to languages that try to force you to use best practices. The first example (for me) was Pascal. Pascal is language designed for teaching and enforcing good practices of structured programming (against evil gotos and unguarded loops) and Pascal is somehow very restrictive.

The next in row was Java, once again, Java has for its goal to promote good object oriented methodology.

What happen when you code (or at least when I code;) using these languages ? You're forced to circumvent the constraints to be able to achieve your goals. Some simple example of (safe) piece of code became a huge and complex plumbing because the direct way to do it is prohibited by the language.

A curious aspect of such languages, is that they tend to prefer keywords rather than symbols. In more recent languages, it can also appears in constraint over code formatting (like fascist languages using indentation to delimit blocks.)

Conclusion


So, what was it all about ? I'm deeply convinced that while using guideline may proven some help in maintaining a process on track, it won't help you build better software. At least, you know that you'll be able to go as far as your idea can lead you, if the idea was bad, it won't save you from failure.

This concept is not only software related: rules, laws and the like are only able to protect you in games ! In real life, the only safeguard are hard-works and technical skills.

No comments:

Post a Comment