2

私はゲームのようなシステムに取り組んでいます。ユーザーは、カスタマイズされた動作のために .class および .java ファイルを送信できます。一部のオブジェクトはコールバックを介してユーザーに配信されますが、ユーザーがこれらのオブジェクトを自分で (カスタム パラメーターを使用して) 構築できる場合、それはユーザーにとって有利になります。ユーザーの反射を禁止し、パッケージを封印します。すべてのパッケージ構造を放棄する (そしてコンストラクターをパッケージ プライベートにする) と、これを機能させることができますが、そうはしたくありません。


以下に例を示します。

sscce.mycode.a.SomeClass.java :

package sscce.mycode.a;

import sscce.mycode.b.RestrictedObject;
import sscce.usercode.SomeUserClass;

public class SomeClass {

    public static void main(String[] args) {
        SomeUserClass userClass=new SomeUserClass();

        // If I can create it from here, anyone can...
        RestrictedObject object=new RestrictedObject();

        userClass.someMethod(object);
    }

}

sscce.mycode.b.Interface.java :

package sscce.mycode.b;

public interface Interface {

    public void someMethod(RestrictedObject restrictedObject);

}

sscce.mycode.b.RestrictedObject.java :

package sscce.mycode.b;

public class RestrictedObject {

    public RestrictedObject() {}

}

sscce.usercode.SomeUserClass.java :

package sscce.usercode;

import sscce.mycode.b.Interface;
import sscce.mycode.b.RestrictedObject;

public class SomeUserClass implements Interface {

    @Override
    public void someMethod(RestrictedObject restrictedObject) {
        // It receives an instance, but cannot create it.
        System.out.println("Got "+restrictedObject);
    }
}

動機: すべてを 1 つのパッケージにまとめるのは面倒に思えます...

パッケージを平坦化せずにこれを達成する方法についてアイデアを持っている人はいますか?
解決策、アイデア、コメントをお寄せいただきありがとうございます。Till

4

1 に答える 1

1

次の方法で行うこともできますが、このアプローチは非常に遅く、率直に言って悪い習慣であるため、本当にこのアプローチを使用するかどうかを慎重に検討する必要があります。とにかく、あなたがそれを行うことができる方法について、私はそれを上げます:

public final class Secured {

  private static final Set<Class<?>> allowedCallers = new HashSet<>();

  static {
    allowedCallers.add(Allowed.class);
  }

  private static final class SecurityManagerExtension extends SecurityManager {

    private static final int OFFSET = 4;

    @Override
    protected Class<?>[] getClassContext() {
      return super.getClassContext();
    }

    private Class<?> getCaller() {
      try {
        return getClassContext()[OFFSET];
      } catch (ArrayIndexOutOfBoundsException e) {
        return null;
      }
    }
  }

  private Secured() {
    // protect against reflection attack
    Class<?> caller = new SecurityManagerExtension().getCaller();
    if (!this.getClass().equals(caller)) {
      throw new IllegalStateException();
    }
    System.out.println("Secured instance constructed!");
  }

  public static Secured createInstance() {
    // this gets the class name of the calling class
    Class<?> caller = new SecurityManagerExtension().getCaller();
    if (allowedCallers.contains(caller)) {
      System.out.println("Created instance by '" + caller + "'!");
      return new Secured();
    } else {
      System.out.println("No instance created because call was made by '" + caller + "'!");
      return null;
    }
  }
}

サブクラス化を防ぐために、クラスの final キーワードに注意してください。クラスを自分でサブクラス化する必要がある場合は、final キーワードをファクトリ メソッドに移動します。また、これはシリアル化攻撃から保護されていないことに注意してください。

于 2013-05-25T21:15:35.253 に答える