セキュリティ関連で調べることがあったので、記憶にとどめておくために文字として調べたことをまとめていこうと思います。
今回はIPAのサイトにあった、ウェブアプリケーションの脆弱性について、その中の一つである「SQLインジェクション」について書きます。
目次
SQLインジェクションとは
SQLインジェクションとは、Structured Query Language Injectionの略で、データベースへの命令文であるSQL文に動作してしまうコードを埋め込む(inject)ことでデータベースの不正利用を招くなどのセキュリティ問題のことを言います。
基本的な攻撃手法としては、データベースへの命令文を構成する入力値を送信することにより、データベースに対して削除、改ざん、データ取得するなどを行います。
発生しうる脅威
IPAのサイトによると、発生しうる脅威は以下の通りになります。
- データベースに蓄積された非公開情報の閲覧
・個人情報の漏洩 - データベースに蓄積された情報の改ざん、消去
・ウェブページの改ざん
・パスワード変更
・システム停止 - 認証回避による不正ログイン
・ログインした利用者に許可されているすべての操作を不正に行われる - ストアドプロシージャなどを利用したOSコマンドの実行
・システムの乗っ取り
・他への攻撃の踏み台としての悪用
SQLインジェクションの例
下記のSQLは、パラメータ(id, pw)を受け取り、account_table(テーブル)からパラメータで検索した結果、該当する場合にログインを許可するコードです。
-- パラメータ(id, pw)を受け取る
-- account_table(テーブル)からパラメータで検索
-- 該当するレコードを返す
SELECT id FROM account_table WHERE id='ユーザID' AND pw='パスワード'
この場合は、ユーザIDのところにユーザーの入力値が入りますが、ユーザーがSQLインジェクション攻撃の内容(ユーザidに「’ OR 1=1—」)を入力した場合、下記のようになります。
-- ユーザーIDに「' OR 1=1--」を入力した場合
SELECT id FROM account_table WHERE id='' OR 1=1--' AND pw=''
ユーザid内に「’ OR 1=1—」を入力すると、idが「id=” OR 1=1」となり必ず真になるようになっており、それ以降のコードは「—」によってコメントとして無視されるため、本来ログインが出来ない場合でもログインが可能になります。
対策方法
対策方法は以下の通りです。
言語の選択による対策
プログラム言語の中には、ロジックの中にソースコードレベルでSQLを記述できる「言語に統合されたクエリ」をサポートしているものがあります。 これらを使うとSQL文のソースコードを文字列データとして扱わなくてもよく、悪意の入力パラメータの影響を回避できます。
例:「.NET LINQ」、「PL/SQL」、「PL/pgSQL」
この対策は有効なSQL注入対策にはなりますが、このような言語処理系を採用することができない場合も多いため、そのような場合は別途対策が必要になります。
コーディングによる対策
コーディングによる対策は、主に以下の3つが挙げられます。
- 入力値チェックの徹底
- プリペアドステートメントの使用
- 文脈に応じた特殊記号対策
それぞれを以下にまとめる。
1. 入力値チェックの徹底
入力値チェックは、入力データを仕様によって絞り込める場合に行います。
入力値チェックの徹底は、SQLインジェクション対策には一定の効果をもちます。入力データの要件について、文字種、桁数、取り得る値のリストなどの範囲を仕様として絞り込める場合、もれなく入力チェックを行うことは有効となります。
ただし、ユーザ側がJavaScriptを無効にしている場合などがあるため、入力値チェックはWebサーバ側で行う必要があります。
データベースで扱う値に対して文字種、文字数などの条件を明確にし、ブラウザから渡された値が、入力値として正しい形式であるかどうかをチェックします。条件を細かく設定し、厳密にチェックすることで、SQLインジェクションを避けることができます。
2. プリペアドステートメントの使用
これは、入力データの部分を埋め込んで文字列を組み立てる際に、文字列連結演算を使用せずに、プリペアドステートメントを使用して、SQLを組み立てる方法です。
プリペアドステートメントは、プレースホルダと値埋め込みAPIから成る解析済みのSQL文であり、コード中のプレースホルダ(予約場所)に入力データを割り当てる機能(バインドメカニズム)のことです。
プリペアドステートメントを利用すると、入力データは、数値定数や文字列定数として組み込まれるため、特殊記号が含まれていた場合でも、それはただの文字として扱われることになります。
3. 文脈に応じた特殊記号対策
これは、SQLインジェクションの例で挙げたような、元のSQLの命令文を変化させてしまう特殊記号や文字の働きに対して文字列の無毒化(サニタイジング)を行うことで対処する方法です。
エスケープの例を以下に示します。
記号名 | 元の記号 | 置換後の記号 |
---|---|---|
シングルクォーテーション | ’ | ”(2個) |
バックスラッシュ | ¥ | ¥¥ |
SQLの文法ではシングルクォートを二つにすることで、文字列定数中で一つのシングルクォートそのものを表すという約束になっているため、シングルクォートを無毒化できます。
また、¥(バックスラッシュ)が使用できるRDBMS(リレーショナルデータベース)の場合、上記の表のようなのエスケープ(¥→¥¥)を行う必要があります。
¥をエスケープしない場合、¥の後に「‘」と入力することで、2個にエスケープしたシングルクォートの一つが中和され、もう一つの特殊記号の働きが残ってしまいます。
また、ほかの対策として、文字種の厳密な制限があります。 SQLの数値リテラル以外の文法要素を形成するような記号や文字を含む入力値を受理しないようにします。数値に関する文字種の制約の仕様は、目的に応じて決めます。 入力値に所定の物以外の文字や記号が含まれている場合、その1項目、もしくは、この時の入力全体を受理しないようにアプリケーションの動きを制限します。
これらの詳細は以下のサイトを参照してください。
IPA ISEC セキュア・プログラミング講座:Webアプリケーション編 第6章 入力・注入対策:SQL注入攻撃: #1 実装における対策
WAFを導入する
WAFはWeb Application Firewallの略で、ウェブ関連のファイアウォールのことです。
WAFは、ファイヤウォールやIPS/DPSでは防げない、Webアプリケーションの脆弱性を悪用したサイバー攻撃を防ぎます。これは、SQLインジェクション以外の攻撃にも対応しているため、より安全にWebサイトを運用できます。
また、クラウド型WAFは初期・運用コストが低いため、手軽に試すことができるメリットもあります。
SQLインジェクションの被害例
被害例としては主にネットショッピングサイトなどが挙げられます。
例としては釣りビジョンなどのショッピングサイトがあります。この例ではクレジットカードを含まない個人情報が約6万件流出しました。
SQLインジェクションでは、ただでさえ被害が甚大である上に、データベースによってはクレジットカードを保持している場合があるため、対策は必須となります。
参照サイト
安全なウェブサイトの作り方:IPA 独立行政法人 情報処理推進機構
安全なウェブサイトの作り方 - 1.1 SQLインジェクション:IPA 独立行政法人 情報処理推進機構
SQLインジェクション | 用語集 | CyberSecurityTIMES
IPA ISEC セキュア・プログラミング講座:Webアプリケーション編 第6章 入力・注入対策:SQL注入攻撃: #1 実装における対策