web-dev-qa-db-ja.com

ストアドプロシージャはどのようにSQLインジェクションを防ぎますか?

ストアドプロシージャについてよくわからないことがあります。 MySqlを使用した簡単な例で、ストアドプロシージャがどのようにSQLインジェクションを防ぐかを誰かに説明できますか?.

14
Anandu M Das

ストアドプロシージャは、パラメーター化されたクエリの形式です。 SQLインジェクションを引き起こす根本的な問題は、データがクエリ言語として扱われることです。

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

この例では、$passwordfoo' OR 'x'='x、これを取得します:

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

文字「x」は常に文字「x」と等しいため、このクエリは、ユーザー/パスが正しいかどうかに関係なく、常に行を返します。データベースには、コンテキストのない文字列しか与えられていないため、これが意図していないことを認識できません。

これを防ぐには、クエリとデータの違いを知る必要があります。ストアドプロシージャでは、パラメーターのマーカーを使用してクエリを事前に記述し、後でデータを渡せるようにすることで、この問題を解決しています。例えば:

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

データベースドライバーは、このストアドプロシージャの名前(または、標準のパラメーター化されたクエリでは、クエリテキスト自体)とパラメーターのリストを、プロトコルの個別のエンティティとして送信します。つまり、データベースサーバーはクエリ文字列をクエリ言語として安全に解析し、パラメーターをあいまいさなくデータとしてのみ扱うことができます。

私も 長い回答を書いた しばらく前に、これがすべての使用法である場合は、より詳細な方法でこのすべてを説明します。

14
Polynomial

ストアドプロシージャはSQLインジェクションの影響を受けません。ここで説明したように:

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

ストアドプロシージャ内で動的SQLを作成できる限り、SQLインジェクションに対して脆弱です。

MySQL5.0.13以降では、動的SQL機能を備えています。

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

したがって、SQLインジェクションに対して脆弱です。

SQLサーバーの例を次に示します。

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

そして別の例:

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

Oracleの例は次のとおりです。

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

上記のBlackhat EuropeのDavid Litchfieldによるプレゼンテーションには、より深刻なものがあります。SQLインジェクションから特権の昇格につながる可能性があるため、ストアドプロシージャが作成されている場合、通常のOracleユーザーはDBAとして実行できます。 DBA(たとえば、すべてのOracleシステムオブジェクト)。

4
Peter Teoh

SQLデータベースは、いくつかのステップでステートメントを処理します。最初にSQLステートメントのテストが解析され、その後、最適化およびコンパイルされます。これが完了すると、データベースには指定されたSQLステートメントを実行できる内部ソフトウェアが組み込まれます。

ストアドプロシージャは事前にコンパイルされています。つまり、データベースは、使用する前にその内部ソフトウェアを作成します。この場合、パラメータの影響を受けずにプログラムコードのみが解釈されます。

完全なSQLステートメントを含むパラメーターをデータベースに渡すと、上記の手順が処理されます。

例えば ​​...

SELECT * FROM myTable WHERE id=1

またはあなたはそのようなものを与える...

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

通常、誰も彼のプログラムコードで2番目のようなステートメントを記述しませんが、たとえばWebリクエストから直接パラメーターを取得すると、そのようなステートメントが生成される可能性があります。

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

ストアドプロシージャまたはプリペアドステートメントを使用する場合。解析とコンパイルのプロセスはすでにデータベースで行われています。すべての解釈は、プログラムコードによって異なります。これを呼び出すと、データベースは、指定されたパラメーターをプリコンパイル済みコードに挿入するだけで、受け入れられるデータ型になります。

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();

ストアドプロシージャと準備されたステートメントは、同等のセキュリティを考慮しています。

3
OkieOth

それについて考えるもう1つの方法は、明示的であり、すでに与えられた答えを補強することです。

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

準備されたステートメントがない場合、「foo」の後のORは扱われますコードとして

ここで、データベースの観点からの準備済みステートメントで、試行されたパスワードは次のとおりです。

'foo' OR 'x'='x'

つまり、「foo」が処理された後のOR(およびその他すべて)データとして

0
james6125