Secure Software Development the practice of writing software without vulnerabilities. The focus is on the software itself, not on administration. Administrative security is about configuring security groups, firewalls, managing credentials, using encryption, and instituting practices such as, oh, say, not doing everything as the root user.
The administrative stuff is incredibly important! But understanding how to write secure code is indispensible too. Know both!
A lot of secure software development comes down to ensuring that you don’t allow attackers to run their code on your system (e.g., through buffer overflows or failure to sanitize inputs) but there’s more. We’ll cover a little bit.
Here is an eclectic mix of references you should browse or read:
There are hundreds of known vulnerabilities and different ways to categorize them. But there are a few categories that are really good to know:
|Injection||Getting code on the victim’s system and getting the system to run it.||SQL Injection, XSS|
|Enumeration||Figuring out information, like user names, by making zillions of guesses and quickly checking which ones are right.||User Enumeration|
|Timing||Figuring out information based on how long it takes a system to respond to certain inputs.|
|Denial||Preventing the victim’s system from running properly, either by flooding it with traffic (perhaps via amplification) or choking off legitimate traffic to it||Billion Laughs, Fork Bomb, Slowloris, R.U.D.Y.|
|Forgery||Tricking a user into doing something by the attacker pretending to be someone it is not.||CSRF|
Some are pretty low-level, in basic code itself, and some are related to networks, some to the the web.
Just sticking to a few classics here. These are vulnerabilities due to poorly written software, not due to poor administration practices and system misconfigurations.
Code that accepts user input and manufactures a database query string with that user input is vulnerable and someone will find a way to mess you up. Let’s say some code is written like:
query = "select * from users where name='" + user_input + "';"
Alice then the query is just:
select * from users where name='Alice';
But if the user sends in
Robert';drop table students;-- the query becomes
select * from users where name='Robert';drop table students;--;'
Defend against this by using parameters, e.g.,
select * form users where name=? or avoid SQL and use a programmatic interface to your database, e.g.
Users.select().filter_by('name', user_input). Both of these techniques will get the quotes correct. Don’t try to deal with the quotes yourself; just one mistake and it’s game over.
Enter your name:
If the code accepts the name and then attempts to render it in HTML, you might be okay:
but if some user enters
<script>alert('XSS!!')</script>, then the browser sees, and tries to render:
<div style="greeting">Hello, <script>alert('XSS!!')</script></div>
and the script runs!
A simple alert is an annoyance, but you know, you can craft scripts that read your local storage, read your cookies, read some other things from the DOM.... So the thing attackers try to get in there is something like:
Attackers can figure things out if for some inputs they get a response in a 1ms and for others it takes 100ms or so. You might need to artificially slow down error responses. See the Wikipedia article on timing attacks as they pertain to attacks on cryptosystems.
Here the attacker knows that the victim will be accepting XML input and will be parsing it. So the attacker sends this small payload:
<?xml version="1.0"?> <!DOCTYPE lolz [ <!ELEMENT lolz (#PCDATA)> <!ENTITY lol1 "lollollollollollollollollollol"> <!ENTITY lol2 "&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;"> <!ENTITY lol3 "&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;"> <!ENTITY lol4 "&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;"> <!ENTITY lol5 "&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;"> <!ENTITY lol6 "&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;"> <!ENTITY lol7 "&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;"> <!ENTITY lol8 "&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;"> <!ENTITY lol9 "&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;"> ]> <lolz>&lol9;</lolz>
And there you go, the parser expands this to one billion
lols, 3 GB of data.
XML is a bit of cesspool, really. You might be surprised at just how many ways there are to attack. (Those XXE, or XML External Entity, attacks account for a lot, so if you find yourself required to use XML, stay away from external entities. Those are bad news.)
Cross-Site Request Forgery (CSRF) is an attack in which the attacker tricks a user into making a request on the attacker’s server using authentication credentials for another server (such as the user’s bank). The attacker now has the credentials and can so some serious damage to the victim’s account on the other server.
Writing in C or C++? Be careful to NEVER copy more data into a buffer than the buffer has room for, and never fill that buffer with data from the outside. If you do, an attacker my be able to overrun your buffer and overwrite the return address of the currently executing function on the stack to point to, you guessed it, some malicious code, which might even be a command to open up a new shell, sometimes with root privileges.
Low and slow attacks send traffic to a server painfully slowly, but just fast enough to avoid timeouts. A single client can open up tons of connections to a threaded webserver and really tie it all up; these are pretty hard to detect. Examples: Sockstress (during TCP 3-way handshake), R.U.D.Y. (HTTP POST), Slowloris (HTTP headers without any double CRLF).
Make sure to check out:
Administrative best practices include (but yes of course not limited to):
If you’re just a regular programmer, what kinds of things can you do, just in software, to stay safe?
strcat, ever! Use
strncatinstead, and ditto whenever you have an
nversion of memory functions.
crypto.timingSafeEqual(a, b)to compare secrets and hashes.
Content-Security-Policyso that, e.g., the browser can only load resources from one domain, guarding against some XSS.