Wednesday, 18 August 2010
DDS Value Object Presentation Video
Tuesday, 3 November 2009
SQL Injection is not an Indata Validation Problem
Dear
If DDS style use of value objects solves the indata validation problem , and if DDS style indata validation does not solve SQL Injection, then there is only one logical conclusion to draw.
SQL Injection is not an indata validation problem. Yes, that might be contrary to popular belief, but it is obviously so.
If not an indata validation problem, what kind of beast is it? And what can we do about it?
Yours
Dan
Saturday, 24 October 2009
Indata Validation is Not Enough for SQL Injection
Dear
When we do indata validation through value objects we get an application tier that is water-proof. The model describes exactly those data that we think are meaningful and can handle (“username, identifier with which the user present herself to the system; regexp [a-z]+“. Each piece of indata is validated as part of the value object constructor (public Username(String s)). For indata to pass through to application, it cannot avoid validation, as the application methods require the value object type (void authenticate(Username uname…)). What more can you ask for?
- Well, you see, we do not want usernames like “danbj”, we would prefer our real names, like “
No problem, we expand the regexp with uppercase letters and space, getting a regexp like [a-zA-Z\ ]+.
- Nice, but our respected colleague
Fair enough – we stuff Scandinavian letters and hyphen into the regexp as well, giving [a-zåäöA-ZÅÄÖ\ \-]+.
- Now there is only one person left: our highly respected Irish colleague Oliver O’Hehir.
Well, well, we are almost finished then, we only need to put the apostrophe into the regexp ending up with something along [a-zåäöA-ZÅÄÖ\ \-\’]+.
Wait, wait, wait!!! Who the h*** just logged in with username “’ OR ‘a’ is not null --“?
Sure, we might have tightened up the regexp to block out that specific attack string and any other malicious use of the format we can think of. But, it is always those we did not think of that causes the trouble.
Well, as always we can think that “SQL Injection is solved by prepared statements”, but remember that Injection Flaw is much larger than SQL Injection. The same vulnerabilities might be there when doing LDAP access, using parameters to construct file names (e g Directory Traversal), or if you have some Domain Specific Language (DSL) which you interpret. In any of these cases there might be a string that might well be fully legally formatted, but attacks the structure of how the underlying resources are used.
Over to a completely different domain: FM broadcast and music radio. In the FM radio broadcast system you must be able to shut down the transmitters from a remote site. Unfortunately, there is only one way to communicate with the transmitters – via radio. The problem was solved by defining a specific sequence of audio blips (very precise on frequencies, duration, and interval) and denoting that sequence the meaning “shut down the transmitter”.
The pioneering Swedish rap group JustD put that exact sequence as the final beat on one of their songs, without telling anyone. They must have laughed all the way home from the studio. That song has been played on Swedish radio exactly once.
The JustD track hack is a wonderful example of exploiting an Injection Flaw, there is no way to escape it “in band”. I have the same gut feeling about indata validation and SQL Injection.
No matter how we structure the indata model, there might always be some data that actually is valid indata, but causes the system to crash.
So, indata modelling and validation in all its glory: However necessary it is for upholding security, it is not sufficient.
Yours
Dan
Thursday, 8 October 2009
Validating away SQL Injection
Integer authenticate(Username username, String passwordMD5)
@Testpublic void shouldNotRegardInjectionAttackStringAsValid() {assertFalse(new Username("' OR 1=1 --").isValid());}
public class Username {// final making it immutablepublic final String username;public Username(String username) {this.username = username;}public boolean isValid() {return username.matches("[a-z]+");}}
Thursday, 1 October 2009
Domain Driven Security and Making Stuff Explicit in the Model
Dear
”But ’ OR 1=1 -- is not a valid username! That is just bad indata validation!”. Well, ‘ OR 1=1 -- might not look like the kind of username we had in mind, but invalid? Says who?
If we have a look at the code, the signature of the authentication method says:
Integer authenticate(String username, String passwordMD5)
Basically, in the code there is nothing saying that username is any special kind of data – it is just a string. And, as such, it can be any string – including ’ OR 1=1 --.
There might be conventions, even documented such, that a username should have certain structure – but the model represented in the code consider any string to valid to send into the method.
The Domain Driven Design take on this is that if you have more restriction in your intended model, then you should better put those restrictions in the code – explicitly.
So, let us take a small step in that direction – let us make Username an explicit part of the model. Later on we can elaborate that part of the model by making restrictions on usernames explicit, and even enforcing them. But let us not take too big a bite – for now we settle for shaping up the model.
If we think about it we can surly agree that username is a special kind of data, separate from amounts, order numbers, or phone numbers. It would simply not make sense to have a phone number “+
In static typed programming languages like Java, C# or ML, we use the type system with interface and classes to separate different kinds of data. However, if we audit the authentication code we will see that there is no representation of username on that level. The only place “username” show up is as the name of a String-typed variables and parameters. The knowledge “username is a specific kind of data with its own rules and restrictions” is not explicit in the code.
Enter class Username, which at this stage might be the simplest kind of value object.
public class Username {
public final String username; // final making it immutable
public Username(String username) { this.username = username; }
}
The important part here is of course that we now have a new type, which can be used by variables, fields, parameters, and returns to make the code explicitly talk about usernames.
The authentication method will change somewhat.
/** Authenticates a user with a given password.
* @param username
* @param passwordMD5 hash of password
* @return user id, or null if no matching account
*/
Integer authenticate(Username username, String passwordMD5)
throws SQLException {
Connection con = accountDs.getConnection();
Statement stmt = con.createStatement();
String sqlSelect = "SELECT uid FROM Accounts";
String usernameMatch = "username = '" + username.username + "'";
String passwdHashMatch = "passwdHash = '" + passwordMD5 + "'";
String sql = sqlSelect +
" WHERE " + usernameMatch +
" AND " + passwdHashMatch;
ResultSet rs = stmt.executeQuery(sql);
Integer result;
if(rs.next()) { // found account with matching password
result = rs.getInt("uid");
} else { // no matching account
result = null;
}
return result;
}
So, whoever wants to call the authentication method with a username, must first create a Username object via the constructor.
public class LoginAction {
void doit() throws SQLException {
Username username = new Username(form.username);
String passwordMD5 = form.password;
accountService.authenticate(username, passwordMD5);
}
}
Now the concept of username is explicit throughout the code, and actually talks the same language as the people working with it. In effect, we have made username a part of the ubiquitous language talking about the system.
Note that we are still not yet protected from bad usernames, that will be a later step - but at least we talk about usernames, not strings.
The distinction between username strings and usernames is subtle. This distinction might seem small, but I think it is essential – as the language form how we think. The moment the programmer start expressing herself in domain terms (creating a Username object), chances are higher that she will also question the indata parameter: Is this string really a username? Where did it come from? Has it been properly checked? No guarantee, but chances are higher.
We still have some way to cover before we have an API that is both easy to use correctly, and hard to use incorrectly – but at least we have taken a step in that direction. We still lack the constraints on usernames, and there is no enforcement at all.
However, if we can guide the programmers into thinking about the model a la DDD, and thus decrease the risk of severe application security flaws, then we have at least done something useful.
And it is usefulness that is the ambition of Domain Driven Security.
Yours
Dan
PS My colleague John Wilander just published a nice example on how they did with Swedish "person number" (roughly social security number) [Swedish]
Others recently read
- CSR, Knowledge, and a Student Conference
- Scala Actors are Just Code - No Magic
- Make Implicit Concepts Explicit in Code
- Project Goals using Effects or Feature List
- How Heavy is Estragon - Event-Based Scala Actor
- Introducing Domain Driven Security
- Vladimir Galore - Lots of Threaded Scala Actors Waiting for Godot
- Scala Actor Waiting for Godot - Vladimir Thread Version
- Demeter Saves Mocking Fairies
- Domain Driven Design to Speed us Up by Opening Options