- PR -

SQL インジェクションの防止

投稿者投稿内容
uk
ぬし
会議室デビュー日: 2003/05/20
投稿数: 1155
お住まい・勤務地: 東京都
投稿日時: 2005-07-07 18:10
引用:

がるがるさんの書き込み (2005-07-07 17:27) より:
パラメタクエリって、MS以外の世界観でも使用できるものでしょうか?


概念そのものはMicrosoftとはまったく無関係で、RDBMSでは当たり前のものです。
ですので、一般的なRDBMSを使用していて、さらに使用するAPIが対応していれば使えますよ。
がるがる
ぬし
会議室デビュー日: 2002/04/12
投稿数: 873
投稿日時: 2005-07-07 18:23
どもです。がるです。
引用:

未記入さんの書き込み (2005-07-07 17:41) より:
¥ (←半角バックスラッシュ) がエスケープ文字として扱われる処理系ってどのようなものがありますか? SQL Server, Oracle, C, Java いずれも問題ないようようですが。いや、むしろエスケープしようとすると ¥ が二重になってしまうのですが・・・。


んっと。とりあえず、MySQLとPostgreSQLについては「エスケープ文字として
扱われる」事を確認してます。
例えば
select * from test WHERE data='¥'';
select * from test WHERE data='''';
については等価に扱われているようです。

CとJavaの「問題ない」というのは…ごめんなさい、ちょっと
状況がよく把握できてないです(苦笑

編集注:
半角の¥を’に入れ込むとHTMLに反映されない?
そんなわけで、SQL文のところで全角使ってます。すんません。

[ メッセージ編集済み 編集者: がるがる 編集日時 2005-07-07 18:38 ]
uk
ぬし
会議室デビュー日: 2003/05/20
投稿数: 1155
お住まい・勤務地: 東京都
投稿日時: 2005-07-07 18:23
引用:

未記入さんの書き込み (2005-07-07 18:01) より:
「SQL Server の場合は」 という表現は、私が確認した範囲という意味です。他の RDBMS がどうなのか知らない・確認していないので、このように書きました。


いや、どうやって確認したのか知りたかったんですが。「専用のストアド経由」っていうのが
どういう処理なんだろう、と気になったんですよ。パラメータクエリの扱いてのは、RDBMSの
中核の機能の一つであって、ストアドで処理するようなもんじゃないだろう、って思うんですが。

引用:

実装が存在するかどうか知りませんが、パラメタ化クエリを使用できない RDBMS では、ミドルウェアがプレーンテキストに展開するしかないのでは? パラメタ化クエリをサポートしていない RDBMS で JDBC(PrepareStatement) や ADO(Command) のパラメータ指定をサポートしているものがあってもおかしくないと思います。


それはそうですが、そのような特殊な例をあたかも一般的な処理のように書かれるのはどうかと
思います。

引用:

それと、(密接な関係があるのは確かですが) パフォーマンス向上の要因になっているのはパラメタを使うことではなく、プリコンパイルによるものでしょう。


もちろんそうですが、「プレーンテキストに展開」(ってパラメータを値に置換するってこと
ですよね?)したら意味ないですよね?

引用:

パラメタを使わないとは言っていませんよ? プリコンパイルクエリを使わないだけです。パラメタは使いたいので自分で実装しています。それで、注意が必要な文字があれば教えて欲しいということ。


プロファイラの使い勝手のために、わざわざ「車輪の再発明」しているわけですよね?
そこまでするほどの理由ですか?
こばさん
大ベテラン
会議室デビュー日: 2004/03/17
投稿数: 147
投稿日時: 2005-07-07 18:29
 SQL Server の前提で。。

引用:

がるがるさんの書き込み (2005-07-07 16:48) より:
現状は
’ ” ¥ ;
の4種ですね。



 「'」は「''」(シングル2つ)に変換すれば、SQL 文として解釈しなくなるので解決ですよね?
 で、「"」や「¥」や「;」は、''の中にあるうちは悪さをしない、そう思ってます。

引用:

select * from account
where uid='<%= Replace(Request.Form("uid"), "'", "''") %>'
and pas='<%= Replace(Request.Form("pas"), "'", "''") %>';



 は私が最初に挙げた ASP での例ですが、Request.Form("uid") に 「'」「"」「¥」「;」のいずれが入ってきても問題起こさないですが。。


引用:

パラメータを使う事でここを考えなくても良くなるなら、その方が良いと思うんですよね。



 検索キーワード省略時に対応したものを作ろうとすると SQL文 が伸びるのがいやで・・・(もしくは完全にストアド化して分岐させるか)

select * from account where (uid=@uid or @uid is null) and (pas=@pas or @pas is null)

※このような認証時の例にパラメータ省略を考えるのは不適切ですけど、うーん、美しくない!って思っちゃいます。
がるがる
ぬし
会議室デビュー日: 2002/04/12
投稿数: 873
投稿日時: 2005-07-07 18:31
がるです。
引用:

ukさんの書き込み (2005-07-07 18:10) より:
概念そのものはMicrosoftとはまったく無関係で、RDBMSでは当たり前のものです。
ですので、一般的なRDBMSを使用していて、さらに使用するAPIが対応していれば使えますよ。


すみません、ちょっと書き方が悪かったです。
んっと。「概念そのものはMicrosoftとはまったく無関係で」ってのは
わかります。
# 厳密には「パラメタクエリの定義」がもうひとつどこにも書いてないので
# 若干ずれへの心配はあるのですが。

で。ポイントは多分「使用するAPIが対応していれば」なんだと
思います。
この部分で、実際に「Linux環境とかUNIX系環境とかで」使っている例が
ググれなかったので、あるのかなぁ、と思いまして。
まぁ似たようなクラスは実際自作しているのですが(苦笑

で、「あるのかなぁ」って思って質問をしてみた次第です。
がるがる
ぬし
会議室デビュー日: 2002/04/12
投稿数: 873
投稿日時: 2005-07-07 18:36
どもです。がるです。
引用:

こばさんさんの書き込み (2005-07-07 18:29) より:
 SQL Server の前提で。。


んむぅ、使ってない(苦笑
# UNIXerなので、MS系は不得手なんです(苦笑

ってなわけで、以下、的外れな可能性がありますのでご注意を。
識者の皆様からの突込みをお待ちしております(笑

引用:

 「'」は「''」(シングル2つ)に変換すれば、SQL 文として解釈しなくなるので解決ですよね?
 で、「"」や「¥」や「;」は、''の中にあるうちは悪さをしない、そう思ってます。


んっと。”と;に関してはその通りです。ただ、¥に関しては…どうなんでしょ?
MySQLやPostgreSQLでは「悪さをします」。ただ、SQL Serverでどうかはわからないです。

引用:

引用:

select * from account
where uid='<%= Replace(Request.Form("uid"), "'", "''") %>'
and pas='<%= Replace(Request.Form("pas"), "'", "''") %>';



 は私が最初に挙げた ASP での例ですが、Request.Form("uid") に 「'」「"」「¥」「;」のいずれが入ってきても問題起こさないですが。。


だとすると、SQL Serverでは「¥はエスケープとして扱わない」という動作があるのかもしれないです。
¥の悪さについては、私のちょっと前の書き込みを参照してみてくださいませ。
uk
ぬし
会議室デビュー日: 2003/05/20
投稿数: 1155
お住まい・勤務地: 東京都
投稿日時: 2005-07-07 18:46
引用:

がるがるさんの書き込み (2005-07-07 18:31) より:
で。ポイントは多分「使用するAPIが対応していれば」なんだと
思います。
この部分で、実際に「Linux環境とかUNIX系環境とかで」使っている例が
ググれなかったので、あるのかなぁ、と思いまして。


いにしえの時代から存在する埋め込みSQLなり動的SQLのAPIを使用すればできると思います。
#いまどき埋め込みSQLなんぞ使ってる人はそういないでしょうが

今時であれば、もっと便利なAPIもあるかもしれませんね。
未記入
ぬし
会議室デビュー日: 2004/09/17
投稿数: 667
投稿日時: 2005-07-07 19:15
引用:
いや、どうやって確認したのか知りたかったんですが。


だから、最初からプロファイラだって言ってるでしょ?

コード:
import java.sql.Connection;

import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.Statement;

public class Test {
public static void main(String[] args) throws Exception {
Class.forName("com.microsoft.jdbc.sqlserver.SQLServerDriver");
Connection cn = DriverManager.getConnection(
"jdbc:microsoft:sqlserver://localhost:1433;DatabaseName=Northwind;", "sa", "***"
);

Statement st = cn.createStatement();
ResultSet rs1 = st.executeQuery("select * from Products where ProductID = 20");
while(rs1.next()) {
System.out.println(rs1.getInt("ProductID") + ": " + rs1.getString("ProductName"));
}
rs1.close();

PreparedStatement pst = cn.prepareStatement("select * from Products where ProductID = ?");
pst.setInt(1, 30);
ResultSet rs2 = pst.executeQuery();
while(rs2.next()) {
System.out.println(rs2.getInt("ProductID") + ": " + rs2.getString("ProductName"));
}
rs2.close();

pst.close();
cn.close();
}
}


これを実行すると次のようにプロファイラに記録されます。

引用:

select * from Products where ProductID = 20
exec sp_executesql N'select * from Products where ProductID = @P1', N'@P1 int ', 30



で、私は後者の記述がキライということ。


引用:
パラメータクエリの扱いてのは、RDBMSの中核の機能の一つであって、ストアドで処理するようなもんじゃないだろう、って思うんですが。


あなたがストアドに変な固定概念を持っているだけでは? 別にストアドのすべてがユーザープログラマブル(とそれを実行する機構)である必要はないでしょ? SQL Server の場合、sp_executesql は拡張ストアドプロシージャとして実装されているので、内部がどうなっているのか良く分からないけど、多分、コアと密接な関係にあるのでしょう。ストアドという呼び出し形態を取る事でミドルウェアのインターフェイスがシンプルになるんじゃないかな。

引用:
それはそうですが、そのような特殊な例をあたかも一般的な処理のように書かれるのはどうかと思います。


一般的な処理だなんて書いてないですよ? むしろ、私の確認できる範囲として「SQL Server の場合」と断り書きをしていることのほうが多いはずですが?


引用:
もちろんそうですが、「プレーンテキストに展開」(ってパラメータを値に置換するってことですよね?)したら意味ないですよね?


意味って何の意味ですか? プリコンパイルによるパフォーマンス向上の恩恵は受けられませんが、十分にテストされたミドルウェアであれば、プレーンテキスト展開をしていても SQL インジェクション対策としての意味が十分あると思いますけど。

引用:
プロファイラの使い勝手のために、わざわざ「車輪の再発明」しているわけですよね? そこまでするほどの理由ですか?


ええ、そこまでするほどの理由です。

[ メッセージ編集済み 編集者: 未記入 編集日時 2005-07-07 21:09 ]

スキルアップ/キャリアアップ(JOB@IT)