メインコンテンツへスキップ
見出し画像

🔰ミカと教授の「ハッカーはどこから入る?」🔯🔯ミカと教授のサイバーセキュリテイ🖥️第2回

    第2回 SQLインジェクション――「お客様の入力欄から、なぜデータベースへ命令できるのか」

    ミカ「教授、前回のXSSでは、入力欄に入れた文字がブラウザへの命令になってしまうことがある、と勉強しました」
    教授「そうだったな」
    ミカ「今回はSQLインジェクションですね。でも、まだ納得できません」
    教授「何がだね」
    ミカ「ホームページの入力欄ですよ。お客様が名前や商品名を入力する場所でしょう。そこから、どうして奥にあるデータベースへ命令できるのですか」
    教授「よい疑問だ。まず一つ覚えておこう。『ここは名前を書く欄です』と理解しているのは、人間だけだ」
    ミカ「またコンピューターが空気を読まない話ですか」
    教授「サイバーセキュリティでは、空気を読まない機械と、空気を読みすぎる人間の両方に注意が必要なのだ」

    そもそもSQLとは何なのか

    ミカ「SQLインジェクションの前に、SQLとは何ですか」
    教授「データベースに対して、データを検索したり、追加したり、変更したりするための言語だ」
    ミカ「たとえばネットショップなら?」
    教授「商品を検索する、顧客情報を取得する、注文を記録する、在庫数を更新する。そうした処理の裏側でデータベースが使われている」
    ミカ「つまり、Webサイトの奥には大きな帳簿があるようなものですか」
    教授「よい例えだ。会計事務所なら顧客台帳、ネットショップなら商品台帳や注文台帳だ。そしてSQLは、その台帳係への指示書だと思えばよい」
    ミカ「『この顧客を探してください』『この注文を登録してください』と命令するわけですね」
    教授「そのとおりだ」

    検索欄からデータベースへ

    ミカ「では、ネットショップの商品検索を考えてみましょう」
    教授「利用者が検索欄へ『ギター』と入力したとする」
    ミカ「私なら検索します」
    教授「Webアプリケーションは、その『ギター』という文字を受け取り、データベースに『商品名にギターを含む商品を探してくれ』と問い合わせる」
    ミカ「普通ですね」
    教授「問題は、プログラムの作り方が悪く、利用者が入力した文字をそのままSQLの命令文へ組み込んでしまった場合だ」
    ミカ「そこでSQLインジェクションが登場するのですね」
    教授「そうだ。利用者が入力したものを単なる検索文字として扱うべきなのに、その一部をデータベースへの命令として解釈させてしまう」
    ミカ「XSSと似ています」
    教授「非常によく似ている。前回は、文章として扱うべき入力がブラウザへの命令になった。今回は、データとして扱うべき入力がデータベースへの命令になってしまう」

    インジェクションとは「注入」

    ミカ「そもそもインジェクションとは、どういう意味ですか」
    教授「英語の injection、つまり『注入』だ」
    ミカ「注射と同じですか」
    教授「語源的には同じ考え方だ。本来の命令文の中へ、外部から別の意味を持つ文字列を注入する」
    ミカ「名前欄へ名前ではなく、データベースが命令だと勘違いするものを入れる」
    教授「そういうことだ」
    ミカ「入力欄には『お名前を入力してください』と書いてあるのに」
    教授「攻撃者は親切な説明書を必ずしも守ってくれない」
    ミカ「利用規約を読んで『それならやめておこう』とはならないのですね」
    教授「攻撃者対策を利用者の良心に委ねるのは、玄関に『泥棒禁止』と貼って鍵を掛けないようなものだ」

    危険なのは「文字」と「命令」が混ざること

    ミカ「では、SQLインジェクションの本質は何でしょう」
    教授「データと命令を混ぜてしまうことだ」
    ミカ「もう少し説明してください」
    教授「プログラムには、あらかじめ決めたSQLの命令部分がある。そして利用者が入力した商品名や顧客番号などのデータ部分がある」
    ミカ「本来は別物ですね」
    教授「そうだ。ところが両者を単純に文字列として連結してしまうと、境界が曖昧になる」
    ミカ「コンピューターから見ると、どこまでがプログラマーの命令で、どこからがお客様の入力なのか分からなくなる」
    教授「そのとおりだ」
    ミカ「人間なら『これは商品名だから命令ではない』と判断しますが」
    教授「データベースは担当者の顔を見て判断してくれない。届いたSQLをSQLとして解釈するだけだ」

    ログイン画面も入口になる

    ミカ「商品検索だけの問題ですか」
    教授「いや。ログイン画面、問い合わせフォーム、会員検索、商品検索、URLのパラメータなど、データベースへ値を渡す場所なら注意が必要だ」
    ミカ「ログイン画面ということは、ユーザーIDとパスワードですね」
    教授「そうだ。通常なら、入力されたIDとパスワードに一致する利用者がいるかデータベースへ問い合わせる」
    ミカ「そこで入力値が命令として扱われたら?」
    教授「本来意図した認証条件が変化してしまう可能性がある」
    ミカ「つまり、『正しいパスワードですか』と聞いたつもりが、別の質問に書き換えられてしまう」
    教授「そう考えると分かりやすい」
    ミカ「受付係に『この人は予約していますか』と確認するはずだったのに、お客様自身が受付係への指示書を書き換えてしまう感じですね」
    教授「しかも受付係は非常に真面目なので、書かれた命令を忠実に実行する」

    成功すると何が起きるのか

    ミカ「SQLインジェクションが成功すると、どんな被害がありますか」
    教授「システムの作りやデータベースに与えられた権限によるが、重大な情報漏えいにつながることがある」
    ミカ「顧客情報ですか」
    教授「氏名、住所、メールアドレス、注文履歴など、本来見せるべきでない情報を取得される危険がある」
    ミカ「見るだけですか」
    教授「条件によっては、データの変更や削除につながる可能性もある」
    ミカ「怖いですね」
    教授「だから、SQLインジェクションは昔から知られている攻撃でありながら、今でもWebアプリケーション開発で非常に重要な対策項目なのだ」
    ミカ「古い攻撃だから安心、ではないのですね」
    教授「包丁も古い道具だが、今でも指は切れる」

    「怪しい文字を禁止すればよい」は危険

    ミカ「では、怪しい文字を入力できないようにすればよいのではありませんか」
    教授「それだけに頼るのは危険だ」
    ミカ「なぜですか」
    教授「名前や住所、商品名、文章にはさまざまな記号が正当に使われる。入力内容だけを見て、これは安全、これは攻撃、と完璧に判断するのは難しい」
    ミカ「では、攻撃文字のブラックリストを作る方法では不十分なのですね」
    教授「そうだ。もちろん入力値の妥当性確認は必要だ。しかし、SQLインジェクション対策の中心はそこではない」
    ミカ「何が中心ですか」
    教授「利用者の入力を、最初から最後まで『データ』として扱うことだ」

    パラメータ化された問い合わせ

    ミカ「具体的にはどうするのですか」
    教授「代表的なのが、パラメータ化されたクエリやプリペアドステートメントを利用する方法だ」
    ミカ「名前が難しくなりました」
    教授「考え方は簡単だ。データベースに最初から、『ここまでは命令です。そして、この場所には後からデータが入ります』と区別して渡す」
    ミカ「命令文を作った後で、データだけ別便で届けるのですか」
    教授「概念的にはそうだ」
    ミカ「すると、お客様がどんな文字を入力しても?」
    教授「その値は、命令の一部ではなくデータとして取り扱われる」
    ミカ「なるほど。受付係に、最初から『この封筒の中身は指示書ではなく資料です』と伝えておく感じですね」
    教授「非常によい」

    エスケープだけではだめなのか

    ミカ「XSSでは、表示するときに特殊な文字を安全な形へ変換しましたよね」
    教授「そうだったな」
    ミカ「SQLでも、危険そうな記号を変換すればよいのではありませんか」
    教授「適切なエスケープが必要になる場面はある。しかし、アプリケーションからデータベースへ値を渡す基本的な防御としては、パラメータ化された問い合わせを使うほうが堅牢だ」
    ミカ「文字を一つずつ警戒するより、最初から命令とデータの席を分ける」
    教授「そうだ。映画館で観客一人ずつに『あなたは俳優ではありませんね』と確認するより、舞台と客席を最初から分けておくほうがよい」

    データベースの権限も重要

    ミカ「パラメータ化すれば、それで完璧ですか」
    教授「セキュリティに『これ一つで完璧』という言葉はあまりない」
    ミカ「また教授が慎重になりました」
    教授「もう一つ重要なのが、データベースへ与える権限だ」
    ミカ「権限?」
    教授「Webアプリケーションが必要とする以上の強い権限を持っていれば、何か別の脆弱性が発生した場合の被害が大きくなる」
    ミカ「商品検索しか必要ないプログラムに、データベース全部を変更できる権限を与えない」
    教授「そのとおりだ。これを最小権限の原則という」
    ミカ「会社でも同じですね。アルバイト初日に金庫と社長室とサーバールームの鍵を全部渡したりしません」
    教授「その会社は、セキュリティ以前に人事制度を見直したほうがよい」

    エラー画面もしゃべりすぎてはいけない

    ミカ「ほかに注意することはありますか」
    教授「エラー処理も大切だ」
    ミカ「エラーが出るのは悪いことですか」
    教授「エラーそのものではない。利用者に必要以上の内部情報を表示することが問題だ」
    ミカ「データベース名や内部構造などですか」
    教授「そうだ。開発者には便利な詳しいエラー情報でも、一般利用者へそのまま表示すると、攻撃の手掛かりになることがある」
    ミカ「泥棒に『この金庫は右へ3回、左へ2回で途中まで開きました』と教えるようなものですね」
    教授「エラー画面は反省文を書く場所ではない。利用者には必要な情報だけを伝え、詳細は安全なログへ残す」

    XSSとSQLインジェクションの違い

    ミカ「前回のXSSと今回のSQLインジェクションを整理したいです」
    教授「では、ミカが説明してみなさい」
    ミカ「XSSは、利用者から受け取った入力が、Webページに表示されるときにブラウザへの命令として解釈されてしまう問題」
    教授「よろしい」
    ミカ「SQLインジェクションは、利用者から受け取った入力が、データベースへ問い合わせるときにSQLの命令として解釈されてしまう問題」
    教授「そのとおり」
    ミカ「攻撃される場所が違うのですね」
    教授「そうだ。しかし根っこには共通した問題がある」
    ミカ「データと命令を混ぜるなですね」
    教授「満点だ」

    さらに先にはOSもある

    ミカ「すると、同じ考え方で別の攻撃もありそうですね」
    教授「ある」
    ミカ「まさか……」
    教授「Webアプリケーションが外部入力を使ってOSへ命令を渡す場合にも、命令とデータの境界が壊れれば危険になる」
    ミカ「それがコマンドインジェクションですか」
    教授「そうだ」
    ミカ「ブラウザ、データベース、OS。だんだん奥へ進んでいきますね」
    教授「シリーズ名を思い出してみなさい」
    ミカ「『ハッカーはどこから入る?』」
    教授「入口は目の前の入力欄でも、その先に何がつながっているかによって被害は変わるのだ」

    入力欄はただの四角い箱ではない

    ミカ「普通にWebサイトを使っていると、入力欄なんてただの白い四角にしか見えません」
    教授「しかしプログラマーは、その四角の向こう側を見る必要がある」
    ミカ「この入力値は、どこへ行くのか」
    教授「ブラウザへ表示するのか、データベースへ渡すのか、ファイル名に使うのか、OSへ渡すのか。それによって必要な防御が変わる」
    ミカ「入力した瞬間ではなく、その入力をどこで使うかが重要なのですね」
    教授「非常に重要だ。入力値は入口で一度確認して終わりではない。使う場所に応じて安全に扱う必要がある」

    プログラマーが覚えておきたい基本

    ミカ「SQLインジェクション対策を、プログラマー向けに短くまとめてください」
    教授「では五つにしよう」
    ・SQL文と利用者の入力値を文字列連結で安易に組み立てない
    ・パラメータ化されたクエリやプリペアドステートメントを利用する
    ・入力値が想定した形式かを確認する
    ・データベースには必要最小限の権限だけを与える
    ・内部構造が分かる詳細なエラー情報を一般利用者へ表示しない
    ミカ「『怪しい入力を見破る』より、『怪しい入力でも命令にならない設計にする』ことのほうが重要ですね」
    教授「まさにそこだ」

    攻撃者より賢くなる必要はない

    ミカ「セキュリティを勉強していると、攻撃者より賢くならなければ守れない気がしてきます」
    教授「そんなことはない」
    ミカ「本当ですか」
    教授「攻撃者が何を入力するかを全部予想する必要はない。こちらが、入力をデータとして安全に扱う設計をすればよい」
    ミカ「攻撃者との知恵比べをしない」
    教授「そうだ。玄関の前で泥棒とクイズ大会をするより、良い鍵を付けたほうがよい」

    今日の結論

    ミカ「では、SQLインジェクションを一言で説明すると?」
    教授「利用者が入力したデータを、データベースが命令として解釈してしまうことで起きる攻撃だ」
    ミカ「防御の基本は?」
    教授「命令とデータを分離すること」
    ミカ「XSSでも似た話をしましたね」
    教授「セキュリティでは、何度も同じ原則に戻ってくる。コンピューターは命令に忠実だからこそ、何を命令として渡すのかをプログラマーが厳密に管理しなければならない」
    ミカ「コンピューターが悪いわけではないのですね」
    教授「そうだ。渡された命令を真面目に実行しているだけだ」
    ミカ「では、一番危険なのは?」
    教授「入力欄を見て、『ただの文字だから大丈夫』と思っているプログラマーかもしれないな」
    ミカ「白い四角い箱が、急に怖く見えてきました」
    教授「怖がる必要はない。入口の向こうに何があるかを知れば、守り方も見えてくる」

    次回予告

    第3回 CSRF――「本人がログインしているのに、なぜ他人の命令を実行してしまうのか」

    ミカ「次は入力欄ではないのですか」
    教授「次は、もっと厄介だ。攻撃者ではなく、正規の利用者本人に操作させる」
    ミカ「本人が攻撃に参加するのですか?」
    教授「本人は参加したつもりがない。それがCSRFの面白くて恐ろしいところだ」
    ミカ「また眠れなくなりそうです」
    教授「安心しなさい。仕組みを知るほど、眠れるようになる」

    あなたへのおすすめ