2011-07-01 17 views
4

JEXLスクリプトを実行するためのサンドボックスを作成しています。そのため、悪意のあるユーザーがアクセスできる変数以外のデータにアクセスできないため、サーバーでDOS攻撃を実行できません。私はこれを誰かのために文書化したいと思っていますし、また、他の人々のアプローチをアプローチに取り入れたいと思います。安全なJEXL(スクリプティング)サンドボックスの作成方法を教えてください。

以下は、私はそれを知ってるもののリストが対処する必要がある:

  1. のみホワイトリスト上にあるその「新しい」使用してクラスをインスタンス化することができます。
  2. forNameを呼び出すことができ、どのクラスにもアクセスできるので、どのクラスでもgetClassメソッドにアクセスすることを許可しないでください。
  3. ファイルなどのリソースへのアクセスを制限します。
  4. 式の実行に一定の時間しかかからないため、消費するリソースの量を制限できます。

これはJEXLには適用されませんが、あなたが使用しているスクリプト言語に適用することがあります。

  1. をfinalizeメソッドはファイナライザスレッドから呼び出されるため、オブジェクトがカスタムのfinalizeメソッドを持ってすることはできません。オブジェクトを作成してその中でコードを実行するために使用されているAccessControlContextではなく、元のAccessControlContextで実行されます。

答えて

6

ここでは、これらのそれぞれのケースを扱うための私のアプローチです。これらのケースをそれぞれテストするための単体テストを作成し、それらが機能することを確認しました。

  1. JEXLは非常に簡単です。カスタムClassLoaderを作成するだけです。 2つのloadClass()メソッドをオーバーライドします。 JexlEngineではsetClassLoader()を呼び出します。

  2. また、JEXLはこれを非常に簡単にします。 '.class'と '.getClass()'の両方をブロックする必要があります。 UberspectImplを拡張する独自のUberspectクラスを作成します。識別子が "class"に等しい場合は、getPropertyGetをオーバーライドします。メソッドが "getClass"に等しい場合は、getMethodをオーバーライドします。 JexlEngineを構築するときは、Uberspect実装への参照を渡します。

  3. これは、JavaのAccessControllerメカニズムを使用して行います。私はこれをすばやく実行停止します。 -Djava.security.policy = policyfileでjavaを起動します。この行を含むpolicyfileという名前のファイルを作成します。 grant {permission java.security.AllPermission; }; この呼び出しでデフォルトのSecurityManagerを設定します。System.setSecurityManager(new SecurityManager());これでパーミッションを制御できるようになり、デフォルトではすべてのパーミッションが適用されます。アプリの権限を必要なものだけに制限する方が良いでしょう。次に、権限を最小限に制限し、AccessController.doPrivileged()を呼び出してAccessControlContextを渡した後、doPrivileged()内のJEXLスクリプトを実行するAccessControlContextを作成します。これを示す小さなプログラムがあります。 JEXLスクリプトはSystem.exit(1)を呼び出し、doPrivileged()でラップされていない場合はJVMを正常終了させます。

    System.out.println("java.security.policy=" + System.getProperty("java.security.policy")); 
    System.setSecurityManager(new SecurityManager()); 
    try { 
        Permissions perms = new Permissions(); 
        perms.add(new RuntimePermission("accessDeclaredMembers")); 
        ProtectionDomain domain = new ProtectionDomain(new CodeSource(null, (Certificate[]) null), perms); 
        AccessControlContext restrictedAccessControlContext = new AccessControlContext(new ProtectionDomain[] { domain }); 
    
        JexlEngine jexlEngine = new JexlEngine(); 
        final Script finalExpression = jexlEngine.createScript(
          "i = 0; intClazz = i.class; " 
          + "clazz = intClazz.forName(\"java.lang.System\"); " 
          + "m = clazz.methods; m[0].invoke(null, 1); c"); 
    
        AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() { 
         @Override 
         public Object run() throws Exception { 
          return finalExpression.execute(new MapContext()); 
         } 
        }, restrictedAccessControlContext); 
    } 
    catch (Throwable ex) { 
        ex.printStackTrace(); 
    } 
    
  4. このトリックは、スクリプトが終了する前に中断しています。私がこれを行うために見つけた1つの方法は、カスタムJexlArithmeticクラスを作成することです。次に、そのクラスの各メソッドをオーバーライドし、スーパークラスチェックで実際のメソッドを呼び出す前に、スクリプトの実行を停止する必要があるかどうかを確認します。私はExecutorServiceを使ってスレッドを作成しています。将来の時。get()は、待つ時間を渡すと呼ばれます。 TimeoutExceptionがスローされると、スクリプトを実行しているスレッドを中断するFuture.cancel()を呼び出します。新しいJexlArithmeticクラスの各オーバーライドされたメソッドの中で、Thread.interrupted()をチェックし、trueの場合はjava.util.concurrent.CancellationExceptionをスローします。 スクリプトが実行されているときに中断することができるように定期的に実行されるコードを配置する場所がありますか?

関連する問題