LoginSignup
11
13

More than 5 years have passed since last update.

【社内勉強会】iBatisの`$`と`#`(2017/03/15)

Last updated at Posted at 2017-03-14
1 / 27

0. はじめに


前提知識

  • iBatis2の基本的な使い方
  • Javaの構文

伝えたいこと

  • iBatisの$#の違い
  • プリペアドステートメント
  • SQLインジェクション

目次

  1. iBatisの概要
  2. JDBCでデータベースにアクセス
  3. iBatisの#$
  4. 付録

1. iBatisの概要


iBatisとは?

O/Rマッピングツールの1つ。
Javaからデータベースに簡単にアクセスできる。
初版は2001年。


iBatisのサンプルコード

SQL文をXMLファイルに定義して、Javaから分離。
SELECT文の結果が、resultClassで指定したクラスのオブジェクトに格納される。
#value#はJavaで指定されたパラメータ。

<select id="getProduct"
    parameterClass="java.lang.Long"
    resultClass="com.example.Product">
        select
            PRD_ID      as id,
            PRD_DESCRIPTION as description
        from 
            PRODUCT
        where 
            PRD_ID = #value#
</select>
Product resultProduct = sqlMapClient.queryForObject("getProduct", 123);

Wikipedia より引用


O/Rマッピングとは?

Object / Relational Mappingの略称。
オブジェクト指向言語(Javaなど)とリレーショナルデータベースの橋渡しとなるツール。

  • オブジェクト指向設計: データモデルを現実世界のモデルに即したものとして定義
  • リレーショナルデータベース設計: リレーショナルデータベースの検索や登録更新処理に最適なモデルを定義

設計思想の違いによる「インピーダンスミスマッチ」を解消するために生まれた。

O/Rマッピングの役割とメリット より引用


JDBCとは?

Java Database Connectivityの略。
Java とリレーショナルデータベースの接続のためのAPI(java.sql, javax.sqlパッケージ)。
iBatisの下位層に該当する。


Javaからデータベースにアクセスする順番

  1. Plain Java(私たちが記述するコード)
  2. iBatis
  3. JDBC
  4. データベース

iBatisの構成図.png


2. JDBCでデータベースにアクセス


環境構築


[TRY]JDBCで単純なSQL文を実行しよう

String sql = "SELECT id, name, population FROM area " +
                "WHERE name = '" + areaName +  "'";

Statement statement = connection.createStatement();
//SQLを実行
ResultSet rs = statement.executeQuery(sql);
//SELECT結果を1行ごとに出力
while (rs.next()) {
    int id = rs.getInt("id");
    String name  = rs.getString("name");
    int population = rs.getInt("population");
    System.out.println(id + "," + name + "," + population);
}

iBatisと比較したJDBCの面倒なこと

  • SQL文をJavaで定義していて、文字列処理が必要。
  • SELECT結果の取り出し処理が必要。

この面倒なことを省けるのが、O/Rマッピングツールのメリット。


[TRY] 変数areaNameにいろんな値を代入してみよう

String areaName = "' OR TRUE --";
String sql = "SELECT id, name, population FROM area " +
                "WHERE name = '" + areaName +  "'";
  • 'OR TRUEでWHERE句の条件を無効
  • --で、末尾のシングルクォートを無効

実行すると、全行の結果が取得できる。
もしこのテーブルがユーザテーブルなら、個人情報漏洩につながる!!
SQLインジェクションに対する脆弱性あり!!


SQLインジェクション

アプリケーションが想定しないSQL文を実行させることにより、データベースシステムを不正に操作する攻撃方法のこと。

Wikipedia より引用


SQLインジェクションの対策方法

  1. 入力値チェックの徹底
  2. 特殊記号のエスケープ
  3. プリペアドステートメントの使用

SQL注入 より引用

1と2は漏れが発生する可能性があるので、3がベスト。


プリペアドステートメントとは?

プリペアドステートメントは、プレースホルダと値埋め込みAPIから成る解析済みのSQL文であり、コード中のプレースホルダ(予約場所)に入力データを割り当てる機能(バインドメカニズム)である。

SQL注入 より引用


[Try] プリペアドステートメントでSQLを実行しよう

String sql = "SELECT id, name, population FROM area " +
                "WHERE name = ? "; //バインドしたいところに"?"を記述

PreparedStatement statement = connection.prepareStatement(sql);
//バインドする
statement.setString(1, areaName);
// SQL実行
ResultSet rs = statement.executeQuery();

[Try] プリペアドステートメントでSQLインジェクションを実行してみよう

String areaName = "' OR TRUE --";

実行されたであろうSQL文(予想)

SELECT id, name, population FROM area 
WHERE name = ''' OR TRUE --'

取得結果は0件。


3. iBatisの'$'と'#'


iBatisでパラメータをSQLに渡す方法

#または$でパラメータを渡せる

<select id="getSample1"
  parameterClass="java.lang.String"
  resultClass="java.util.HashMap">
  SELECT * FROM
  WHERE area = #value#
</select>

<select id="getSample2"
  parameterClass="java.lang.String"
  resultClass="java.util.HashMap">
  SELECT * FROM
  WHERE area = $value$
</select>

iBatisの$#の違い

パラメータを渡す方法に違いがある。

  • # : プリペアドステートメントでパラメータを渡す
  • $ : 文字列処理としてパラメータを渡す

SQLインジェクション対策として、特に理由がない限り#を使うべき。
iBatisのタグを駆使すれば、大抵のSQL文は#で対応できる。

iBatis2 を参考


iBatisの$を使ってもよいとき

  • IN句で大量のパラメータ(1000個以上)を渡すとき。多すぎるとエラーになる。(何個からエラーかは不明)
  • テーブル名をパラメータとして渡したい

SELECT * FROM #tablename# <!-- エラー -->
SELECT * FROM $tablename$ <!-- OK -->

4.付録


参考サイト

TECHSCORE

O/Rマッピングツールに対する誤解をときたい

O/Rマッパーによるトラブルを未然に防ぐ

11
13
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
11
13