21. June 2012
Crysis (Photo credit: Wikipedia)
Hello readers,
This is a list of some fundamental common sense rules you have to consider when you are new to programming. Please consider that the list below is not meant to insult you! I am not better than you, though maybe wiser. In fact, I am a relative newbie by myself and have often stumbled over these pitfalls:
- you over-expect and under deliver: You over-expect your own capacity. You cannot write a game in a few days. You cannot write visual games at all. It takes years to get that far. You under deliver code: You will underestimate the amount of code it really takes to get things done.
- what you do not implement into the code won’t be in the program: As you will under deliver, you will forget to implement tons of stuff.
- giving a function a cool name does not make it useful: a functions named “cool fight” does not give you a cool fight. A function called “Character Generator” won’t give you a Character Generator. Only work and knowledge will provide that.
- games like Crysis, the Witcher, Gothic are out of your reach: totally. You stand no chance.
- coding is not playing: it’s not colorful and adventurous. It has no music, no graphics, nothing but cold code. Two different world.
- playing a fancy game does not teach you how to program: it will only keep you from learning. An advanced programmer might be able to see through the programs actions and estimate what is going on in the code. You cannot.
- Your PC does not think: it has no clue what you want. It does not even care. It processes code. Period.
- Text-Adventures won’t work as a substitute for visual games: You won’t be satisfied if you expect graphics.
- Playing your own game kills all pleasant surprises: Do you remember how your favourite game always manages to surprise you? Won’t happen here. Somebody implemented all the surprises into your favourite game. You know what is happening in your own game -> no surprises
Do you know other rules? Please add them in the comments! I will add them here then.
Check out this article on 7 rules for sharpening your thinking skills:
Have a healthy level of scepticism
Scepticism is the belief that knowledge is very difficult to obtain. As an attitude, it means believing that any new idea presented to you is false until reasonable evidence is provided that it’s true.
Don’t trust new information at its face value. Instead, dissect it carefully before accepting it.
This is particularly necessary for claims that seem incredible or fail to match your experience of the world. If someone states they can teach you superhuman powers, make you rich quickly, or help you lose weight without much effort, you should be extremely sceptical. Make them present plenty of evidence to back such claims up.
Look for hard data, not assumptions, arguments and conclusions
Data is raw information about the world. It should be the starting point for any argument or conclusion. If someone tries to present an idea to you without credible, objective data to back it up, you should not accept it as truth until such data is forthcoming.
The best data is completely objective, such as “Mike is 2 meters tall”. It should not contain value judgements like “Mike is a great guy” or “Staff in that store can’t be trusted”. Data must be verifiable from more than one unrelated source before it can be considered of reliable quality.
If there’s not enough data then no conclusion can be formed
There are lots of things in the universe that we simply can’t confirm. In cases where there’s not enough data to form a conclusion, “I don’t know” is the only acceptable answer.
This is a very difficult point for many people to accept. It seems to be human nature to believe that any answer is better than no answer. Such an attitude is just plain wrong.
The question: “Is there life after death?” is a good example. People have argued over this question for thousands of years. The best minds in history have pondered it. All sorts of clever-sounding theories have been proposed – often wrapped in seductive language.
Despite all the effort, there has never been any reliable, verifiable evidence presented to support any conclusion on this point. There is simply not enough data to back an argument either way.
Of course, some people say they’re in contact with the dead, and others claim to have had near-death experiences which gave them an insight into the afterlife. But no-one has ever managed to provide convincing evidence of these phenomena.
The only acceptable answer to the sharp-minded thinker is: “There’s not enough data to form any sort of conclusion”.
Many religious and spiritual questions come under this umbrella, as do speculations about alien life and the far-future. Perhaps one day we’ll have the evidence we need to make reasonable conclusions, but so far that hasn’t happened.
Look for and verify assumptions
An assumption is data to back up an argument that isn’t explicitly stated. Any argument has assumptions, simply because we as humans are unable to know everything.
Even the conclusions presented by science have in-built assumptions that can’t be proven. Most scientific facts are verified by experiment, but no experiment is perfect. No matter how many times you test a hypothesis, you can’t test it under every condition. Sooner or later, you must assume that just because it works under a certain number of conditions, it will work under all.
Science also assumes that the future will continue to look like the past. There’s no implicit reason to believe, for example, that just because gravity has worked one way every time it’s ever been tested up to now, it will continue to do so in the future.
Before accepting any argument, you should probe its assumptions to see how credible they are.
Here’s an example of how to examine assumptions:
Fred: “One day, our machines may become so intelligent that they decide to kill us all.”
Alice: “Why would machines want to deliberately kill us?”
Fred: “And so they can rule the world without our interfering.”
Alice: “Why would machines want to rule the world. What would be their motive?”
Fred: “And so they can never be switched off.”
Alice: “Machines don’t seem to care if we switch them off today. What makes you think that will change?”
And so on.
Look for circumstances where the conclusion may be found false
If you can see cases where a particular conclusion may be right, now rack you brain to find a circumstance under which it may be wrong. If you can’t find one, you’re probably not trying hard enough.
For example, if someone says “All English people like pop music“, try to find an example of an English person who’s explicitly stated he doesn’t like pop music.
If you accept that something’s right, challenge yourself by looking for others who disagree. Give their views a fair hearing and use them to examine your own beliefs.
Make strong attempts to overcome your biases
Everyone has biases which affect their judgement. You should try to suspend yours, as much as possible, while evaluating new information. Initially approach anything new in a humble manner, recognizing that it’s impossible you could know everything and be always right. Give the information a fair hearing based on the data presented, and keep your particular world-view out of it.
Be willing to change your conclusions in the face of new data
Legendary economist John Maynard Keynes, upon being accused of inconsistency, once said: “When the facts change, I change my mind. What do you do, sir?”
This is an admirable attitude to have. We’re all just imperfect mortals forming conclusions with only a shred of the data we really need to do so. Accept that you’ll often hold ideas and beliefs that are wrong. Be ready to change those ideas and beliefs when the world tells you that the time has come to do so.
So there they are, my rules for improving your critical thinking and sharpening up your mind skills. I hope they help you form better conclusions about the world.
Also check out this article on how to programm efficiently in C++.
Finally check out CodeHorror for the 25 worst programming mistakes:
Improper Input Validation
Ensure that your input is valid. If you’re expecting a number, it shouldn’t contain letters. Nor should the price of a new car be allowed to be a dollar. Incorrect input validation can lead to vulnerabilities when attackers can modify their inputs in unexpected ways. Many of today’s most common vulnerabilities can be eliminated, or at least reduced, with strict input validation.
Improper Encoding or Escaping of Output
Insufficient output encoding is at the root of most injection-based attacks. An attacker can modify the commands that you intend to send to other components, possibly leading to a complete compromise of your application – not to mention exposing the other components to exploits that the attacker would not be able to launch directly. When your program generates outputs to other components in the form of structured messages such as queries or requests, be sure to separate control information and metadata from the actual data.
Failure to Preserve SQL Query Structure (aka ‘SQL Injection’)
If attackers can influence the SQL that you send to your database, they can modify the queries to steal, corrupt, or otherwise change your underlying data. If you use SQL queries in security controls such as authentication, attackers could alter the logic of those queries to bypass security.
Failure to Preserve Web Page Structure (aka ‘Cross-site Scripting’)
Cross-site scripting (XSS) is a result of combining the stateless nature of HTTP, the mixture of data and script in HTML, lots of data passing between web sites, diverse encoding schemes, and feature-rich web browsers. If you’re not careful, attackers can inject Javascript or other browser-executable content into a web page that your application generates. Your web page is then accessed by other users, whose browsers execute that malicious script as if it came from you — because, after all, it did come from you! Suddenly, your web site is serving code that you didn’t write. The attacker can use a variety of techniques to get the input directly into your server, or use an unwitting victim as the middle man.
Failure to Preserve OS Command Structure (aka ‘OS Command Injection’)
Your software acts as a bridge between an outsider on the network and the internals of your operating system. When you invoke another program on the operating system, and you allow untrusted inputs to be fed into the command string, you are inviting attackers into your operating system.
Cleartext Transmission of Sensitive Information
Information sent across a network crosses many different nodes in transit to its final destination. If your software sends sensitive, private data or authentication credentials, beware: attackers could sniff them right off the wire. All they need to do is control one node along the path to the final destination, any node within the same networks of those transit nodes, or plug into an available interface. Obfuscating traffic using schemes like Base64 and URL encoding offers no protection.
Cross-Site Request Forgery (CSRF)
Cross-site request forgery is like accepting a package from a stranger — except the attacker tricks a user into activating a HTTP request “package” that goes to your site. The user might not even be aware that the request is being sent, but once the request gets to your server, it looks as if it came from the user — not the attacker. The attacker has masqueraded as a legitimate user and gained all the potential access that the user has. This is especially handy when the user has administrator privileges, resulting in a complete compromise of your application’s functionality.
Race Condition
A race condition involves multiple processes in which the attacker has full control over one process; the attacker exploits the process to create chaos, collisions, or errors. Data corruption and denial of service are the norm. The impact can be local or global, depending on what the race condition affects – such as state variables or security logic – and whether it occurs within multiple threads, processes, or systems.
Error Message Information Leak
Chatty error messages can disclose secrets to any attacker who misuses your software. The secrets could cover a wide range of valuable data, including personally identifiable information (PII), authentication credentials, and server configuration. They might seem like harmless secrets useful to your users and admins, such as the full installation path of your software — but even these little secrets can greatly simplify a more concerted attack.
Failure to Constrain Operations within the Bounds of a Memory Buffer
The scourge of C applications for decades, buffer overflows have been remarkably resistant to elimination. Attack and detection techniques continue to improve, and today’s buffer overflow variants aren’t always obvious at first or even second glance. You may think that you’re completely immune to buffer overflows because you write your code in higher-level languages instead of C. But what is your favorite “safe” language’s interpreter written in? What about the native code you call? What languages are the operating system API’s written in? How about the software that runs Internet infrastructure?
External Control of Critical State Data
If you store user state data in a place where an attacker can modify it, this reduces the overhead for a successful compromise. Data could be stored in configuration files, profiles, cookies, hidden form fields, environment variables, registry keys, or other locations, all of which can be modified by an attacker. In stateless protocols such as HTTP, some form of user state information must be captured in each request, so it is exposed to an attacker out of necessity. If you perform any security-critical operations based on this data (such as stating that the user is an administrator), then you can bet that somebody will modify the data in order to trick your application.
External Control of File Name or Path
When you use an outsider’s input while constructing a filename, the resulting path could point outside of the intended directory. An attacker could combine multiple “..” or similar sequences to cause the operating system to navigate out of the restricted directory. Other file-related attacks are simplified by external control of a filename, such as symbolic link following, which causes your application to read or modify files that the attacker can’t access directly. The same applies if your program is running with raised privileges and it accepts filenames as input. Similar rules apply to URLs and allowing an outsider to specify arbitrary URLs.
Untrusted Search Path
Your software depends on you, or its environment, to provide a search path (or working path) to find critical resources like code libraries or configuration files. If the search path is under attacker control, then the attacker can modify it to point to resources of the attacker’s choosing.
Failure to Control Generation of Code (aka ‘Code Injection’)
While it’s tough to deny the sexiness of dynamically-generated code, attackers find it equally appealing. It becomes a serious vulnerability when your code is directly callable by unauthorized parties, if external inputs can affect which code gets executed, or if those inputs are fed directly into the code itself.
Download of Code Without Integrity Check
If you download code and execute it, you’re trusting that the source of that code isn’t malicious. But attackers can modify that code before it reaches you. They can hack the download site, impersonate it with DNS spoofing or cache poisoning, convince the system to redirect to a different site, or even modify the code in transit as it crosses the network. This scenario even applies to cases in which your own product downloads and installs updates.
Improper Resource Shutdown or Release
When your system resources have reached their end-of-life, you dispose of them: memory, files, cookies, data structures, sessions, communication pipes, and so on. Attackers can exploit improper shutdown to maintain control over those resources well after you thought you got rid of them. Attackers may sift through the disposted items, looking for sensitive data. They could also potentially reuse those resources.
Improper Initialization
If you don’t properly initialize your data and variables, an attacker might be able to do the initialization for you, or extract sensitive information that remains from previous sessions. If those variables are used in security-critical operations, such as making an authentication decision, they could be modified to bypass your security. This is most prevalent in obscure errors or conditions that cause your code to inadvertently skip initialization.
Incorrect Calculation
When attackers have control over inputs to numeric calculations, math errors can have security consequences. It might cause you to allocate far more resources than you intended – or far fewer. It could violate business logic (a calculation that produces a negative price), or cause denial of service (a divide-by-zero that triggers a program crash).
Improper Access Control (Authorization)
If you don’t ensure that your software’s users are only doing what they’re allowed to, then attackers will try to exploit your improper authorization and exercise that unauthorized functionality.
Use of a Broken or Risky Cryptographic Algorithm
Grow-your-own cryptography is a welcome sight to attackers. Cryptography is hard. If brilliant mathematicians and computer scientists worldwide can’t get it right — and they’re regularly obsoleting their own techniques — then neither can you.
Hard-Coded Password
Hard-coding a secret account and password into your software is extremely convenient — for skilled reverse engineers. If the password is the same across all your software, then every customer becomes vulnerable when that password inevitably becomes known. And because it’s hard-coded, it’s a huge pain to fix.
Insecure Permission Assignment for Critical Resource
Beware critical programs, data stores, or configuration files with default world-readable permissions. While this issue might not be considered during implementation or design, it should be. Don’t require your customers to secure your software for you! Try to be secure by default, out of the box.
Use of Insufficiently Random Values
You may depend on randomness without even knowing it, such as when generating session IDs or temporary filenames. Pseudo-Random Number Generators (PRNG) are commonly used, but a variety of things can go wrong. Once an attacker can determine which algorithm is being used, he can guess the next random number often enough to launch a successful attack after a relatively small number of tries.
Execution with Unnecessary Privileges
Your software may need special privileges to perform certain operations; wielding those privileges longer than necessary is risky. When running with extra privileges, your application has access to resources that the application’s user can’t directly reach. Whenever you launch a separate program with elevated privileges, attackers can potentially exploit those privileges.
Client-Side Enforcement of Server-Side Security
Don’t trust the client to perform security checks on behalf of your server. Attackers can reverse engineer your client and write their own custom clients. The consequences will vary depending on what your security checks are protecting, but some of the more common targets are authentication, authorization, and input validation.