SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

Javaセキュアコーディング入門

Javaの参照型変数とセキュリティ

Javaセキュアコーディング入門(7)

  • このエントリーをはてなブックマークに追加

 Javaには2種類の型、プリミティブ型と参照型があります。みなさんはこれらの違いをきちんと理解して使っているでしょうか? とくに参照型の取り扱いは、気を付けないと脆弱性を作り込むもとになってしまいます。今回は参照型の取り扱いについて見てみましょう。

  • このエントリーをはてなブックマークに追加

Javaにおける参照型

 一通りJavaプログラミングを経験した方であれば、プリミティブ型と参照型についてはご存じでしょう。Javaは強い型付け言語であることをうたっており、全ての変数や式は、何らかの型を持つことになっています。そしてJavaにおける型は、プリミティブ型と参照型の2種類に分類されます(※null型というのもありますが、ここでは省略します)。

  • プリミティブ型:boolean型、char型、数値型(byte、short、int、long、float、double)
  • 参照型:配列型、クラス型、インタフェース型

 プリミティブ型のデータはビット幅やその取り得る値の範囲が具体的に規定されています。では、参照型はどのように規定されているでしょうか。『Java言語仕様』の第4章「型、値、変数」から引用します。

参照型の値は, オブジェクトへの参照となる。

オブジェクトとは, クラス型から動的に生成されるインスタンス、あるいは動的に作成される配列のことである。

 CやC++を知っている方なら「ああポインタのことね」と思うことでしょう。実際、別のところには次のように書かれています。

参照値(しばしば単に参照(reference)とも呼ばれる)は、こういったオブジェクトへのポインタ(pointer)や, どのオブジェクトも参照しない特殊なnull参照となる。

 ガベージコレクタの仕組みを考えると、 Javaの参照型はC/C++のポインタが2段に組み合わさったものと考えるのがよさそうです。それはともかく、プリミティブ型のデータと参照型のデータは扱いが異なるという点を理解しておくことが重要です。

 プリミティブ型変数には、プリミティブ型の値自身が収められており、代入などの操作を行うと、値がコピーされていきます。これに対して、参照型変数に収められているのは参照なので、代入操作を行うとオブジェクト自身がコピーされるわけではなく、参照(ポインタ)がコピーされます。

図1
図1

 Javaのコードでは、プリミティブ型も参照型も同じように記述できるため、ついついプリミティブ型データと同じようにオブジェクト自身がコピーされると思いがちですが、そうではありません。『Java言語仕様』でもわざわざ次のように記述されています。

2つの変数が同じオブジェクトへの参照を保持している場合、どちらか一方の変数に設定されたオブジェクト参照を用いてオブジェクトの状態を変更することができ、変更された状態はもう一方の変数に設定された参照を用いて取得することができる。

 同じ箇所に掲載されているサンプルコード(を簡略化したもの)を以下に示します。

class Value { int val; }

class Test {
  public static void main(String[] args){
    Value v1 = new Value();
    v1.val = 5;
    Value v2 = v1;
    v2.val = 6;
    System.out.print("v1.val==" + v1.val);
    System.out.println(" and v2.val==" + v2.val);
  }
}

 v1とv2はどちらも、new Value()で生成されたValueクラスのインスタンスを指しています。そのため、v1が指しているインスタンスのvalフィールドの値をv2を使って変更することができるわけです。

 この参照型の特徴に注意してコーディングしないと、クラス定義などによるデータのカプセル化やプログラムのモジュール化が台無しになってしまう危険があります。

参照型データを使う

 具体的に次のサンプルコードで見てみましょう。

class i_Container {
  private int i;
  i_Container(int arg){ i = arg; }
  public int get_i(){ return i; }
  public void set_i(int iarg){ i = iarg; }
}

class User {
  private i_Container ic;

  public User(i_Container arg){ ic = arg; }

  public i_Container get_ic(){ return ic; }

  // その他のメソッド
}

 クラスUserのフィールドicはprivate宣言されているので、Userのインスタンスを扱うコードで、直接フィールドicにアクセスすることはできません。しかし、コンストラクタUser()では、引数として受け取った参照をそのままicに代入しているため、User()コンストラクタに渡した参照を使えば、icが指しているi_Containerインスタンスにアクセスすることが可能です。

// ...... 攻撃者が実行するコード ......
i_Container iarg = new i_Container(10);
User u = new User(iarg);
// u.ic.set_i(100);  とするとコンパイルエラーになる
iarg.set_i(100); // iarg を使えば u.ic.i を 10 から 100 に変更できる

 Userクラスの他のメソッドがicの値に応じた処理を行っている場合、外部からicを操作されることによって、意図せぬ動作をさせられる危険があります。Userクラスでは、攻撃者がこのようなコードを用意して実行する可能性を考慮しておかなければなりません。

会員登録無料すると、続きをお読みいただけます

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー

次のページ
ディフェンシブコピー

この記事は参考になりましたか?

  • このエントリーをはてなブックマークに追加
Javaセキュアコーディング入門連載記事一覧

もっと読む

この記事の著者

戸田 洋三(JPCERT コーディネーションセンター)(トダ ヨウゾウ(JPCERT コーディネーションセンター))

リードアナリストJPCERTコーディネーションセンター東京工業大学情報理工学研究科修士課程修了。学生時代は、型理論および証明からのプログラム抽出を研究。その後、千葉大学総合情報処理センターのスタッフとして、学内ネットワークの運営、地域ネットワーク、IPマルチキャストの実験ネットワークであるJP-MB...

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

  • このエントリーをはてなブックマークに追加
CodeZine(コードジン)
https://codezine.jp/article/detail/6704 2012/08/16 16:00

おすすめ

アクセスランキング

アクセスランキング

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー

アクセスランキング

アクセスランキング