12

コンテキスト (編集)

いくつかの明確化はオンデマンドで行われたので、質問に影響を与えるものを要約しようとします.

  • このプロジェクトの目標は、プログラマーに特定の機能を提供することです。ほとんどの場合、ライブラリ (クラス ファイルを含む JAR と思われます) の形で提供します。

  • 上記の機能を使用するには、プログラマーは満たさなければならない(すべき)制約に準拠する必要があります。そうしないと、期待どおりに機能しません ( のロックと同様java.util.concurrentに、適切な時間と場所で取得/解放する必要があります)。

  • このコードは、それを使用するアプリケーションへのエントリ ポイントにはなりません (つまり、何もありませんmain)。

  • API で公開される操作の量は限られています (そして少量です)。

例:

  1. ほとんどすべてが実装済みのクラスによって実装および管理される小さなゲームを考えてみてください。プログラマーに残された唯一のことは、キャラクターが何をするか (歩く、方向を変える、停止する、オブジェクトを検査する)​​ を記述するメソッドを 1 つまたはいくつか記述することです。それらのメソッド (おそらく注釈でマークされていますか?) がwalk、 またはchangeDirection、または calculateだけであることを確認しdiff = desiredValue - x、たとえば、ファイルに書き込んだり、ソケット接続を開いたりしないようにしたいと思います。

  2. トランザクションマネージャーを考えてみてください。マネージャは、このライブラリによって提供されるほか、トランザクションのいくつかの一定の属性 (分離レベル、タイムアウトなど) も提供されます。ここで、プログラマーはトランザクションを持ち、このマネージャーを使用したいと考えています。、 、、または一部のリソースでのみread、マネージャーに知られていることを確認したいと思います。マネージャーがロケットの発射を制御していない場合、トランザクションの途中で彼らを望んでいません。writecommitrollbacklaunchRocket

問題

メソッド(またはメソッドのグループ)の本体にいくつかの不変条件/制限/制約を課し、後で他のプログラマーによって他のパッケージ/場所に実装されるようにしたいと考えています。たとえば、私は彼らに次のようなものを与えます。

public abstract class ToBeExtended {
    // some private stuff they should not modify
    // ...
    public abstract SomeReturnType safeMethod();
}

このプロジェクトの目的のために、メソッド本体がいくつかの不変条件を満たしていることが重要です (おそらく必須です)。むしろ、このメソッドの実装で使用するコマンドのセットを制限することが不可欠です。これらの制約の例:

  • このメソッドは I/O を実行してはなりません。
  • このメソッドは、未知の (潜在的に危険な) オブジェクトをインスタンス化してはなりません。
  • ...

別の言い方をすれば:

  • このメソッドは、既知の (特定の) クラスのメソッドを呼び出すことができます。
  • このメソッドは、いくつかの基本的な命令 (数学、ローカル変数の割り当て、ifs、ループなど) を実行できます。

私は注釈を調べてきましたが、これに近いものはないようです。
これまでの私のオプション:

  1. いくつかの注釈を定義@SafeAnnotationし、それをメソッドに適用して、実装者との契約を定義し、課された規則に従うか、システムが誤動作するかを決定します。

  2. Enum許可された操作で を定義します。許可されたメソッドを公開する代わりに、これらの列挙型オブジェクト (または制御フロー グラフに似たもの) のリストを受け入れて実行するメソッドのみが公開され、何ができるかを制御できます。

例:

public enum AllowedOperations { OP1, OP2 }

public class TheOneKnown {
    public void executeMyStuff (List<AllowedOperations> ops) {
        // ...
    }
}

私の質問

メソッドが有効かどうか (つまり、制約を満たしているかどうか)を (コンパイル時または実行時に) 調べることができる、注釈、リフレクションなどの機能が言語にあるか?
むしろ、他のメソッドの限られたセットのみを呼び出すように強制する方法はありますか?

そうでない場合 (そして私はそうではないと思います)、この 2 番目のアプローチは適切な代替手段でしょうか?
直感的で、よく設計された、および/または優れた実践のように、適切です。

更新(進捗)

関連するいくつかの質問を見た後、この質問の受け入れられた回答に記載されている手順に従うことも検討しています(おそらく3番目のオプションとして)。ただし、これにはアーキテクチャの再考が必要になる場合があります。

注釈を使用して制限を課すという全体的なアイデアには、独自の注釈プロセッサを実装する必要があるようです。これが本当なら、プログラマーがこれらの限られた操作を使用し、後でコードを Java に変換できるように、小規模なドメイン固有言語を検討することもできます。このようにして、指定されたものを制御することもできます。

4

5 に答える 5

6

Java ポリシー ファイルを参照してください。私はそれらを使用したことがなく、それらがあなたの問題に正確に適合するかどうかはわかりませんが、ドキュメントを掘り下げると、適合する可能性があります. ここに役立つかもしれないいくつかのSOの質問があります

Java でのファイル アクセスの制限

ファイルの書き込みを単一のディレクトリに制限するための単純な Java セキュリティ ポリシーは何ですか?

また、ポリシー ファイルに関するドキュメントもいくつかあります。

http://docs.oracle.com/javase/6/docs/technotes/guides/security/PolicyFiles.html

于 2013-04-11T21:36:18.660 に答える
4

カスタム クラス ローダーを使用して、信頼できないコードで使用されるクラスを制限できます。

public class SafeClassLoader extends ClassLoader {

    Set<String> safe = new HashSet<>();

    {
        String[] s = {
            "java.lang.Object",
            "java.lang.String",
            "java.lang.Integer"
        };
        safe.addAll(Arrays.asList(s));
    }

    @Override
    protected Class<?> loadClass(String name, boolean resolve)
            throws ClassNotFoundException {
        if (safe.contains(name)) {
            return super.loadClass(name, resolve);
        } else {
            throw new ClassNotFoundException(name);
        }
    }
}

public class Sandboxer {
    public static void main(String[] args) throws Exception {
        File f = new File("bin/");
        URL[] urls = {f.toURI().toURL()};
        ClassLoader loader = new URLClassLoader(urls, new SafeClassLoader());
        Class<?> good = loader.loadClass("tools.sandbox.Good");
        System.out.println(good.newInstance().toString());
        Class<?> evil = loader.loadClass("tools.sandbox.Evil");
        System.out.println(evil.newInstance().toString());
    }
}

public class Good {
    @Override
    public String toString() {
        return "I am good";
    }
}

public class Evil {
    @Override
    public String toString() {
        new Thread().start();
        return "I am evil.";
    }
}

これを実行すると、

I am good
Exception in thread "main" java.lang.NoClassDefFoundError: java/lang/Thread
    at tools.sandbox.Evil.toString(Evil.java:7)
    at tools.sandbox.Sandboxer.main(Sandboxer.java:18)
Caused by: java.lang.ClassNotFoundException: java.lang.Thread
    at java.net.URLClassLoader$1.run(URLClassLoader.java:366)
    at java.net.URLClassLoader$1.run(URLClassLoader.java:355)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.net.URLClassLoader.findClass(URLClassLoader.java:354)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:423)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:356)
    ... 2 more

もちろん、これは、ホワイトリストに登録したクラスに注意が払われていることを前提としています。また、次のようなサービス拒否を防ぐこともできません。

while (true) {}

また

new long[1000000000];
于 2013-04-11T23:41:42.923 に答える
3

別の方法として、組み込みスクリプト インタープリター、たとえば groovy インタープリター ( https://docs.groovy-lang.org/latest/html/documentation/guide-integrating.html ) を使用し、サードパーティ メソッドのコンテンツを評価する方法があります。実行前の検証を伴うランタイム。

利点は、スクリプトの実行のためにバインドする変数のみへのアクセスを制限できることです。

独自の検証 DSL を作成し、たとえばカスタム アノテーションを使用して、スクリプトを実行するメソッドに適用することもできます。

于 2013-04-17T06:41:06.430 に答える