When I recently wrote about my first impressions of Kaminsky’s Interpolique, I mentioned that the only thing I didn’t like is that PHP doesn’t offer any way to protect against syntactic mistakes, such as where the programmer mistakenly uses a
$ instead of a
Today we’ll look at how Interpolique can be implemented in Haskell in such a way that we force the developer to use Interpolique when creating a SQL query, precluding the possibility of the
^^ mixup bug. In doing so we’ll see that we don’t need anything like PHP’s
eval to get the job done.
All of the code for this post is on github: InterpoliqueQQ.
Since version 6.10 of the Glorious Haskell Compiler, we have had the ability to essentially define new language syntax. This functionality — called quasi-quotation — is useful for embedding mini-languages into Haskell in a type-safe way. Since Interpolique is basically a mini-language (it’s only operator is the
^^ interpolator), it is natural to use quasi-quotation when implementing Interpolique in Haskell.
Let’s look at an example of what this looks like when it’s being used. On the Interpolique site, an example of an attempted SQL injection is given. The crux of the example is the following code:
$conn->query(eval(b('insert into posts values(^^_POST[author] , ^^_POST[content] );')));
In InterpoliqueQQ (see
Test.hs in the InterpoliqueQQ code), the same code can be written as
query = [$interpolique| insert into posts values(^^author , ^^content ); |]
If we hop into interactive-mode with GHC, we can see the value of
*Test> query InterpoliquedString " insert into posts values(b64d(\"Zm9v\"), b64d(\"JyBvciAxPTE7\")); "
Thus the run-time value of
query is, in fact, an Interpolique’d SQL query.
Why this is interesting
The important feature of InterpoliqueQQ is that this syntax offers protection in the form of static typing. If we inspect the type of
query we get
*Test> :t query query :: InterpoliqueQQ.InterpoliquedString
That is, this syntax creates a query whose type is
InterpoliquedString. In this implementation of Interpolique, the only way to obtain an instance of
InterpoliquedString is via this syntax. In other words, if a function is given a query of type
InterpoliquedString, it can be completely cetain that the query was generated using Interpolique. Since this syntax does not allow PHP-style string interpolation (that is, there is no analogue of
'insert into posts values($author, $content)), there is no way for a developer to introduce a SQL injection bug due to a misused interpolation operator.
(We can also note that InterpoliqueQQ does not use anything similar to PHP’s
eval, thereby rendering any objection to the presence of
InterpoliqueQQ is implemented in Haskell in less than 75 lines of code, relying on the powerful parsec parser combinator library, GHC’s quasi-quotation support, and the base64 encoder of the dataenc library.
This implementation is entirely proof-of-concept. In particular, it’s missing two things:
- Field-testing. Interpolique hasn’t (yet) been out long enough for peer review to have run its course, so certainly nothing can be said about whether or not this particular implementation is secure.
- Library support. This implementation is built on the
InterpoliquedStringtype. In order for this to be useful, there needs to be a SQL library which is ready to act on this type. For the time being, I’ve included the
InterpoliqueQQwhich just takes an
InterpoliquedStringand prints (to
stdout) the corresponding SQL code, as in
*Test> runQuery query insert into posts values(b64d("Zm9v"), b64d("JyBvciAxPTE7"));
At present time Haskell is a decidedly non-standard language to use for web development. Examples like this, however, suggest that it could be a powerful tool in this domain in the future.