こんにちは。名古屋グループのとりです。
昨年まではリモートワークにする日が多く、静かな環境で集中できるかと思いきや、安物の椅子で座り心地が悪かったり、移動する事が無いので運動不足がストレスになったりと、やっぱり職場の方が仕事に集中できるなと思う今日この頃です。
今回取り上げるのは「SQLインジェクション」です。
私はWebやアプリの入力フォームに対して探索的テストを行う時、開発現場に居た時の経験から何か悪さできないかなとプログラム上誤動作を起こしそうな入力を試す事が多いのですが、同様の手法でデータベースを意図的に不正操作する方法をSQLインジェクションと呼びます。
SQLインジェクションは、システムの脆弱性診断を行っている現場寄りの内容になりますが、仕様の穴になりやすい内容で機能テストを実施する現場でも理解しておいて損はないと思いますので、具体的な事例を紹介します。
セキュリティ領域は非機能要件になるため、機能テストではカバーされない事がありますが、探索的テスト等の観点の1つとしてSQLインジェクションを取り入れると機能要件側でもリスクヘッジができて良い対策だと思います。
SQLインジェクションとは
SQLインジェクションの説明ですが、まず名称に入ってるSQLから軽く説明します。
SQLというのは、データベースに対して命令を投げる際の問い合わせ言語の事です。
アプリケーションやWebシステムのサーバで動くプログラム上からデータベースにアクセスし処理を行う場合、SQL言語で組まれた命令を投げて目的のデータを取り出したり、書き換えを行ないます。
SQL例
SELECT * FROM 顧客マスタ WHERE ID = '01234567';
UPDATE 顧客マスタ SET パスワード = 'abcdefgh' WHERE ID = '01234567';
上記例は基本的な構文となりますが、1つ目が顧客マスタからIDが「01234567」に該当するデータを返させる内容で、2つ目が顧客マスタ上でIDが「01234567」に該当するデータに対して、パスワードの情報を「abcdefgh」に書き換える内容になります。
Webサービスなどでユーザーが自身情報を画面に表示して参照する時、そしてパスワード変更を行う時を想定すればイメージしやすいと思います。
さて、次にSQLインジェクションの説明です。
WHERE ID = '〇〇〇〇'
の「〇〇〇〇」は、処理を行う上で対象となるデータを特定する条件となりますが、この値は入力フォームに入力した値を、プログラム上そのまま当てはめている場合があります。
では、例えばその入力値がこんな値だったらどうなるでしょう。
例1
■入力値
01234567' OR 'A' = 'A
■SQL
SELECT * FROM 顧客マスタ WHERE ID = '01234567' OR 'A' = 'A';
フォームに入力する値としてはとてもおかしな値ですが、入力値に「’」を含めることによって生成されるSQL文では前後にシングルクォーテーション「’」がついてSQLの構文として成り立ってしまいます。SQLの内容としては、IDが「01234567」であるまたは「A」が「A」である条件に該当するデータを全て返せになります。「A」が「A」である事って、当たり前で意味のない指定の様ですが、こうする事により常に条件が真となり顧客マスタ上のすべてのデータが返されてしまいます。
例2
■入力値
01234567'; UPDATE 顧客マスタ SET パスワード = 'abcdefgh' WHERE ID = ‘01234567
■SQL
SELECT * FROM 顧客マスタ WHERE ID = '01234567'; UPDATE 顧客マスタ SET パスワード = 'abcdefgh' WHERE ID = '01234567';
上記の例では終了記号「;」を入力値に含ませ、続けてDBを操作する構文を入れることによって自由にDBのデータ書き換えなどが出来てしまう可能性があります。
こういったSQLの命令を悪用して不正動作を発生させる手法をSQLインジェクションと呼びます。
(入力フォームなどでSQLの構文の一部を注入(インジェクション)するという意味です)
実際にこの仕組みが使われて顧客情報が漏洩したなどの過去の事例は多いです。
テスト実施時に考慮すべき点(SQLインジェクションを防ぐ)
では、SQLインジェクションを防ぐ為、テストの実施者として考慮する点を2点挙げます。
(開発観点では他にも色々ありますが、テストの実施観点として絞っています)
入力値のバリデーション処理は行なわれているか
ここで言うバリデーション処理とは、フォーム上で入力された値が仕様に沿った形式(文字数、文字のタイプ、文字列の形式など)となっているかプログラム側で確認し、外れている場合はエラーとして返す処理の事です。
(バリデーションテスト/妥当性確認試験とは、また言葉として別物なので注意)
SQLで使用される「’」といった記号は、SQLインジェクションの様な問題が発生しない様に入力フォーム上にて入力不可の文字として設計される事が多いです。機能テストとして、その設計内容通りに入力がエラーとなる事を確認する事はとても重要です。
特に検索キーとなるIDといった入力は、入力制限は多いと思います。
記号に対してエスケープ処理は行なわれているか
入力値としてSQL構文で特殊な意味を持つ「’」といった記号を許可していても、エスケープ処理を施していれば問題ありません。エスケープ処理とは、エスケープ文字を組み合わせる事によってプログラム構文上で使われる記号であっても、文字データとして扱われる処理の事です。
エスケープ文字は使用されているDBシステムによって違い、例えばMySQLであれば「\」がエスケープ文字になります。
SQL例
UPDATE 顧客マスタ SET 備考 = ' 使用端末 'iPhone 14' ' WHERE ID = '01234567';
という様な「iPhone 14」を「’」で囲んだ情報で更新したい場合、このままでは「iPhone 14」が「’」の囲みから外れてSQL構文の一部と見做され構文エラーとなってしまいますが、
UPDATE 顧客マスタ SET 備考 = ' 使用端末 \'iPhone 14\' ' WHERE ID = '01234567';
上記の様に「iPhone 14」前後の「’」の前に「\」を付けることによって、「 使用端末 ‘iPhone 14’ 」という文字列データとして扱われ更新されます。
エスケープ処理が施されていれば、「’」の様な記号が悪さしてSQLインジェクションに繋がる事はありません。ただこのあたりの確認はブラックボックステストにおいては入力を試して挙動を確認するしかないので、探索的テストでこういった構文を想像しながら怪しい入力を試してみると良いと思います。
私の経験則では、この辺りの対策がされているシステムは、設計時点からしっかりされてそもそも入力ではじかれます。1画面ピックアップして対策されていないシステムは、どの画面もされていない事が多いので探索的にどこか主要の1画面を確認するだけでも十分効果はあるんじゃないかと思います。
最後に
学生の頃はコミュニティサイト内のチャットでの発言にHTMLタグを組み込んでみたり、相手のCDROMドライブが勝手に開くみたいな悪戯を仕込んだりといった事が流行った記憶がありますが、昔はユーザーの入力に対して本当にどのWebサイトも無警戒だったと思います。
今回の様なSQLインジェクションに関わるような入力を探索的テストで確認していた時も、それでとんでもない挙動を起こさないかと半ば好奇心で試していましたが、情報漏洩やデータ改ざんに繋がるって怖いなと改めて思いました。
ただ、テストを行う上で好奇心を持つことは大事で、普段何気なくテストで確認している入力制限文字の確認なども、システム中のプログラムの仕組みを知るとなぜこういう仕様になっているのか?と理解が進み楽しくなるんじゃないでしょうか。
本記事を読んで頂き、少しでもテスト観点の幅が広がれば幸いです。ではまた。
<おすすめ記事・メディア>
JavaScriptの変数をSQL文に入れる方法とSQLインジェクションの回避
SQLのセキュリティ強化:インジェクション防止のためのベストプラクティス
ワードプレスでSQLインジェクションを防ぐPHPプログラミング
#SQLインジェクション