はじめに
こんにちは!
株式会社ユーザベース BtoB SaaS Product Team(以下 Product Team)の山室・利根です。
ユーザベースの Product Team には、全社のセキュリティを担うチームとは別に、プロダクトセキュリティの底上げを担うセキュリティチーム、通称 Blue Team というチームがあります。
私たちはそのチームの一員として、日頃の開発業務に加えてユーザベースのプロダクトのセキュリティを横断的に向上するための活動を行なっています。
現在、 Blue Team の取り組みのひとつとして、脆弱性のリスクや対策方法について継続的に記事にまとめ、Product Team 内の各開発チームで読み合わせを行なってもらう施策を実施しています。
チーム内でセキュリティについて詳しい人が知見を共有しながら読み合わせを行うことで、チーム内のコミュニケーションの促進を図ったり、プロダクトへ反映するための具体的な方法について議論してもらいたい、という狙いがあります。
また、Product Team で行なっている活動の様子を社外の方に紹介する一環として、それらの記事をテックブログにも掲載しています。
このテックブログが ユーザベースに興味を持っていただくきっかけになればと思っています!
前回の記事はこちら!
第 2 回目である今回は、SQL インジェクション の脆弱性について取り上げます!
SQL インジェクションとは?
概要
データベースと連携するアプリケーションでは、ユーザーの入力をもとに SQL 文を生成することがあります。
SQL インジェクションは、この入力の機能を悪用して本来の意図とは異なる SQL 文を生成・実行させることを意味し、SQL インジェクションが発生する可能性がある状態を「SQL インジェクションの脆弱性」、この脆弱性を突く攻撃を「SQL インジェクション攻撃」といいます。
リスク
SQL インジェクションでは SQL で実行できるあらゆる操作が行われてしまう可能性があるため、次のような深刻な被害をもたらすリスクがあります。
個人情報や機密情報の漏洩
Web サイトの改竄やパスワードの変更
不正なデータ登録によるマルウェアの拡散
データの削除やデータベースの破壊
不正ログイン
システムの乗っ取りや踏み台としての悪用
また、これらの被害によってユーザーの信頼を大きく損ねてしまったり、損害賠償を請求されることになってしまう可能性もあります。
発生件数
IPA の資料によると、IPA での届出受付開始から 2014 年第 4 四半期の間に届出があった Web サイトの脆弱性のうち、約 11 %が SQL インジェクションに関するものとなっており、これは他の脆弱性と比べると大きな割合を占めています。
最近でも、SQL インジェクション攻撃によって大きな被害を受けたケースの報告が度々あがっています。
2022 年 6 月 マーケティング・リサーチ企業が運営する Web サイトへの攻撃により、約 10 万件の個人情報が漏洩
2022 年 5 月 総合資格取得支援サイトへの攻撃により、約 30 万件のメールアドレスの漏洩やデータの改竄などが発生
2022 年 2 月 決済代行会社のアプリケーションに対する攻撃によって、約 240 万件のクレジットカード情報などが流出
また、サイバーセキュリティサービスを展開する株式会社サイバーセキュリティクラウドの直近の調査によると、2023 年 1 月 1 日~ 3 月 31 日の期間において、同社が提供するセキュリティサービスでの 1 ホストあたりの SQL インジェクション攻撃の検知数が前年同期比で +150 %(485 件 → 1208 件)と、急激に増加していることが明らかになっています。
このように、SQL インジェクションは極めて深刻な被害をもたらす脆弱性であり、近年攻撃件数も増えていることから、きちんと対策を実施して脆弱性を生み出さないことが非常に重要です。
攻撃方法
SQL インジェクション攻撃が一体どのようにして行われるのか、本をタイトルで検索できるアプリケーションを例に説明します。
このアプリケーションでは、検索欄に入力されたタイトルを SQL 文の検索条件に埋め込んでデータベースからデータを取得します。
例えば、検索欄に リーダブルコード
と入力して検索を実行すると、以下の SQL 文が発行されます。
SELECT * FROM book WHERE title = 'リーダブルコード';
もし、このアプリケーションに SQL インジェクションの脆弱性がある場合、検索欄に ‘; DELETE FROM book;
と入力すると、以下のような SQL 文が発行されることになります。
SELECT * FROM book WHERE title = ''; DELETE FROM book;
その結果、すべての本のデータが削除されることになってしまいます。
SQL インジェクション攻撃では、このように不正な入力で意図しない SQL 文を実行させることによって攻撃が行われます。
対策
続いて、SQL インジェクション攻撃への対策方法を説明します。
対策方法には根本的なものと保険的なものがありますが、まずは根本的な対策を実施し、SQL インジェクションの脆弱性を発生させないようにしましょう。
根本的な対策
攻撃方法のセクションで説明したように、SQL インジェクションは不正な入力によって意図しない SQL 文が生成され、それが実行されてしまうことによって攻撃が成立する脆弱性です。
したがって、入力によって不正な SQL 文が生成されないようにすることが根本的な対策となります。
プレースホルダの利用
プレースホルダとは、SQL 文の中に変数を埋め込む場所を示す記号を置いておき、あとでその場所に実際の値を機械的な処理で割り当てる仕組みです。
以下は、JDBC でプレースホルダを利用する例になります。
Connection conn = DriverManager.getConnection(url, user, password); String sql = "SELECT * FROM book WHERE title = ?"; PreparedStatement pstmt = conn.prepareStatement(sql); pstmt.setString(1, title); ResultSet rs = pstmt.executeQuery();
この例では、SQL 文で実際の値を埋め込む場所に ?
を置き、その後の処理で ?
の部分に変数 title
を割り当てています。
プレースホルダに実際の値を割り当てる処理を「バインド」と呼びます。
バインドの方式により、プレースホルダには「静的プレースホルダ」と「動的プレースホルダ」の2種類があります。
静的プレースホルダ
静的プレースホルダでは、データベース側でバインドが行われます。
まず、アプリケーションからデータベースにプレースホルダを含む SQL 文が送られます。
送られてきた SQL 文はデータベースで事前にコンパイルが行われ、この時点で SQL 文が確定します。
そのため、割り当てる値によって SQL 文が変更される可能性が一切なくなります。
その後、プレースホルダに割り当てる値がアプリケーションから送られ、データベースはその値を確定した SQL 文のプレースホルダ部分にバインドすることで実際に実行する SQL 文を生成し、実行します。
動的プレースホルダ
動的プレースホルダでは、アプリケーション側のライブラリやドライバでバインドが行われます。
アプリケーションは、入力で受け取った値をプレースホルダを含む SQL 文にバインドして実際に実行する SQL 文を生成し、それをデータベースに渡して実行します。
バインドの際、割り当てる値に対してライブラリが適切な処理を行うため、SQL インジェクションは発生しません。
どちらのプレースホルダの方法を利用する場合でも SQL インジェクションの脆弱性を解消することができますが、以下の理由から静的プレースホルダのほうが優れています。
- 静的プレースホルダでは、SQL 文が事前にコンパイルされ確定するので、原理的に SQL インジェクションの脆弱性が生じない。
- 動的プレースホルダでは、ライブラリやドライバで不適切な実装が行われていた場合に SQL インジェクション攻撃を許してしまう可能性がある。
そのため、可能な限り静的プレースホルダを利用することが推奨されます。
JDBC(MySQL Connector/J )で MySQL を利用する場合、以下のようにデータベースとの接続時のURLで useServerPrepStmts プロパティを true にセットすることで、静的プレースホルダを利用することができます。
Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/uzabase?useServerPrepStmts=true", "user", "password");
現在の最新バージョン(8.2.0)ではデフォルトが動的プレースホルダであるため、このプロパティを設定しない、もしくは false にセットすることで動的プレースホルダが選択されます。
データベースやライブラリによっては静的プレースホルダがサポートされていない場合があるので、事前に調べておくと良いでしょう。
エスケープ処理
SQL において、シングルクォート「’」は文字列リテラルを表現するために利用される特別な記号です。
シングルクォートに囲まれた範囲が文字列リテラルとして認識されるため、文字列リテラルの中にシングルクォートを含めたい場合はシングルクォートを重ねる必要があります。
例えば、「O’Reilly」という文字列にエスケープ処理を行い文字列リテラルにすると「’O’’Reilly’」となります。
このように、入力値を適切なリテラルに変換する処理のことをエスケープ処理といいます。
エスケープ処理が適切に行われている場合、もし検索欄に ‘; DELETE FROM book;
と入力されたとしても、実際に生成される SQL 文は以下のようになるため、SQL インジェクション攻撃が成功することはありません。
SELECT * FROM book WHERE title = '''; DELETE FROM book';
ただし、エスケープ処理が適切に行われているかどうかは開発者に委ねられるため、エスケープ漏れが発生する可能性があります。
また、データベースの種類や設定によってエスケープしなければならない文字が異なるため、それぞれに合わせた適切な処理を行う必要があります。
保険的な対策
入力値の制限
入力できる値に制限を設けることで、SQL インジェクション攻撃への対策になる場合があります。
例えば、電話番号の入力欄の場合、数字しか入力できないように制限することで、文字列による不正な入力を行うことができなくなります。
適切なデータベース権限の設定
データベースでは、データベースを利用するアカウントが実行できる操作を細かく設定することができます。
アプリケーションがデータベースを操作する際に利用するアカウントに適切な権限を設定することで、不正な SQL 文を実行できないようにすることができます。
詳細なエラーメッセージの非表示
エラーメッセージにデータベースの種類やテーブル名、エラーの原因やエラーを起こした SQL 文などの情報が含まれていると、SQL インジェクション攻撃に有用な手がかりを与えてしまうことになります。
また、攻撃の結果を知るための情報源として悪用される場合もあります。
そのため、発生したエラーをアプリケーションで適切にハンドリングし、データベースに関連するエラーメッセージをブラウザで表示しないようにします。
WAF の導入
WAF(Web Application Firewall)は、クライアントとサーバの間に設置することで、サイバー攻撃から Web アプリケーションを守るためのセキュリティツールです。
仕組みとしては、クライアントからサーバに送られてくるリクエストを解析・検査し、不正な内容が含まれている場合はそのリクエストをブロックすることで、Web アプリケーションを攻撃から守ります。
そのため、SQL インジェクションだけでなく、XSS やブルートフォース攻撃、ディレクトリトラバーサルなど様々な脆弱性に対しても有効です。
まとめ
今回は SQL インジェクションについて取り上げました!
SQL インジェクションは個人情報の漏洩やデータの改竄、システムの停止など重大なインシデントに繋がる非常に危険な脆弱性です。
SQL インジェクション攻撃の件数は年々増えており、実際に個人情報やクレジットカード情報の漏洩などの被害に遭ったケースも度々発生しています。
今回ご紹介した対策方法を適切に実施し、SQL インジェクションの脆弱性を発生させないようにしましょう!
We are Hiring!!
Uzabase の Product Team では、積極的に採用を行なっています!
私たちの会社やプロダクト、取り組みなどが少しでも気になった方は、ぜひ以下のリンクからチェックしてみてください!
http://uzabase.com/jp/careers/