Search code examples
mysqlsqlsql-serversql-injection

Can one prevent SQL injection by customizing # -- /**/ tags and ; DELIMITER?


As I understand, most SQL injection is done by inserting a malicious piece of SQL and commenting out the remainder of the query.

Of course this would only be an additional layer on top of known and proven best practices but is it possible to simply change the comment tags from the defaults of #, --, and /*...*/ to something a little less attacker friendly as in noInject (remainder of comment here)? so that the query throws an error rather than completing?

And further by changing the ; delimiter to something like eol or \|/

I'm using MySQL, but as a general question would this be worth the effort?


Solution

  • Even if such a change were possible (which it's not, unless you fork the MySQL source code and compile your own—not feasible with SQL Server) and would cause some injections to fail, it wouldn't catch them all.

    Let's imagine a PHP-driven website through which users can view their medical records. To enable the user to filter his records for those related to a particular illness, one permits the illness to be specified by its id as a query parameter:

    http://www.example.com/health/fetchmyrecords.php?illness=123

    The developer, relying on the fact that the server has been modified, makes no further effort to protect against SQL injection, so then does something like this:

    print_r(
      $pdo->query("
        SELECT *
        FROM   health_records
        WHERE  user    = $_SESSION[uid]
           AND illness = $_GET[illness]
      ")
      ->fetchAll()
    );
    

    Now suppose that user 987 requests the following URI:

    http://www.example.com/health/fetchmyrecords.php?illness=123+OR+1%3D1

    Consequently the RDBMS will receive the following query:

    SELECT *
    FROM   health_records
    WHERE  user    = 987
       AND illness = 123 OR 1=1
    

    SQL successfully injected! In this particular example the injection is fatal, since the RDBMS will parse that WHERE clause as:

    WHERE (user = 987 AND illness = 123) OR 1=1
    

    …so it will actually return every health record of every user in the database!

    Good luck affording the legal fees that will come out of that. It's a reasonable guess that your business will collapse, your personal finances will be ruined, your house will be repossessed, your wife will leave you, your kids won't speak to you and your cat will run away!

    The explanation (for the injection, not your cat's disappearance) is that none of the tokens that you modified were required!

    But let's suppose that you went further and modified every single token in order that any previously valid SQL injection would now result in an error: you still haven't protected against SQL injection, as an attacker need merely alter his attack to use your customised SQL variant. You have achieved little more than security through obscurity, which is not secure at all.

    As @Nanne has stated, parameterising your queries is the correct way to defeat SQL injection attacks (at least, those that attack literal values—if you accept untrusted values into other language tokens you will need to protect yourself in some other way, although that's a rare requirement and well beyond the scope of this answer).