SlideShare a Scribd company logo
Javaセキュアコーディングセミナー東京
第1回
オブジェクトの生成とセキュリティ
演習の解説

2012年9月9日(日)
JPCERTコーディネーションセンター
脆弱性解析チーム
戸田 洋三




                      1
演習[1]




        2
演習[1]

class Dog {                      (A)どのような出力が得られるか?
  public static void bark() {    (B) bark()メソッドがstatic宣言されて
    System.out.print("woof");
  }                                 いない場合の出力は?
}                                (C)メソッドがどのように実行されて

class Bulldog extends Dog {         いるか説明せよ
  public static void bark() {}
}

public class Bark {
  public static void main(String args[]) {
    Dog d1 = new Dog();
    Dog d2 = new Bulldog();
    d1.bark();
    d2.bark();
  }
}                ヒント
                Java言語仕様 §15.12 Method Invocation Expressions


                            3
演習[1]
(A)どのような出力が得られるか?
      $ java Bark
      woofwoof$

(B) bark()メソッドがstatic宣言されて
  いない場合の出力は?
      $ java Bark
      woof$

(C)メソッドがどのように実行されて
  いるか説明せよ




                             4
コンパイラおよびVMによる処理

                                     (2) コンパイル時のチェック
class Dog {
                                      Dogのメソッドbark()は
  public static void bark() {
    System.out.print("woof");         static宣言されている
  }
}
                                    (3) 実行時処理
class Bulldog extends Dog {           Dogのstaticメソッド
  public static void bark() {}        bark()を呼び出そう!
}

public class Bark {
  public static void main(String args[]) {
    Dog d1 = new Dog();
    Dog d2 = new Bulldog();
    d1.bark();
    d2.bark();                 (1) コンパイル時のチェック
  }                              - d1,d2どちらもDog型の変数
}                                - Dogのメソッドbark()があるのでOK




                            5
コンパイラおよびVMによる処理(staticメソッドでない場合)

                                    (2) コンパイル時のチェック
class Dog {
                                     Dogのメソッドbark()は
  public void bark() {
    System.out.print("woof");        virtual呼び出しだ
  }
}
                                   (3) 実行時処理
class Bulldog extends Dog {          d1,d2が参照している
  public void bark() {}              インスタンスをチェック!
}

public class Bark {                 (4) 実行時処理
  public static void main(String args[]) {
                                      それぞれのインスタンスから って
    Dog d1 = new Dog();               メソッドを呼び出そう!
    Dog d2 = new Bulldog();
    d1.bark();
    d2.bark();                 (1) コンパイル時のチェック
  }                              - d1,d2どちらもDog型の変数
}                                - Dogのメソッドbark()があるのでOK




                              6
演習[2]




        7
演習[2]
                         (A)どのような出力が得られるか?
                         (B) なぜこのような出力が得られたのか説明せよ.

class Point {
                         (C)適切な出力が得られるようにコードを修正せよ.
  protected final int x, y;
  private final String name;
  protected String makeName() { return "[" + x + "," + y + "]"; }
  public final String toString() { return name; }
  Point(int x, int y) {
    this.x = x; this.y = y;
    this.name = makeName();
  }
}

public class ColorPoint extends Point {
  private final String color;
  protected String makeName() { return super.makeName() + ":" + color; }
  ColorPoint(int x, int y, String color) {
    super(x, y);
    this.color = color;
  }
  public static void main(String[] args) {
    System.out.println(new ColorPoint(4, 2, "purple"));
  }
}                                ヒント: Java言語仕様 §15.12 Method Invocation Expressions

                                       8
演習[2]
(A)どのような出力が得られるか?
 $ java ColorPoint
 [4,2]:null
 $

(B) なぜこのような出力が得られたのか説明せよ.
 →Point.toString() から出力
 →name の値
 →name には makeName() の返り値が代入されている

   どの makeName() ?
                              つまり...
    ColorPoint の makeName()   サブクラスのインスタンスが初期
                              化される前にスーパークラスのコ
                              ンストラクタがサブクラスのメ
                              ソッドを呼び出した
                         9
実行の様子
class Point {
  protected final int x, y;
  private final String name; // Cached at construction time
  protected String makeName() { return "[" + x + "," + y + "]"; }
  public final String toString() { return name; }
  Point(int x, int y) {
    this.x = x; this.y = y;
    this.name = makeName();               (3) ColorPointの makeName() が呼び出される
  }
}
                                               (4) 初期化前の color にアクセス
public class ColorPoint extends Point {
  private final String color;
  protected String makeName() { return super.makeName() + ":" + color; }
  ColorPoint(int x, int y, String color) {
    super(x, y);                               (2) Pointのコンストラクタ呼出し
    this.color = color;
  }                                            (5) ここでようやくcolorの初期化
  public static void main(String[] args) {
    System.out.println(new ColorPoint(4, 2, "purple"));
  }
}
                                        (1) ColorPointのコンストラクタ呼出し




                                  10
演習[2]

このコードの問題点:
初期化される前のcolorにアクセスしている
(その結果, デフォルト値の null が出力されている)



元々の意図は?
  初期化された後のcolorの値を出力したい



(C)適切な出力が得られるようにコードを修正せよ.




                    11
どのように修正するか?
class Point {
  protected final int x, y;
  private final String name; // Cached at construction time
  protected String makeName() { return "[" + x + "," + y + "]"; }
  public final String toString() { return name; }
  Point(int x, int y) {
    this.x = x; this.y = y;
    this.name = makeName();
  }
}

public class ColorPoint extends Point {
  private final String color;
  protected String makeName() { return super.makeName() + ":" + color; }
  ColorPoint(int x, int y, String color) {
    super(x, y);
    this.color = color;
  }
  public static void main(String[] args) {
    System.out.println(new ColorPoint(4, 2, "purple"));
  }
}




                                 12
どのように修正するか?
class Point {
  protected final int x, y;
  private String name; // 遅延初期化 (最初に使われたときにキャッシュされる)
    protected String makeName() { return "[" + x + "," + y + "]"; }
    public final synchronized String toString() {
      return (name == null ? name = makeName() : name);
    }
    Point(int x, int y) {      コンストラクタからの makeName() 呼び出し
      this.x = x; this.y = y;
    }                          を避ける
}

public class ColorPoint extends Point {
  private final String color;
  protected String makeName() { return super.makeName() + ":" + color; }
  ColorPoint(int x, int y, String color) {
    super(x, y);
    this.color = color;
  }
  public static void main(String[] args) {
    System.out.println(new ColorPoint(4, 2, "purple"));
  }
}




                                 13
演習[3]




        14
演習[3]

class Purse {
  private int i;

    public Purse(int arg) {
        i = arg;
    }
    public int get_i() { return i; }
    public void set_i(int iarg) { i = iarg; }
}

class User {
  private Purse p;
                             (A) User クラスのインスタンスを生成し,
  public User(Purse arg) {
      p = arg;                    その private フィールド p が参照する
  }                               Purse インスタンスの持つ値を変更す
  public Purse get_p() {
    return p;                     る攻撃コードを書け.
  }                          (B) (A) でつくった攻撃コードが動作しな
}
                                  いように元のコードを修正せよ.
                             15
攻撃コード例

こんなことすると......
class dc {
  public static void main(String[] args){
    Purse newp = new Purse(9999);
    User u = new User(newp);
    System.out.println(u.get_p().get_i());
                                                 get_p() の返り値を使って u
        Purse p = u.get_p();
                                               の private フィールドをいじる
        p.set_i(1099);
        System.out.println(u.get_p().get_i()); ことができる

        newp.set_i(999);
        System.out.println(u.get_p().get_i());
    }
}
                           コンストラクタに渡したオブジェクトを使って u の
                           private フィールドをいじることができる




                               16
修正例

    class User {
    private Purse p;
                                      受け取ったオブジェクトはコ
    public User(Purse arg) {
        p = new Purse(arg.get_i());   ピーを作って使う.
    }
    public Purse get_p() {
      return new Purse(p.get_i());
    }                                 外に渡すオブジェクトはコ
}                                     ピーを作って使う.




     defensive copy : デフェンシブコピー



                             17
修正例(2) Purseクラスを公開する必要がなければ...

class User {                            Purse クラスを入れ子クラスと
                                        して定義する. Purse の中身へ
    private class Purse {
                                         のアクセスは必ず User クラス
      private int i;
      Purse(int arg) { i = arg; }        のメソッド経由とする.
      int get_i() { return i; }
      void set_i(int iarg) { i = iarg; }
    }

    private Purse p;
    public User(int iarg) {
        p = new Purse(iarg);
    }
    public int get_i() { return p.get_i(); }
    public void set_i(int i) { p.set_i(i); }
}




                             18
演習[4]




        19
演習[4]
class Authlet {
  int i;
  Authlet(int i0){
    if (checkarg(i0)) { this.i = i0; }
  }
  boolean checkarg(int i) throws IllegalArgumentException {
    if (i<0 || 100<i) {
      throw
         new IllegalArgumentException("arg should be positive < 100.");
    }
                    class Auth {
    return true;
                      private static Authlet a0;
  }
}
                      public static void checkAuth(Authlet a){
                        if (a0 == null){
                          if (a == null){
                            System.out.println("invalid Authlet!");
                            System.exit(1);
                          }
                          a0 = a;
                        }
                      }
                    }
                                    20
演習[4]
class useAuth {
  public static void main(String[] args){
    Authlet au;
    try {
        au = new Authlet(Integer.parseInt(args[0]));
    } catch(IllegalArgumentException ex){
        au = null;
    }
    Auth.checkAuth(au);                       訂正!
    System.out.println("Authenticated!");
  }
                                              SecurityException ではなく
}                                             IllegalArgumentException


      (A) checkarg() による入力値チェックを回避する攻撃
         コードを書け.
      (B) (A) で書いた攻撃コードに対する対策を行え.



                                21
プログラムの動作を確認する
$ javac Authlet.java Auth.java useAuth.java
$ java useAuth
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 0
"   at useAuth.main(useAuth.java:5)
$
                                   コマンドライン引数が必要


$ java useAuth 101
invalid Authlet!
$
                           checkarg()の入力値検査でエラー


$ java useAuth 50
Authenticated!
$
                                   checkarg()の検査をパス




                                    22
Auth と Authlet の問題点
•Authlet のサブクラスをつくり, checkarg() の検査の後で
フィールド i の値を更新可能
•Auth.checkAuth()は Authlet のインスタンスの中身を
チェックしていない




•Authlet のサブクラスをつくり, フィールド i に任意の値を設
定したインスタンスを作成可能
•作成したインスタンスをAuth.checkAuth()にそのまま渡せば
認証される
攻撃コード
class exploitAuthlet extends Authlet {
  exploitAuthlet(int e){
    super(10);                      checkarg() の後で i の値を再設定
    this.i = e;
  }

    public static void main(String[] args){
      exploitAuthlet eal = new exploitAuthlet(102);
      Auth.checkAuth(eal);
      useAuth.main(new String[]{“1000”});
    }
}                                       不正な値で Authlet を作成, 登録



             元のmain メソッドにはダミーの引数を渡す




                            24
exploitAuthlet の実行
$ javac exploitAuth.java
$ java exploitAuth
Authenticated!
$
              値102のAuthletでパスしてしまう



     対策
     •Authlet のサブクラスをつくれないようにする
     •フィールド i の値を再設定できないようにする
     •Auth.checkAuth()で渡されたAuthletが持っている
      値をチェックする
修正例
final class Authlet {
  int i;
  Authlet(int i0){
    if (checkarg(i0)) { this.i = i0; }
  }
  boolean checkarg(int i) throws IllegalArgumentException {
    if (i<0 || 100<i) {
      throw
         new IllegalArgumentException("arg should be positive < 100.");
    }
                    class Auth {
    return true;
                      private static Authlet a0;
  }
}
                      public static void checkAuth(Authlet a){
                        if (a0 == null){
                          if (a == null){
                            System.out.println("invalid Authlet!");
                            System.exit(1);
                          }
                          a0 = a;
                        }
                      }
                    }
                                    26
‣ (empty page)




                 27

More Related Content

PDF
Javaセキュアコーディングセミナー東京第1回 演習
PPTX
C# LINQ ~深く知って、使いまくろう~
PPTX
C# 式木 (Expression Tree) ~ LINQをより深く理解するために ~
PPTX
C#6.0の新機能紹介
PDF
Java SE 7 InvokeDynamic in JRuby
PDF
C# ドキドキ ライブ コーディング!! ~ 小島の分 ~ | BuriKaigi 2020
PPTX
C#を始めたばかりの人へのLINQ to Objects
PDF
LINQソースでGO!
Javaセキュアコーディングセミナー東京第1回 演習
C# LINQ ~深く知って、使いまくろう~
C# 式木 (Expression Tree) ~ LINQをより深く理解するために ~
C#6.0の新機能紹介
Java SE 7 InvokeDynamic in JRuby
C# ドキドキ ライブ コーディング!! ~ 小島の分 ~ | BuriKaigi 2020
C#を始めたばかりの人へのLINQ to Objects
LINQソースでGO!

What's hot (20)

PDF
C++14 Overview
PDF
Java puzzlers 2013 at JavaFesta Japan
PDF
サーバーサイドでの非同期処理で色々やったよ
PDF
C++0x in programming competition
PDF
Cloud TPU Driver API ソースコード解析
PDF
boost tour 1.48.0 all
PPTX
C# LINQ入門
PDF
C++ lecture-2
PPTX
メタプログラミング C#
PPTX
Java Puzzlers JJUG CCC 2016
PPTX
Visual C++で使えるC++11
PDF
unique_ptrにポインタ以外のものを持たせるとき
KEY
Objc lambda
PDF
Ekmett勉強会発表資料
PDF
.NETラボ 勉強会 2021年1月 「C#で機械学習」
PDF
わかるコードを書くために For writing clean code
PDF
今から始める Lens/Prism
PDF
“Design and Implementation of Generics for the .NET Common Language Runtime”他...
PDF
Pythonで始めるDropboxAPI
C++14 Overview
Java puzzlers 2013 at JavaFesta Japan
サーバーサイドでの非同期処理で色々やったよ
C++0x in programming competition
Cloud TPU Driver API ソースコード解析
boost tour 1.48.0 all
C# LINQ入門
C++ lecture-2
メタプログラミング C#
Java Puzzlers JJUG CCC 2016
Visual C++で使えるC++11
unique_ptrにポインタ以外のものを持たせるとき
Objc lambda
Ekmett勉強会発表資料
.NETラボ 勉強会 2021年1月 「C#で機械学習」
わかるコードを書くために For writing clean code
今から始める Lens/Prism
“Design and Implementation of Generics for the .NET Common Language Runtime”他...
Pythonで始めるDropboxAPI
Ad

Viewers also liked (8)

PDF
Lec 04 program development and programming languages
PDF
Javaセキュアコーディングセミナー東京第3回演習の解説
PDF
Javaセキュアコーディングセミナー東京第2回演習の解説
PDF
脆弱性事例に学ぶセキュアコーディング「SSL/TLS証明書検証」編 (JavaDayTokyo2015)
PPTX
Android Platform の URLConnection に HTTP ヘッダインジェクションの脆弱性
PDF
OWASP ASVS と Cheat Sheet シリーズ (日本語版) のご紹介 (OSC2016Hokkaido)
PDF
Android Secure Coding
PDF
デブサミ2015 事例から学ぶAndroidアプリのセキュアコーディング「SSL/TLS証明書検証の現状と対策」
Lec 04 program development and programming languages
Javaセキュアコーディングセミナー東京第3回演習の解説
Javaセキュアコーディングセミナー東京第2回演習の解説
脆弱性事例に学ぶセキュアコーディング「SSL/TLS証明書検証」編 (JavaDayTokyo2015)
Android Platform の URLConnection に HTTP ヘッダインジェクションの脆弱性
OWASP ASVS と Cheat Sheet シリーズ (日本語版) のご紹介 (OSC2016Hokkaido)
Android Secure Coding
デブサミ2015 事例から学ぶAndroidアプリのセキュアコーディング「SSL/TLS証明書検証の現状と対策」
Ad

Similar to Javaセキュアコーディングセミナー東京第1回演習の解説 (20)

PDF
C#の新機能勉強会 ~ C#7、8の新機能を活用して速く安全なプログラムを書こう~
PPTX
Junit4
PDF
Xtend - Javaの未来を今すぐ使う
PDF
Javaセキュアコーディングセミナー東京第4回講義
PDF
第2回デザインパターン資料
PDF
Shibuya JVM Groovy 20150418
PDF
Javaセキュアコーディングセミナー東京第3回講義
PDF
Xtend30分クッキング
PDF
第三回ありえる社内勉強会 「いわががのLombok」
PPTX
GoF デザインパターン 2009
PDF
Entity Framework
PDF
Replace Output Iterator and Extend Range JP
PDF
オブジェクト指向できていますか?
PPTX
Enshu8
PDF
ATN No.2 大阪から来たJavaPuzzlers
PDF
現実世界のJRuby
PDF
Pfi Seminar 2010 1 7
PDF
Javaセキュアコーディングセミナー東京第3回演習
PDF
Valhalla Update JJUG CCC Spring 2019
PDF
C#勉強会 ~ C#9の新機能 ~
C#の新機能勉強会 ~ C#7、8の新機能を活用して速く安全なプログラムを書こう~
Junit4
Xtend - Javaの未来を今すぐ使う
Javaセキュアコーディングセミナー東京第4回講義
第2回デザインパターン資料
Shibuya JVM Groovy 20150418
Javaセキュアコーディングセミナー東京第3回講義
Xtend30分クッキング
第三回ありえる社内勉強会 「いわががのLombok」
GoF デザインパターン 2009
Entity Framework
Replace Output Iterator and Extend Range JP
オブジェクト指向できていますか?
Enshu8
ATN No.2 大阪から来たJavaPuzzlers
現実世界のJRuby
Pfi Seminar 2010 1 7
Javaセキュアコーディングセミナー東京第3回演習
Valhalla Update JJUG CCC Spring 2019
C#勉強会 ~ C#9の新機能 ~

More from JPCERT Coordination Center (20)

PDF
いま改めて製品開発者の脆弱性対応について考える ~情報セキュリティ早期警戒パートナーシップを運用する調整機関の視点から~
PDF
安全なプラグインに必要なこと: 脆弱性届出状況に見る傾向と対策 (WordCampTokyo 2017)
PDF
DLL読み込みの問題を読み解く
PDF
WordBench東京 7月勉強会「夏のLT大会!」『WordPress とバックアップの話』
PDF
CERT コーディングスタンダードご紹介 (OSC2017@Osaka)
PDF
脆弱性情報はこうしてやってくる
PDF
Case Studies and Lessons Learned from SSL/TLS Certificate Verification Vulner...
PDF
クロスサイトリクエストフォージェリ(CSRF)とその対策
PDF
ソフトウェアセキュリティ保証成熟度モデル
PDF
Lessons (to be) Learned from Handling OpenSSL Vulnerabilities
PDF
脆弱性事例に学ぶセキュアコーディング「SSL/TLS証明書検証」編 (KOF2014)
PDF
JRE標準ライブラリの脆弱性事例を理解する (AtomicReferenceArrayクラス と Type Confusion)
PDF
Apache Axis2におけるXML署名検証不備
PDF
Apache Tomcat における クロスサイトリクエストフォージェリ (CSRF) 保護メカニズム回避の脆弱性
PDF
Spacewalkにおけるクロスサイト リクエストフォージェリ(CSRF)の脆弱性
PDF
Apache CommonsのHttpClientに おけるSSLサーバ証明書検証不備 (CVE-2012-5783)
PDF
Apache ActiveMQにおける認証処理不備の脆弱性(AMQ-1272)
PDF
JBoss Application Server におけるディレクトリトラバーサルの脆弱性
PDF
MySQL Connector/J における SQL インジェクションの脆弱性
PDF
Blojsom におけるクロスサイトスクリプティングの脆弱性
いま改めて製品開発者の脆弱性対応について考える ~情報セキュリティ早期警戒パートナーシップを運用する調整機関の視点から~
安全なプラグインに必要なこと: 脆弱性届出状況に見る傾向と対策 (WordCampTokyo 2017)
DLL読み込みの問題を読み解く
WordBench東京 7月勉強会「夏のLT大会!」『WordPress とバックアップの話』
CERT コーディングスタンダードご紹介 (OSC2017@Osaka)
脆弱性情報はこうしてやってくる
Case Studies and Lessons Learned from SSL/TLS Certificate Verification Vulner...
クロスサイトリクエストフォージェリ(CSRF)とその対策
ソフトウェアセキュリティ保証成熟度モデル
Lessons (to be) Learned from Handling OpenSSL Vulnerabilities
脆弱性事例に学ぶセキュアコーディング「SSL/TLS証明書検証」編 (KOF2014)
JRE標準ライブラリの脆弱性事例を理解する (AtomicReferenceArrayクラス と Type Confusion)
Apache Axis2におけるXML署名検証不備
Apache Tomcat における クロスサイトリクエストフォージェリ (CSRF) 保護メカニズム回避の脆弱性
Spacewalkにおけるクロスサイト リクエストフォージェリ(CSRF)の脆弱性
Apache CommonsのHttpClientに おけるSSLサーバ証明書検証不備 (CVE-2012-5783)
Apache ActiveMQにおける認証処理不備の脆弱性(AMQ-1272)
JBoss Application Server におけるディレクトリトラバーサルの脆弱性
MySQL Connector/J における SQL インジェクションの脆弱性
Blojsom におけるクロスサイトスクリプティングの脆弱性

Javaセキュアコーディングセミナー東京第1回演習の解説

  • 3. 演習[1] class Dog { (A)どのような出力が得られるか? public static void bark() { (B) bark()メソッドがstatic宣言されて System.out.print("woof"); } いない場合の出力は? } (C)メソッドがどのように実行されて class Bulldog extends Dog { いるか説明せよ public static void bark() {} } public class Bark { public static void main(String args[]) { Dog d1 = new Dog(); Dog d2 = new Bulldog(); d1.bark(); d2.bark(); } } ヒント Java言語仕様 §15.12 Method Invocation Expressions 3
  • 4. 演習[1] (A)どのような出力が得られるか? $ java Bark woofwoof$ (B) bark()メソッドがstatic宣言されて いない場合の出力は? $ java Bark woof$ (C)メソッドがどのように実行されて いるか説明せよ 4
  • 5. コンパイラおよびVMによる処理 (2) コンパイル時のチェック class Dog { Dogのメソッドbark()は public static void bark() { System.out.print("woof"); static宣言されている } } (3) 実行時処理 class Bulldog extends Dog { Dogのstaticメソッド public static void bark() {} bark()を呼び出そう! } public class Bark { public static void main(String args[]) { Dog d1 = new Dog(); Dog d2 = new Bulldog(); d1.bark(); d2.bark(); (1) コンパイル時のチェック } - d1,d2どちらもDog型の変数 } - Dogのメソッドbark()があるのでOK 5
  • 6. コンパイラおよびVMによる処理(staticメソッドでない場合) (2) コンパイル時のチェック class Dog { Dogのメソッドbark()は public void bark() { System.out.print("woof"); virtual呼び出しだ } } (3) 実行時処理 class Bulldog extends Dog { d1,d2が参照している public void bark() {} インスタンスをチェック! } public class Bark { (4) 実行時処理 public static void main(String args[]) { それぞれのインスタンスから って Dog d1 = new Dog(); メソッドを呼び出そう! Dog d2 = new Bulldog(); d1.bark(); d2.bark(); (1) コンパイル時のチェック } - d1,d2どちらもDog型の変数 } - Dogのメソッドbark()があるのでOK 6
  • 8. 演習[2] (A)どのような出力が得られるか? (B) なぜこのような出力が得られたのか説明せよ. class Point { (C)適切な出力が得られるようにコードを修正せよ. protected final int x, y; private final String name; protected String makeName() { return "[" + x + "," + y + "]"; } public final String toString() { return name; } Point(int x, int y) { this.x = x; this.y = y; this.name = makeName(); } } public class ColorPoint extends Point { private final String color; protected String makeName() { return super.makeName() + ":" + color; } ColorPoint(int x, int y, String color) { super(x, y); this.color = color; } public static void main(String[] args) { System.out.println(new ColorPoint(4, 2, "purple")); } } ヒント: Java言語仕様 §15.12 Method Invocation Expressions 8
  • 9. 演習[2] (A)どのような出力が得られるか? $ java ColorPoint [4,2]:null $ (B) なぜこのような出力が得られたのか説明せよ. →Point.toString() から出力 →name の値 →name には makeName() の返り値が代入されている どの makeName() ? つまり... ColorPoint の makeName() サブクラスのインスタンスが初期 化される前にスーパークラスのコ ンストラクタがサブクラスのメ ソッドを呼び出した 9
  • 10. 実行の様子 class Point { protected final int x, y; private final String name; // Cached at construction time protected String makeName() { return "[" + x + "," + y + "]"; } public final String toString() { return name; } Point(int x, int y) { this.x = x; this.y = y; this.name = makeName(); (3) ColorPointの makeName() が呼び出される } } (4) 初期化前の color にアクセス public class ColorPoint extends Point { private final String color; protected String makeName() { return super.makeName() + ":" + color; } ColorPoint(int x, int y, String color) { super(x, y); (2) Pointのコンストラクタ呼出し this.color = color; } (5) ここでようやくcolorの初期化 public static void main(String[] args) { System.out.println(new ColorPoint(4, 2, "purple")); } } (1) ColorPointのコンストラクタ呼出し 10
  • 11. 演習[2] このコードの問題点: 初期化される前のcolorにアクセスしている (その結果, デフォルト値の null が出力されている) 元々の意図は? 初期化された後のcolorの値を出力したい (C)適切な出力が得られるようにコードを修正せよ. 11
  • 12. どのように修正するか? class Point { protected final int x, y; private final String name; // Cached at construction time protected String makeName() { return "[" + x + "," + y + "]"; } public final String toString() { return name; } Point(int x, int y) { this.x = x; this.y = y; this.name = makeName(); } } public class ColorPoint extends Point { private final String color; protected String makeName() { return super.makeName() + ":" + color; } ColorPoint(int x, int y, String color) { super(x, y); this.color = color; } public static void main(String[] args) { System.out.println(new ColorPoint(4, 2, "purple")); } } 12
  • 13. どのように修正するか? class Point { protected final int x, y; private String name; // 遅延初期化 (最初に使われたときにキャッシュされる) protected String makeName() { return "[" + x + "," + y + "]"; } public final synchronized String toString() { return (name == null ? name = makeName() : name); } Point(int x, int y) { コンストラクタからの makeName() 呼び出し this.x = x; this.y = y; } を避ける } public class ColorPoint extends Point { private final String color; protected String makeName() { return super.makeName() + ":" + color; } ColorPoint(int x, int y, String color) { super(x, y); this.color = color; } public static void main(String[] args) { System.out.println(new ColorPoint(4, 2, "purple")); } } 13
  • 14. 演習[3] 14
  • 15. 演習[3] class Purse { private int i; public Purse(int arg) { i = arg; } public int get_i() { return i; } public void set_i(int iarg) { i = iarg; } } class User { private Purse p; (A) User クラスのインスタンスを生成し, public User(Purse arg) { p = arg; その private フィールド p が参照する } Purse インスタンスの持つ値を変更す public Purse get_p() { return p; る攻撃コードを書け. } (B) (A) でつくった攻撃コードが動作しな } いように元のコードを修正せよ. 15
  • 16. 攻撃コード例 こんなことすると...... class dc { public static void main(String[] args){ Purse newp = new Purse(9999); User u = new User(newp); System.out.println(u.get_p().get_i()); get_p() の返り値を使って u Purse p = u.get_p(); の private フィールドをいじる p.set_i(1099); System.out.println(u.get_p().get_i()); ことができる newp.set_i(999); System.out.println(u.get_p().get_i()); } } コンストラクタに渡したオブジェクトを使って u の private フィールドをいじることができる 16
  • 17. 修正例 class User { private Purse p; 受け取ったオブジェクトはコ public User(Purse arg) { p = new Purse(arg.get_i()); ピーを作って使う. } public Purse get_p() { return new Purse(p.get_i()); } 外に渡すオブジェクトはコ } ピーを作って使う. defensive copy : デフェンシブコピー 17
  • 18. 修正例(2) Purseクラスを公開する必要がなければ... class User { Purse クラスを入れ子クラスと して定義する. Purse の中身へ private class Purse { のアクセスは必ず User クラス private int i; Purse(int arg) { i = arg; } のメソッド経由とする. int get_i() { return i; } void set_i(int iarg) { i = iarg; } } private Purse p; public User(int iarg) { p = new Purse(iarg); } public int get_i() { return p.get_i(); } public void set_i(int i) { p.set_i(i); } } 18
  • 19. 演習[4] 19
  • 20. 演習[4] class Authlet { int i; Authlet(int i0){ if (checkarg(i0)) { this.i = i0; } } boolean checkarg(int i) throws IllegalArgumentException { if (i<0 || 100<i) { throw new IllegalArgumentException("arg should be positive < 100."); } class Auth { return true; private static Authlet a0; } } public static void checkAuth(Authlet a){ if (a0 == null){ if (a == null){ System.out.println("invalid Authlet!"); System.exit(1); } a0 = a; } } } 20
  • 21. 演習[4] class useAuth { public static void main(String[] args){ Authlet au; try { au = new Authlet(Integer.parseInt(args[0])); } catch(IllegalArgumentException ex){ au = null; } Auth.checkAuth(au); 訂正! System.out.println("Authenticated!"); } SecurityException ではなく } IllegalArgumentException (A) checkarg() による入力値チェックを回避する攻撃 コードを書け. (B) (A) で書いた攻撃コードに対する対策を行え. 21
  • 22. プログラムの動作を確認する $ javac Authlet.java Auth.java useAuth.java $ java useAuth Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 0 " at useAuth.main(useAuth.java:5) $ コマンドライン引数が必要 $ java useAuth 101 invalid Authlet! $ checkarg()の入力値検査でエラー $ java useAuth 50 Authenticated! $ checkarg()の検査をパス 22
  • 23. Auth と Authlet の問題点 •Authlet のサブクラスをつくり, checkarg() の検査の後で フィールド i の値を更新可能 •Auth.checkAuth()は Authlet のインスタンスの中身を チェックしていない •Authlet のサブクラスをつくり, フィールド i に任意の値を設 定したインスタンスを作成可能 •作成したインスタンスをAuth.checkAuth()にそのまま渡せば 認証される
  • 24. 攻撃コード class exploitAuthlet extends Authlet { exploitAuthlet(int e){ super(10); checkarg() の後で i の値を再設定 this.i = e; } public static void main(String[] args){ exploitAuthlet eal = new exploitAuthlet(102); Auth.checkAuth(eal); useAuth.main(new String[]{“1000”}); } } 不正な値で Authlet を作成, 登録 元のmain メソッドにはダミーの引数を渡す 24
  • 25. exploitAuthlet の実行 $ javac exploitAuth.java $ java exploitAuth Authenticated! $ 値102のAuthletでパスしてしまう 対策 •Authlet のサブクラスをつくれないようにする •フィールド i の値を再設定できないようにする •Auth.checkAuth()で渡されたAuthletが持っている 値をチェックする
  • 26. 修正例 final class Authlet { int i; Authlet(int i0){ if (checkarg(i0)) { this.i = i0; } } boolean checkarg(int i) throws IllegalArgumentException { if (i<0 || 100<i) { throw new IllegalArgumentException("arg should be positive < 100."); } class Auth { return true; private static Authlet a0; } } public static void checkAuth(Authlet a){ if (a0 == null){ if (a == null){ System.out.println("invalid Authlet!"); System.exit(1); } a0 = a; } } } 26