C# と VB.NET の質問掲示板

ASP.NET、C++/CLI、Java 何でもどうぞ

C# と VB.NET の入門サイト

C#からデータベース書き込み [1]

[トピック内 23 記事 (21 - 23 表示)]  << 0 | 1 >>

■89037 / inTopicNo.21)  Re[12]: C#からデータベース書き込み
  
□投稿者/ 魔界の仮面弁士 (1896回)-(2018/10/26(Fri) 10:57:16)
No89035 (WebSurfer さん) に返信
> SQL インジェクション
> https://docs.microsoft.com/ja-jp/previous-versions/sql/sql-server-2008/ms161953(v=sql.100)

念のために書いておくと、御紹介いただいた URL は Transact-SQL の場合の話ですね。

他のデータベース、たとえば Jet SQL にしても PL/SQL にしても、
そのそれぞれで留意すべき記号やキーワードは異なっていますので、
自力でのサニタイズ処理は、どうしても SQL 言語固有の処理として記述せざるを得ません。
(だからこそ、パラメータークエリを用いることが有効な解決策になるわけですが)

なお、パラメータークエリを利用できない何かしらの理由があって、
文字列リテラルを SQL 埋め込みする必要がある場合には、
Jet SQL のバイナリリテラル構文を使うことで、
非可読文字も含めて確実に無害化できたりします。
可読性が著しく落ちるので、個人的にはお奨めしませんが。


> 質問者さんのケース、Access ではどうかとか、魔界の仮面弁士さんが言われるほど詳しく考え
> てませんけど。

個人的に SQL で厄介だと思っているのは、個数不定の IN 句問い合わせと、
『WHERE ProductName LIKE 何某』な検索パターンなんですよね。

IN については、配列入力に対応したミドルウェア等で対処できることもありますが、
LIKE の方はちょっと面倒。


たとえば "りんご100%生絞り" などといった「% を含む文字列」を LIKE 検索で抽出したい場合、
JET の SQL-89 モードなら ProductName LIKE '*%*' と書けますが、
JET の SQL-92 モードだと ProductName LIKE '%[%]%' と書かねばなりません。

で、こういう対応はパラメータークエリで解決する問題では無いので、
プログラム側でバリデーションとサニタイジングが必要になってしまうという罠。


ちなみに Oracle の場合は
 ProductName LIKE '%*%%' ESCAPE '*' -- VARCHAR2 な列の場合
 ProductName LIKE N'%*%%' ESCAPE N'*' -- NVARCHAR な列の場合
とします。ESCAPE 句の一文字には任意の一文字を指定可能です。

そして SQL Server の場合は、上記の両方に対応しており、
 ProductName LIKE '%[%]%' -- VARCHAR な列の場合
 ProductName LIKE N'%[%]%' -- NVARCHAR な列の場合
 ProductName LIKE '%"%%' ESCAPE '"' -- VARCHAR2 な列の場合
 ProductName LIKE N'%"%%' ESCAPE N'"' -- NVARCHAR な列の場合
の構文をサポートしています。

2 種類の対応方法があるというのは、一見すると融通が利くようにも見えるのですが、
角括弧のための無害化なども考慮すると、むしろ Oracle の方が対処しやすかったり。


> それ以前のパラメータ化をしないなんて言うのは問題外と思ってます。

同意。
引用返信 編集キー/
■89038 / inTopicNo.22)  Re[13]: C#からデータベース書き込み
□投稿者/ 魔界の仮面弁士 (1897回)-(2018/10/26(Fri) 11:39:56)
2018/10/26(Fri) 11:45:43 編集(投稿者)

No89037 (魔界の仮面弁士) に追記
> JET の SQL-89 モードなら ProductName LIKE '*%*' と書けますが、
> JET の SQL-92 モードだと ProductName LIKE '%[%]%' と書かねばなりません。
>
> で、こういう対応はパラメータークエリで解決する問題では無いので、
> プログラム側でバリデーションとサニタイジングが必要になってしまうという罠。

追加補足すると、上記は『〜を含む文字列を検索』する画面を作る際に、
パラメーターを用いて
 para = "%" + textBox1.Text + "%";
 sql = "SELECT * FROM TBL WHERE ProductName LIKE ?";
あるいは
 para = textBox1.Text;
 sql = "SELECT * FROM TBL WHERE ProductName LIKE '%' & ? & '%'";
として実装した場合の問題点を挙げたものです。
元質問では LIKE 検索の話は挙がっていないので、完全に蛇足なのですが。


で、こういう場合、問題になりそうな特殊文字( %,",[,_,],',# など)への
対処を完全に盛り込むのは大変なので、実際には、"%" や "[" や "]" の
利用を、アプリケーションの仕様として禁じてしまうことも多いと思います。


その意味においては、元質問者が書かれていた
>> McDonald's
>> のような「'」が入力されることがないので(会社名や氏名しか入力しないため)
という対応も、選択肢の一つであるとは思っています。
(それでも、パラメーター化すべきという点では変わりませんが)

ただし、『「'」が入力されることが無い』という言い訳が立つのは、
入力制限や検証コードなどを用いて、絶対に入力されないように
防御されているということが前提となります。

「普段の運用上で、そういう文字が必要になることは無いだろう」と
暗黙ルールとして考えているだけというのは NG ですね。
今は入力されていないというだけで、今後必要になる可能性もありえます。

少なくとも、企業名としての
 "McDonald's Company (Japan), Ltd."
 "K's cube(株)"
 "(株)80'sスマイル"
などは実在しているわけですし。氏名についても同様ですね。
引用返信 編集キー/
■89039 / inTopicNo.23)  Re[14]: C#からデータベース書き込み
□投稿者/ Jitta (418回)-(2018/10/28(Sun) 11:41:23)
No89038 (魔界の仮面弁士 さん) に返信
> ただし、『「'」が入力されることが無い』という言い訳が立つのは、
> 入力制限や検証コードなどを用いて、絶対に入力されないように
> 防御されているということが前提となります。

2000年くらいにNECがやられて、「SQLインジェクションなんてのは新しい攻撃方法なので対処はできなかった」っていってたんだけど、
少なくとも1990年に、私は、先輩から「シングルクォートは使うと危ないから、入力データから消してね」と言われた。
SQL 文とつなげてデータベースに何らかのダメージを与える、あるいは情報を吸い出すといったことは、新しかったかもしれない。
でも、「おかしな動きをする」ことは10年も前にはわかっていたことなので、何らかの対処をしているべきだった。
それからさらに20年近く経っているんだから、「使われることはない」と無防備なのは論外でしょう。

90年代の時の対応は、物理キーボードを隠し、スクリーンキーボードにシングルクォートその他の記号を出さない。
初期データは徹底的にクレンジング。
引用返信 編集キー/

このトピックをツリーで一括表示

<前の20件
トピック内ページ移動 / << 0 | 1 >>

このトピックに書きこむ