12

May be I am not much clear about the stored procedure. Can someone explain me how stored procedure prevents SQL injection with a simple example using MySql.

12

Stored procedures are a form of parameterised query. The fundamental problem that causes SQL injection is data being treated as query language.

$query = "SELECT * FROM users WHERE username = '$username' AND password = '$password'";

In this example, if I set $password to foo' OR 'x'='x, we get this:

SELECT * FROM users WHERE username = 'blah' AND password = 'foo' OR 'x'='x'

Since the character 'x' is always equal to the character 'x', this query will always return rows regardless of whether the user / pass is correct. The database can't know that you didn't intend this, because it's only being given a string with no context.

In order to prevent this, you have to be able to know the difference between the query and the data. Stored procedures solve this problem by writing the query beforehand, with markers for parameters, so that data can be passed into them later. For example:

SELECT * FROM users WHERE username = ? AND password = ?

The database driver sends the name of this stored procedure (or, in standard parameterised queries, just the query text itself) and a list of parameters, as distinct separate entities in the protocol. This means that the database server can parse the query string as query language safely, and treat parameters solely as data, without any ambiguity.

I also wrote a longer answer a while back that explains all of this in a more verbose way, if that's any use to you.

  • Thanks for the answer. I would like to know what happens to the data inside these stored procedures? Sanitize? – Anandu M Das Oct 1 '14 at 10:44
  • 2
    @AnanduMDas No, that's not necessary. The database server, in a traditional string query, has to parse out the query language and data itself. This is why we have to sanitise the data, because it's ambiguous and could be mistaken for query language. When the two are separated out as part of the protocol (i.e. the query string and the data fed into it are split into separate sections of the packet), the data doesn't need to be sanitised because the database already knows that it's data, and won't treat it as query language. – Polynomial Oct 1 '14 at 12:29
  • @Polynomial, Do prepared statements work the same way? – Pacerier Jan 29 '15 at 0:19
  • @Pacerier Yes. Prepared statements are essentially the same thing as stored procedures, at least from this perspective. – Polynomial Jan 29 '15 at 13:00
  • Stored procedures are only safe if EXEC() is not being used. If you use EXEC() with dynamic content, you're vulnerable to SQL injections exactly as if you were executing the query manually. – kba Jun 24 '15 at 2:52
4

Stored procedures are not immune to SQL injection. As explained here:

https://blogs.msdn.microsoft.com/brian_swan/2011/02/16/do-stored-procedures-protect-against-sql-injection/

So long as dynamic SQL can be created inside the stored procedures, you are vulnerable to SQL injection.

And MySQL as of 5.0.13 onwards, have dynamic SQL capability:

https://stackoverflow.com/questions/190776/how-to-have-dynamic-sql-in-mysql-stored-procedure

And thus is vulnerable to SQL injection.

In SQL server, here is an example:

http://www.sqlinjection.net/advanced/stored-procedure/

VULNERABLE STORED PROCEDURE USING EXEC STATEMENT.
CREATE PROCEDURE getDescription
   @vname VARCHAR(50)
AS
   EXEC('SELECT description FROM products WHERE name = '''+@vname+ '''')
RETURN

And another example:

VULNERABLE STORED PROCEDURE USING DYNAMIC CURSOR.
CREATE PROCEDURE printDescriptions
   @vname             VARCHAR(100)
AS
   DECLARE @vdesc VARCHAR(1000)
   DECLARE @vsql VARCHAR(4000)
   SET @vsql = 'SELECT description FROM products WHERE name='''+@vname+''''
   DECLARE cur CURSOR FOR EXEC @vsql

   OPEN cur
   FETCH NEXT FROM cur INTO @vdesc

   WHILE @@FETCH_STATUS = 0
   BEGIN
      PRINT @vdesc
      FETCH NEXT FROM cur INTO @vdesc
   END

   CLOSE cur
   DEALLOCATE cur
RETURN

And in Oracle, here are the examples:

http://software-security.sans.org/developer-how-to/fix-sql-injection-in-oracle-database-code

https://www.blackhat.com/presentations/bh-europe-04/bh-eu-04-litchfield.pdf

The above presentation by David Litchfield in Blackhat Europe has something more serious, from SQL injection it can lead to privilege escalation - so a normal Oracle user can be running as a DBA if the stored procedures are created by DBA (eg, all Oracle system objects).

3

A SQL database works a statement in several steps. At first the test of the SQL statement is parsed, after that it will be optimized and compiled. When this is finished the database has now a internal piece of software that can run the given SQL statement.

Stored procedures are pre compiled. In other words the database creates that internal piece of software before you use it. In this case only programm code is interpreted without any influence of parameters.

If you pass a full SQL statement inclusive parameter to the database it process the above described steps.

For instance ...

SELECT * FROM myTable WHERE id=1

or you give something like that ...

SELECT * FROM myTable WHERE id=1;DROP TABLE myTable

Normally nobody would write a statement like the second one in his programm code, but if you take for instance direct parameters from a web request, it is possible that a statement like that results.

var sqlString="SELECT * FROM myTable WHERE id=";
sqlString = sqlString+request.getParameter("id");
// database parse, compile and optimize
var result=database.doQuery(sqlString);

If you use Stored Procedures or Prepared Statement. The parse and compile process is allready done in database. All the interpretation depends on your programm code. When you call it the database only insert the given parameters to the precompiled code and it nows the eccepted datatypes for it.

var sqlString = "call queryMyTable(?)";
// get the precompiled statement from database
var statement = database.createStatement(sqlString);
// inject the parameter
statement.setParameter(1,request.getParameter("id"));
// if 'id' is a number it works fine ...
// but if 'id' is '1;DROP TABLE myTable' you will got a type cast error and the risk of SQL injection is banned
var result = statement.execute();

Stored procedures and prepared statements are in view of the security equal.

  • The code is sample code - no special programming language :-D – OkieOth Oct 1 '14 at 7:41
  • Here is another example :-D xkcd.com/327 – OkieOth Oct 2 '14 at 7:40
0

Another way to think about it, to be explicit and augment the already given answers.

SELECT * FROM users WHERE username = 'blah' AND password = 'foo' OR 'x'='x'

Without the prepared statement the OR after the 'foo' is treated as code

Now, with the prepared statement from the perspective of the database the password tried is:

'foo' OR 'x'='x'

I.E the OR (and everything else) after 'foo' is treated as data

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.