ストアドプロシージャはSQLインジェクションを魔法のように防ぐことはありませんが、SQLのインジェクションを防ぐことは非常に簡単です。必要なことは、次のようなものだけです(Postgresの例):
CREATE OR REPLACE FUNCTION my_func (
IN in_user_id INT
)
[snip]
SELECT user_id, name, address FROM my_table WHERE user_id = in_user_id; --BAM! SQL INJECTION IMMUNE!!
[snip]
それでおしまい!この問題は、文字列連結(つまり、動的SQL)を介してクエリを形成する場合にのみ発生し、そのような場合でもバインドできる場合があります!(データベースに依存します。)
動的クエリでSQLインジェクションを回避する方法:
手順1)動的クエリが本当に必要かどうかを自問します。入力を設定するためだけに文字列をつなぎ合わせているのであれば、おそらく間違っているでしょう。(このルールには例外があります。1つの例外は、一部のデータベースでクエリをレポートすることです。実行ごとに新しいクエリを強制的にコンパイルしないと、パフォーマンスの問題が発生する場合があります。 )
ステップ2)特定のRDBMSの変数を設定する適切な方法を調査します。たとえば、Oracleでは次のことができます(ドキュメントから引用)。
sql_stmt := 'UPDATE employees SET salary = salary + :1 WHERE '
|| v_column || ' = :2';
EXECUTE IMMEDIATE sql_stmt USING amount, column_value; --INJECTION IMMUNE!!
ここでは、まだ入力を連結していません。あなたは安全にバインドしています!やった!
データベースが上記のようなものをサポートしていない場合(願わくば、どれもまだこれほど悪いわけではありませんが、私は驚かないでしょう)-または、入力を連結する必要がある場合(クエリをレポートする「時々」の場合のように)上記でほのめかしました)、適切なエスケープ機能を使用する必要があります。自分で書いてはいけません。たとえば、postgresはquote_literal()関数を提供します。だからあなたは実行します:
sql_stmt := 'SELECT salary FROM employees WHERE name = ' || quote_literal(in_name);
このように、in_nameが「[snip] or 1 = 1」(「または1 = 1」の部分はすべての行を選択することを意味するため、ユーザーは給与を表示できないはずです!)結果の文字列を作成します:
SELECT salary FROM employees WHERE name = '[snip] or 1=1'
結果が見つかりません(本当に奇妙な名前の従業員がいない限り)。
それがその要点です!今、私はちょうどポイント自宅を駆動するために、SQLインジェクションの対象にOracleの第一人者トム・カイトにより、古典的な記事へのリンクを残すみましょう:Linkyは