セキュリティ関連でよく言われますよね。

でも、インジェクションの脆弱性はSQLだけではないのです。


まず、インジェクションという言葉の意味ですが、「注入」と言う意味です。


何を注入するかと言うと、「悪意」です(笑)


はい。

簡単に言うと、プログラム上に不備があり、注入された悪意をはじけないとセキュリティホールになります。


以下、具体的に見ていきましょう。



【SQLインジェクション】

例えば、ログインのIDとパスワードを認証することを考えます。

ユーザが入力したIDとパスワードを受け取ったところから考えてみましょう。

DBにSQL文でそのIDとパスワードが存在するかチェックに行きますよね?


<入力>

ID: nana

PW: july


<SQL>

ostringstream sql;

sql << "select id, pw from user where id='" << ID << "' and pw='" << PW << "'";


このプログラム、問題あるでしょうか?


おおありです!とかげ

ユーザがPWに「' or 0=0」と入力したらどうなるでしょう?

上のプログラムで作成されるSQL文は以下のようになります。


select id, pw from user where id='nana' and pw='' or 0=0


赤字がキーポイントです。

意味は、idフィールドが"nana"でpwフィールドが空文字の場合、

もしくは0が0と等しい場合、のレコードを返しなさい、となります。


当然ながら0と0はいつでも等しいので、全レコードを返すことになります。


これが先ほど言った「悪意」です。



解決策は、プレースホルダを使用するか、自分でSQLエスケープをすることです。

Javaの場合、JDBCのようなものがDB間の違いを吸収してくれます。

でもC++の場合、そのようなものは無いのでDBの提供するライブラリによって、プレースホルダがあったりなかったりします。

基本的には自分でSQLエスケープすることになるかと思います。


あとで、漏補で補足事項を書こうと思います。



【OSコマンドインジェクション】

これは、system()関数にユーザが入力した値を使用する場合などにおきます。

良くある例では、sendmail を引き合いに出します。

http://www.thinkit.co.jp/cert/tech/7/5/4.htm


ここでは、ファイルをダウンロードさせる例を考えてみましょう。

WEBでユーザがファイル名のリンクを押すと、filename=sample.txt などの引数が送信され、

そのファイルをダウンロードすることを考えます。


string file="sample.txt";  ←ユーザ入力した値

ifstream(file.c_str());


このプログラム、問題あるでしょうか?

おおありです!台風


引数の値はユーザ側で改ざんして送信することができます。

改ざんした値が、../../../passwd.txtなどだったらどうでしょうか?

もしパスワードファイルがあればダウンロードできてしまします。

もちろんファイルのパスが分かっていることが前提となりますが、WEBサーバのOSと使用しているWEBサーバが分かるとたいていどこに何があるか分かってしまいます。

なので、とても危険なのです。


ピリオドやスラッシュ(/)、\を入力したらエラーではじくようにしましょう!

他にもセキュリティに関する注意点はいくつもあります。

十分調べてプログラム設計しておきましょう!



漏補

漏:

SQLのプレースホルダについてです。

プレースホルダを使用するとシングルクォートなどをエスケープしてくれて、インジェクションの攻撃から守ってくれます。

ただ、like を使用する場合、難があります。

具体的にSQLを書いてみましょう。memoというフィールドが入力した単語を含むレコードを検索します。


select * from t_contents where memo like ?


では、%が無いのでだめです。 (?はプレースホルダです。)

例えば、ナナという文字を入力した場合上記のSQL文は以下のようになります。


select * from t_contents where memo like 'nana'


フィールドがnanaと完全一致するレコードしかひっかかりませんよね?



補:

これにはテクニックがあるのですが、結局自分でエスケープしないといけません。

以下のようにします。


select * from t_contents where memo like '%' || ? || '%'


意味、分かるでしょうか?

リプレース後のSQL文は以下のようになります。


select * from t_contents where memo like '%' || 'nana' || '%'


||は文字列連結なので、SQLの中で like '%nana%' としているのと同じです。

これなら分かりますよね?


でもこれでは不十分です。


例えば「100%ジュース」という単語を含むレコードを探したい場合どうなるでしょうか?

上記と同じくリプレース後のSQLのlikeの部分だけ抜き出してみると、以下のようになります。


 like '%100%ジュース%'


これだと、100 とジュースが含まれるレコードが抽出されてしまいます。

なので、%と_をエスケープする必要があります。

(likeではこの2つが特殊文字です)


プレースホルダに代入する前にlikeエスケープをして、それから上記の like '%' || ? || || '%' に代入しましょう。