SHOEISHA iD

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

DeveloperZine(デベロッパージン)- エンジニアの意思決定を支える技術情報メディア ProductZine

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

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

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

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

ディフェンシブコピー

 この場合の定石は、「ディフェンシブコピー」を行うこと、つまり、渡されたインスタンスの複製を作って使うことです。Javaセキュアコーディングスタンダードでは、OBJ06-Jというルールでこれを説明しています。

 ディフェンシブコピーを行うように更新したコンストラクタを次に示します。

public User(i_Container arg){
  ic = new i_Container(arg.get_i());
}

 引数で受け取ったi_Containerインスタンスのフィールドiの値をget_i()メソッドで求め、それを使って改めてi_Containerインスタンスを生成します。こうすることで、外部からこのインスタンスを操作される危険がなくなります。

 全く同じことが、クラス内部で使っている参照を返り値として返す場合にも当てはまります。

 Userクラスのget_ic()メソッドはicの値(参照)をそのまま返しています。これを受け取ったコードでは、icが指すインスタンスが持っている値を変更することが可能です。こちらにもディフェンシブコピーを適用すべきでした。get_ic()メソッドもディフェンシブコピーを行うように更新したUserクラスのコードを次に示します。

class User {
  private i_Container ic;

  public User(i_Container arg){
    ic = new i_Container(arg.get_i());
  }

  public i_Container get_ic(){
    return new i_Container(ic.get_i());
  }

  // その他のメソッド
}
図2: コンストラクタでディフェンシブコピーを行うようにしたUserクラス
図2: コンストラクタでディフェンシブコピーを行うようにしたUserクラス
図3: ディフェンシブコピーを行うget_ic()メソッド
図3: ディフェンシブコピーを行うget_ic()メソッド

 Javaセキュアコーディングスタンダードでは、OBJ05-Jというルールがこれを説明しています。

コピーコンストラクタと静的ファクトリメソッド

 前述のi_Containerクラスでは、フィールドiの値だけ分かれば簡単にインスタンスの複製を作ることができました。しかし、より複雑で大きなクラスを扱う場合、今回のようにメンバフィールドの複製を作る作業は繁雑になってきます。しかもインスタンスの複製を作る作業はクラスの内部構造にも依存するので、複製を作るコードがそのクラスの外部にあるのはカプセル化の観点からも好ましいことではありません。

 そこで、インスタンスの複製が必要となることが想定されるクラスは、複製をつくるメソッドを提供すべきと考えられます。このようなときに使われるのがコピーコンストラクタや静的ファクトリメソッドです。これらについては、JavaセキュアコーディングスタンダードのOBJ04-Jを参照してください。

まとめ

 今回はJavaの参照型についてとりあげ、参照型データを扱うときに重要となるディフェンシブコピーの考え方について紹介しました。みなさんが今までに書いたJavaアプリケーションには、このようなディフェンシブコピーが必要な部分がなかったでしょうか? いちど見直してみることをおすすめします。

 JDK 7の初期のバージョンにバンドルされていたライブラリのなかでも、このようなディフェンシブコピーを行っていなかった例が発見されています。そのコードは次のようなものでした。

public class InvalidityDateExtension ...... {
  ......
  private Date date;
  ......
  public Object get(String name){
    if (name.equalsIgnoreCase(DATE)){
      return date;
    } else { ... }
  }
  ......
}

 InvalidityDateExtensionクラスのdateフィールドはprivate宣言されています。しかし、get()メソッドではdateフィールドの値をディフェンシブコピーすることなくそのまま呼出し元に返しているため、この返り値を使えばdateフィールドが参照しているDateインスタンスを改変することが可能でした。この部分のコードはOpenJDKのソースでは以下のファイルに収められています。

openjdk/jdk/src/share/classes/sun/security/x509/InvalidityDateExtension.java

 OpenJDKのソースコードを参照できる方は、上記の部分が現在のコードでどのように修正されているか、確認してみてください。

参考文献

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

連載通知を行うには会員登録(無料)が必要です。
既に会員の方はを行ってください。
Javaセキュアコーディング入門連載記事一覧

もっと読む

この記事の著者

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

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

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

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

この記事をシェア

CodeZine(コードジン)
https://codezine.jp/article/detail/6704 2012/08/16 16:00

イベント

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

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

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

メールバックナンバー