ふつーのプログラマです。主に企業内Webシステムの要件定義から保守まで何でもやってる、ふつーのプログラマです。

イノウーの憂鬱 (56) SQLインジェクション

»

 結局、ぼくとマリは土日も仕事をすることになった。職域接種受付フォームの機能は土曜日の午前中には完成し、一通りのテストを終えたのだが、経営管理部の大石部長から、事前に「ユーザ目線で」テストをしたい旨の申し入れがあったためだ。
 「で、どうして」マリは露骨に不機嫌な顔で斉木室長に食ってかかった。「テストが日曜日の夕方なんですか! 今からやればいいじゃないですか」
 「今日は外せない用事があるそうなんでね」斉木室長はなだめるように答えた。「明日も昼過ぎまで家庭の事情でできないって。私も頼んでみたんだけどね。どうしてもってことで」
 受付フォームの案内やとりまとめなどは総務課が主管部署なので矢野課長が責任者なのだが、エースシステム絡みの業務とあって、大石部長が慎重を期したらしい。エースシステムの人が使うわけでもないし、稼働するのは月曜日の朝から水曜日の午後までの短期間でしかないというのに、そこまで神経質にならなければならない理由がわからない。
 「どういう段取りでやるんですか」ぼくは諦めて訊いた。
 日曜日の16 時ぐらい――つまり明確な開始時刻は決まっていないということだ――に、大石部長他数人が会社や自宅のPC、スマートフォンなどから、実際に申し込みを行う。ユーザビリティや表示などをチェックし、修正点が発生した場合、即座に修正を行うために、ぼくとマリも待機していなければならない。また、テストが終わった後、申し込みデータをクリアする必要もある。
 「何も指摘事項がなければ、座ってるだけだよ。もちろん休日出勤扱いになるしね。うまくいけば、座ってるだけで手当がもらえるってわけ」
 そう聞かされても、たいして嬉しいとは感じなかった。だいたい、座っているだけだ、と言われて、実際に座っているだけだったことなどない。
 「あ、それからさ」斉木室長は付け加えた。「JV 準備室のメンバーも参加させることにしたよ。待ってる間、受付フォームの構造について説明してもらえると、実地での勉強になるからね」
 「......じゃあ、出勤した方がいいってことですね」
 斉木室長との通話を終えた後、ぼくは少し考えてからマリに言った。
 「修正対応なら一人で何とかなるし、まさかWebpack とかの説明をするわけはないから、マリちゃんは休んでいいよ」
 「何言ってんすか」マリの瞳には堅固な意志の光が宿っていた。「あたしも行きますよ。こういうのは若い人間から出るものですよ。先輩が仕事してるのに、あたしがダラダラやってるわけにはいかないですよ」
 「ぼくは、そういうのは気にしないけどね」
 「それに」マリはニヤッと笑った。「早く終われば、一緒に映画行けるじゃないですか」
 「......まあいいか。早く終わったら考えるよ」
 そんなわけで、ぼくとマリは翌日の日曜日、13 時にシステム開発室で顔を合わせた。この時間にしたのは、4 時間以上勤務しないと休日出勤にカウントされないからだ。朝から出社している斉木室長は何が忙しいのか、出たり入ったりしているようだ。ぼくたちの顔を見ると、「ああ、おつかれ」と言ったが、そのまま出ていってしまった。
 「エヴァのラスト回は18 時30 分からです」マリは持参したサンドイッチをパクつきながら言った。「それまでには終わらせましょう」
 「そうだね」
 終わらせる、と言っても、間に合うように会社を出られるかどうかは、テストを行う大石部長その他の人々にかかっているので、ぼくたちの努力ではどうにもならないのだが、そんなことを口にしても仕方がない。
 15 時を過ぎた頃から、JV 準備室のメンバーがTeams にログインし始めた。意外なことに、真っ先にログインしたのは伊牟田さんだった。人事課の自席からログインしているそうだ。プログラミング学習は免除されたはずなのに、とぼくとマリは顔を見合わせて驚いた。
 「ま、俺もさ」伊牟田さんは照れ笑いを浮かべながら言った。「足踏みばっかもしてらんねえからな」
 「急にやる気になったんですね」伊牟田さんが画面から消えると、マリが首を傾げた。「後がないから?」
 「なんだっていいよ。来る者は拒まず、で行こう」
 16 時1 分には一人を除いて、JV 準備室のメンバーは全員揃った。リモート参加も認められていたが、結局、全員が出社している。遅れているのは夏目課長だ。テストを行うはずの大石部長もまだ来ていないが、こちらは開始時間が定まっていないし、放置しておいても勝手にテストを行うだろうから、待っていても意味がない。ぼくは出勤してきたメンバーに、受付フォームの説明を開始することにした。
 せっかく、全員が会社に来ているのだから、ということで、説明は会議室で行うことにした。それぞれのPC を持って、十分に間隔を取った席に座ってもらう。Teams は画面の共有のみで使用し、説明そのものはリアルで行う方法だ。
 といっても、いきなり実装レベルの話をしても理解してもらえないことはわかりきっているので、最初はマリがHTML の簡単な説明をすることにしよう、と事前に決めていた。実際の画面とソースを比較できるので説明しやすいし、聞く方も理解しやすいからだ。
 「じゃ、始めます」マリは宣言し、作ったばかりの受付フォームを画面共有した。「これが今回の職域接種受付フォームです。スマホでの表示を見たい人は、ブラウザの幅をこんな感じで狭くしてもらって......」
 事前に練習をしてきたのか、マリは手際よく、フォームの説明を進めていった。業務三課、現在の営業三課にいた頃は、客先でのプレゼンは女子社員か若手社員の役目、というのが暗黙のルールだったそうで、両方の属性を持つマリは、一時期、毎日のように、様々な客先に駆り出されていたらしい。
 「やあ、おつかれさま」
 そう言いながら大石部長が会議室に入ってきたのは、20 分ほど経過した後だった。一人ではない。すぐ後ろに続いているのは夏目課長で、次に私服姿の見覚えのない中年男性、最後が斉木室長だった。中年男性に室内の視線が集中していることに気付くと、大石部長は振り返った。
 「こちらは今日のテストに同席してもらう浦西さんだ。えーと、夏目くんが頼んでくれたんだよな」
 「はい」夏目課長は頷いた。「浦西さんは、フリーランスでIT システムコンサルをされている方です。専門的な視線で受付フォームの検証をお願いするために、ご足労いただきました」
 浦西氏は小さく頭を下げた。他人への第一印象をあまり気にしない人のようだ。寝グセなのかファッションなのか、四方八方へ跳ねた長髪で、小さめのマスクからは無精髭がはみ出している。プチプラではなさそうなボタンダウンのシャツなのに、襟先はもちろん、上部のボタンはほとんど外れている。なぜか片方の袖だけまくり上げているのも変だ。意図的にやっているのかもしれないが、初顔合わせの場にふさわしい服装とは思えない。
 「では、私たちはこっちでやらせてもらうよ」大石部長は空いている席を指した。「何かあったら、声かけるから。それでいいかな」
 ぼくが頷くと、大石部長、夏目課長、浦西氏は会議室の隅の方に移動し、ノートPC やスマートフォンを出して、何やら会話しながらテストを開始した。斉木室長が隣に座ったので、ぼくは小声で訊いた。
 「なんですか、あの人は」
 「どうやら」斉木室長も小声で返した。「最初から、これが目的だったみたいだね。もちろん大石部長のことじゃないよ。夏目さんね。そもそも、このテストの言い出しっぺは大石部長じゃなくて、夏目さんだったらしいんだ」
 一体、何を考えてるのか、と感じた疑問の答えはすぐに明らかになった。
 「あー、なるほどですねえ」浦西氏の必要以上に大きな声が会議室に響き渡った。「いかにもって感じですわ、こりゃ」
 説明中だったマリが言葉を切って、大石部長たちが固まっている方を見つめた。JV 準備室のメンバーも同じ方に顔を向けた。
 「具体的にはどんなところがですか」
 嬉しそうに訊ねたのは、もちろん夏目課長だ。
 「この画面、もろにBootstrap のテンプレートそのまんまですわ。手抜きって言っちゃあ失礼ですけど、まあ手抜きですね。CSS フレームワークって、そのまんま使うもんじゃないんです。たとえばbtn-primary の色って、デフォルトだとこの青地に白のデザインなんですけど、ちょっとでも勉強したデザイナーなら、background-color とかborder とか変えるものなんですよ。自分なりにね」
 マリの目元が険悪状態に変化するのがわかったので、ぼくは急いで席を立つと隣に立った。気付いたマリが訴えかけるような視線をぶつけてきたので、ぼくは落ち着け、という意味をこめて肩に手を置いた。
 「気にしなくていいから」
 マリが戸惑ったように見上げてきたので、もう一度、肩を叩いておいて、ぼくは会議室の隅に向かった。浦西氏はちらりとぼくの方を見たが、構わずフォームの批判を続行した。
 「この家族分の入力エリアも、ちょっとムダですね。最大人数って4 人ですよね。追加ボタンで増やすんじゃなくて、最初から4 人分用意しときゃいいじゃないですか。ってか、ちょっと考えりゃ、その方がいいことぐらいわかりますよ」
 「なるほどね」夏目課長は腕を組んで頷いている。「パッと見だと普通にできてるようだけど、プロから見ると、いろいろ欠点が出てくるわけね」
 「そうなんですよ」浦西氏はノートPC のキーボードに指を走らせた。「まあ、典型的に動けばいいや的なフォームですね。社内SE さんが作ると、だいたい細かい部分がおろそかになるんですよ。試しにやってみましょうか。これって、まだテストなんですよね」
 その質問はぼくに向けられていた。ぼくは頷いた。
 「ってことは、たとえばデータぶっ壊れても大丈夫ってことですね」
 「......まあ、構いませんよ」できるものなら、という言葉は呑み込んだ。
 「オッケー」浦西氏は芝居がかって、指をパチンと鳴らした。「じゃ、お許しが出たところで」
 浦西氏は画面に向き直った。横から覗き込むと大石部長の社員ID でログイン済みの受付フォームが見えた。浦西氏はBack Space キーを押してログイン画面に戻ると、社員ID のテキストボックスに入力した。

 1' or '1' = '1';--

 そしてログインボタンにフォーカスを移すと、腕を高々と差し上げ、ぼくに意味ありげに笑いかけながら勢いよくスペースキーを叩いた。
 すぐにエラーメッセージがポップアップした。

56-m2.png

 「お、なるほど」一瞬固まった浦西氏は、すぐに余裕の表情を取り戻した。「なるほど。最小限の必須チェックぐらいは入れてるみたいですね。ま、こういうのは、required とか付けておけば、ボタン押す前に自動でメッセージ出してくれるんですけどね。じゃ、適当にパスワード入れてっと」
 浦西氏は適当にキーを二つ三つ叩くと、またログインボタンを押した。

56-m2.png

 「あー、なるほどなるほど」浦西氏はまた言った。「こういう基本的なところは入れてあるんですね。ネットワーク管理規程のルールじゃしょうがないですね。そりゃ入れますよね。このルールって何ですか」
 夏目課長が、8 文字以上、アルファベット、数字、記号のそれぞれから最低1 文字以上、というルールを教えると、浦西氏はまたキーを叩いた。
 「これでよしっと。じゃ、行きますよ」
 ログインボタンが押されると、フォームがサブミットされた証拠にブラウザタブの左側に、ビジーアイコンが一瞬だけ表示されたが、すぐに戻ってきた。画面には素っ気ないエラーメッセージが1 行。

 社員ID、またはパスワードが不正です

 針が落ちる音さえ聞こえそうな静寂が降りた。それを破ったのはシノッチの声だった。
 「あの、イノウーさん」シノッチは首を傾げながら言った。「さっきから何やってるんでしょうか?」
 「あれですか」ぼくはうんざりしながら答えた。「たぶん、SQL インジェクションという古典的な攻撃を試したんでしょうね。社員ID やパスワードがわからなくても、ログインできちゃうっていう脆弱性ですよ」
 「あ、そうなんですか。へー。でも、今のってログインできてないですよね」
 シノッチは批判するつもりではなかったのだろうが、浦西氏にしてみれば心臓を突き刺されたような気分だっただろう。夏目課長にさえ、冷たい視線を向けられていることに気付くと、エアコンの効いた室内だというのに、浦西氏の額には大粒の汗が浮かんだ。同情するつもりはないが、少しばかり気の毒に感じた。
 「なーるほどなるほど」浦西氏は必死の形相で挽回を図った。「今のメッセージもちょっと不親切ですよねえ。不正だったのが、社員ID だったのかパスワードだったのかがわかりませんからね。どっちが間違ってたのか、明示してあげるのが親切設計ってもんですわ」
 浦西氏は大きな笑い声を上げたが、同調者は皆無だった。その雰囲気を察したのか、慌てて取り繕うような言動を口にした。
 「ま、まあ、一応、ログインぐらいは初歩的な対策をしてるようですね。もうちょっと試してもいいですかね」
 夏目課長の顔には逡巡が浮かんでいた。何の意図があるのかわからないが、どうやらシステム開発室のスキルが低い、と主張するために、わざわざ部外者を呼んできたらしい。だが、自信ありげに行った最初の攻撃が失敗に終わったため、その評価に疑問符が付いてしまったようだ。
 「お願いします」夏目課長は頷いた。「続けてください」
 どうやら、ここで止める方が自分にとってのデメリットになる、と判断したようだ。
 「じゃ、すいませんが、もう一度ログインしてもらえますか」
 浦西氏の言葉は大石部長に向けられていたが、話しかけられた方は不審そうに見返したので、夏目課長が急いでログインした。受付フォーム画面が再表示される。いつの間にか、JV 準備室のメンバーやマリが、近寄ってきていて、密状態を形成していた。それに気付いた湊くんが気を利かせて申し出た。
 「こっちの液晶につなぎましょう。そうすればみんなに見えますから」
 間もなく、会議室に設置されている移動式の液晶TV にノートPC の映像が出力された。全員が適度な距離を保ったことを確認して、ぼくは浦西氏を促した。
 「どうぞ、続けてください。不具合や脆弱性があるなら、リリース前に知っておきたいので」
 浦西氏はノートPC に向き直り、住所までカーソルを進めた。単純な数字の固定桁数である郵便番号をスキップしたのは、バリデーションで対策済みだと考えてのことだろう。
 浦西氏が住所として入力したのは、こんな文字列だった。

 '; drop database syainMaster; --

 ぼくは頭の中で、SQL 文を組み立ててみた。

 insert into hoge values('';drop database syainMaster; --','......

 syainMaster というデータベースがあれば削除される、または存在しないデータベース名を指定したことで、何らかのエラーメッセージを誘発しようと考えたらしい。ぼくが黙って見ていると、浦西氏はその他の必須項目を入力し、登録確認ボタンを押した。<登録します。よろしいですか?>のポップアップが表示される。浦西氏は勢い込んでOK ボタンをクリックしたが、結果は、ぼくが想定した通りの画面に変わった。

 正常に登録されました。登録内容を変更する場合は、再度、登録を行うことができます。キャンセルする場合は、総務課に連絡してください。

 「今のも」湊くんが言った。「SQL イン何とかですか?」
 ぼくが頷くと、湊くんは「やっぱり失敗したんですね」と言ったが、それを聞いた浦西氏はやけになったように叫んだ。
 「まだです。このままDB 名を変えていけば、いつか当たるかもしれない。もう少しやらせてください」
 面倒になったぼくは、前に進み出て言った。
 「ムダですよ。SQL 文の変数部分は全部プレースホルダにしてますから」
 浦西氏は絶句し、ぼくの顔をまじまじと見つめた。社内SE 風情がプレースホルダを知ってるなんて、と驚愕しているようだ。
 「それに」ぼくは続けた。「さっきBootstrap のスタイルをデフォルトのまま使ってることを非難されてたようですけどね、それの何が悪いのかわかりませんね。長期間使用するシステムなら、デザインを統一することは大切だと思いますが、2、3 日しか使わないフォームにそこまでのデザインなど必要ではないでしょう」
 「......」
 「動けばいいや的とも言ってましたっけ。それのどこが悪いんですか。デザインにこだわって、リリースが遅れたらそっちの方が問題だとは思わないんですか」
 「そ、それでも」浦西氏は反論した。「フォームの作りが甘いのは確かです。そうじゃないですか」
 「たとえばどこですか」
 「さっき言ったように、エラーメッセージが不親切で......」
 「社員ID、またはパスワード、のメッセージですか」
 「そう、それです。どっちが間違ったのかわかるようにメッセージを変えるとか、違っている項目を赤く表示するとか、いろいろ......」
 「そんな"親切設計"をすると」ぼくは浦西氏の言葉を拝借して答えた。「実際の攻撃者に攻撃の手がかりを与えることになりますね。社員ID だけは合ってると知らせてあげて、わざわざ手間を省いて差し上げるのが、浦西さんの言う"親切設計"というわけですか?」
 「じゃあ、これは......」浦西氏はブラウザの戻るボタンで、登録画面に戻った。「これで戻れてしまっては二重登録になりますよ」
 「構いませんよ。さっきの完了メッセージを読まなかったんですか? 再登録可能なんですよ、このフォームは。最後の登録が有効になるだけです」
 「この家族の入力部分なんか」浦西氏は液晶TV を指した。「冗長じゃないですか。ボタンで追加していくなんて、わからない人にはわからないですよ」
 「あなたもわからなかったんですか?」ぼくは丁寧に訊いた。
 「いや、私はわかりましたけどね。一般のユーザにはわからない人だっていますよ」
 「あなたにわかったなら、一般の人だってわかると思いますね。そもそもこのフォームを利用するのは、うちの社員だけです。一般の人ではありません」
 浦西氏は黙り込んだ。そんな前提条件も聞かされていなかったらしい。恨みがましい目で夏目課長を睨んだが、夏目課長の方は真剣な表情でボールペンの先端を観察するのに忙しいようだった。
 「最大人数が4 人に決まってるんだから、最初から4 人分の入力エリアを用意しておいた方がわかりやすいじゃないですか」
 「本人だけとか」予想されていた難癖だったので、ぼくは即座に反論した。「家族一人だけの場合、余計なスクロールを強いることになりますね。むしろ間違えやすいんじゃないですか。スマホの狭い画面でスクロールしているうちに、今、家族2 に入れているのか、家族3 に入れているのかわからなくなる。追加ボタンで追加すれば、今、何人目を入力しているのかが明確になります。JavaScript でチェックする際も、家族1 から家族4 まで、それぞれ入力されているか、いないかをチェックする必要があります」
 「JavaScript ?」浦西氏はその単語に飛びついた。「JavaScript で必須チェックなんかをやってるんですか? それだと適当なツール使えば、不正なデータを送信できちゃいますね。これは大きな脆弱性に......」
 「理屈ではそうですが」ぼくは肩をすくめた。「このフォームに限って言えば、大した問題にはなりません。まず、ログインしないとこのフォームにたどり着けないし、仮にツールで不正なリクエストを送信したとしても、登録完了した時点で、社員のメールアドレス宛に登録内容を送信してます。第三者がなりすましで登録したところで、すぐに発覚するでしょう」
 「メールを見ないかもしれないでしょう」浦西氏は弱々しい声で反論した。「そしたら、第三者がなりすまして申し込んでしまうかもしれない。それで社員さんのふりをして接種を受けることだって......」
 「このフォームの手続きを理解されてますか?」
 「は?」
 「ここで入力された内容が、そのまま接種会場の予約になるわけじゃないんですよ。最終的にはエースシステム側で接種日を割り当てて、その結果はうちの総務に戻ってきます。チェックが入るから、全く社員とは関係ない氏名だったら、そこで弾かれますよ。そもそも接種会場では身分証明書が必要になるんですよ。どうやって、第三者が社員になりすますんですか」
 「......」
 浦西氏はぼくを憎々しげに睨んだが、すぐに視線を液晶TV に戻した。何とか自分の意見が通りそうなアラを探そうと必死にマウスを動かしている。そんな浦西氏を、夏目課長は、この役立たずが、と言わんばかりの冷たい目で見ていた。

 (続)

 この物語はフィクションです。実在する団体名、個人とは一切関係ありません。また、特定の技術や製品の優位性などを主張するものではありません。

Comment(16)

コメント

匿名

相変わらず変な業者に金ばらまいてるのか。
懲りないねぇ。

にゃんきち

イノウーくんにこの程度のレベルの相手で歯が立つ筈もなく…

匿名

これは流石に夏目氏、悪質な業務妨害じゃ…。
斉木さん、出番ですよー。

匿名

イントラ内で2〜3日しか使わない上に超短納期、再利用の予定なしとか最低限しか実装しないだろうに

匿名D

夏目女史、また同じようなことを繰り返しているのか。
伊牟田グチ氏のほうが潔いじゃん。

じぇいく

「浦西さんは、フリーランスでIT システムコンサルのされている方です。」
→「浦西さんは、フリーランスでIT システムのコンサルをされている方です。」
かな。

h1r0

イノウーや会社にとっても有意義な検証するなら、イニシアチブメンバー連れてこ~い

匿名

いまどきSQLインジェクションが通用するようなシステムが、まだあるのかなぁ。
某銀行にはありそうな予感がするけれども。

匿名

浦西は浦島太郎が元ネタかな?

匿名

こういうレベルのコンサルで金がもらえるものなら今すぐにでも転職したいw

リーベルG

じぇいくさん、ご指摘ありがとうございました。
「の」→「を」でした。

匿名

マリちゃん、ひんぬーのくせに強い

匿名

本人が主張するほど、肉が少ないわけでもないな (第33話より)

匿名

昨日のアクセスランキング第10位:
イノウーの憂鬱 (33) サンタクロースからの手紙

匿名

ミスズ先生かと思ったのに…

匿名

みんな、ひんぬーマリちゃん大好き。
私も大好き。

コメントを投稿する