Date: Thu, 7 Jul 2005 14:26:58 +0900
From: "Akira Horikawa" <who@example.ne.jp>
堀川です、こんにちは
価格COMでは被害者側から正確な情報提供が無かったですが、
犯人側からの話によれば、『SQLインジェクション』という方法が
使われたようです。
SQLインジェクション攻撃に気づかない企業は山のようにある
http://itpro.nikkeibp.co.jp/free/NPC/NEWS/20050706/164102/
WebアプリケーションのCGIプログラムを開発している環境が、
UNIXであれば、外部から渡されるパラメータ文字列の中に
パイプ記号やリダイレクト記号などが含まれ、/etc/passwd等の
重要なファイルを簡単に盗まれてしまうので、十分なパラメータ
検査が必要だと徹底的に教え込まれます。
そのような経験をした技術者であれば、データベースと連携する
SQL文を書くときも、不正な文字列等が含まれていないかどうか
の検査を自然に行ないます。
本来このような検査は、UNIXのCGI開発の経験が無くても、当然の
こととして行なわなければいけませんが、大事なことは、外部から
渡されるパラメータの中に、
『仕様外の予想もできない内容が含まれることがある』
ということを自覚し、
そのような例外を除去するような検査プログラム
を書いているかどうかだと思います。
外部から渡されるパラメータの内容が全部インチキであることを
前提にシステムを作っているかどうかの姿勢が大事です。
外部から渡されるパラメータを信用して、そのままSQL文を組み
立てているようなプログラムがあるときは、十分にご注意下さい。
前回記事『SQL インジェクションについて』
http://www.horikawa.ne.jp/cgi-bin/showlog.cgi?kd=2&no=1522
でも触れていますが、
SQL="SELECT * FROM TBL WHERE( ID=" + Param$ + ")"
このような感じで、外部から与えられる文字列(Param$)から
SQL文の文字列を組み立てている場合は要注意です。
SELECT文以外の命令でも、同様に十分な検査が必要です。
SQL="DELETE FROM TBL WHERE( ID=" + Param$ + ")"
のときに、Param$の入力が
'1 or (1=1)'
と入力されると、全部のレコードが削除されます。
--
--Transact-SQLの例題です
--
CREATE TABLE #TMP( ID INT )
INSERT INTO #TMP(ID) VALUES(1)
INSERT INTO #TMP(ID) VALUES(2)
INSERT INTO #TMP(ID) VALUES(3)
INSERT INTO #TMP(ID) VALUES(4)
INSERT INTO #TMP(ID) VALUES(5)
DECLARE @SQL VARCHAR(256)
DECLARE @PARAM VARCHAR(256)
SELECT @PARAM = '1'
SELECT @SQL = 'DELETE FROM #TMP WHERE( ID = ' + @PARAM + ')'
SELECT * FROM #TMP
EXEC(@SQL)
SELECT * FROM #TMP
DROP TABLE #TMP
上記プログラムの@PARAMへの代入を
SELECT @PARAM = '1 OR (1=1)'
と書き換えて、実行してみて下さい。
全部のレコードが削除されます。
本来@PARAMの内容が数字であるべきところに、論理演算子の
ORが含まれた文字列が渡される可能性を予想もしていなかった
ことに、問題が潜んでいます。
データベースシステム側に問題があるのではなく、外部から渡される
パラメータを100%信用した、このプログラムを作成した人間が悪いです。
皆様のシステムの中で、何の検査もせずに、ただ単純に、SQL文の
文字列を組み立てているような箇所があれば、その箇所には、
SQLインジェクションの問題が発生する可能性が潜んでいます。
SQLインジェクションを簡単に防ぐ方法は、SQL文の実行をEXECUTE命令
を使わずに、sp_executesql ストアドプロシージャに置き換えることです。
上記例題プログラムを次のように書き換えます。
変数名を多少変えています。
CREATE TABLE #TMP( ID INT )
INSERT INTO #TMP(ID) VALUES(1)
INSERT INTO #TMP(ID) VALUES(2)
INSERT INTO #TMP(ID) VALUES(3)
INSERT INTO #TMP(ID) VALUES(4)
INSERT INTO #TMP(ID) VALUES(5)
DECLARE @SQL NVARCHAR(256)
DECLARE @PARAM_DEF NVARCHAR(256)
DECLARE @PARAM_VALUE VARCHAR(256)
SELECT @PARAM_VALUE = '1'
SELECT @SQL = N'DELETE FROM #TMP WHERE( ID = @SET_PARAM )'
SELECT @PARAM_DEF = N'@SET_PARAM INT'
SELECT * FROM #TMP
EXEC sp_executesql
@stmt = @SQL ,
@params = @PARAM_DEF ,
@SET_PARAM = @PARAM_VALUE
SELECT * FROM #TMP
DROP TABLE #TMP
上記プログラムの中で、
SELECT @PARAM_VALUE = '1'
の部分を
SELECT @PARAM_VALUE = '1 OR (1=1)'
にして、実行して見てください。
サーバー : メッセージ 8114、レベル 16、状態 1、行 0
型 varchar から型 int への変換エラー。
データベースサーバーから、エラーが発生します。
レコードが全部削除されるよりは、エラーが発生するのがまだマシです。
ただこのようなエラーが発生することを、これを呼び出したCGIプログラムは
想定しているでしょうか?
やはり、SQL文の中で、正しい文字列かどうか、検査するようにしてください
------------------------------------
(株)日本技術ソフト開発
堀川 明 (Akira Horikawa)
07月07日(木曜日) 14時25分記
mailto:who@example.ne.jp
http://www.horikawa.ne.jp/msde/
[MSDE/SQLServerに関して、今、どんなことにお困りですか?] |
よろしければお困りの内容を、電子メールで教えて下さい。 |
質問を電子メールで作成する
|
[ウィンドを閉じる][MSDE/SQLServer FAQ ][MSDE / MSDE2000 技術サポート情報一覧]
|