2012-04-15 7 views
2

JavaでListを要求するときに、ユーザーが自分のフィルタを書き込むことができるようにします。
ユーザーが(安全に)独自のフィルタをJavaでプログラミングできる方法

オプション1)私はJavaScriptをRhinoと考えています。
ユーザーのフィルタをJavaScript文字列として取得します。そして、このスクリプトでisAccepted(myItem)と呼んでください。
返信に応じて、私は要素を受け入れるかどうかを決めます。

オプション2)私はGroovyについて考えています。
私のユーザは、テキストフィールドにGroovyスクリプトを書くことができます。私のユーザがこのフィルタで検索すると、GroovyスクリプトがJavaでコンパイルされ(最初の呼び出しの場合)、Javaメソッドが呼び出されます。isAccepted() 返信に応じて、要素を受け入れるかどうかを指定します。

私のアプリケーションはこの機能に多く依存しており、私のサーバー上で集中的に呼び出されます。
私はビリーブのスピードが鍵です。

オプション1つの思考:(...私が間違っている場合は が私を修正して、私は私の場合のGroovyの主な利点は速度ですが、私のユーザーが自分のサーバー上の不要なコードをコンパイルして実行することができると思います任意の回避策)

オプション2思考:? 私はほとんどの人で考えるにはJavaScriptを有効にし、よりおもちゃのようなものです気。 の場合はにしてもそれほど信頼できないのはおそらく私の顧客です。あなたはそう思いますか?
私が期待している他の悪い点は、Webでの私の読書からのスピードです。
そして再び私のユーザー(任意の回避策?)... access Javaすることができますし、自分のサーバー上の不要なコードを実行

さらに詳しい情報: 私は私のアプリのメインのWebサービスのためのGoogle App Engineの上で自分のアプリケーションを実行していますよ。
フィルタはコールで20回適用されます。
フィルタは(ほとんどの場合、)シンプルになります。

私のサーバーでこのフィルタを安全にするための考え方はありますか?
それを動作させる他のapproche?

+1

あなたの質問はあまりにも漠然としており、Javascriptをちょっとおもちゃにすると考えている人は非常に連絡がありません – ControlAltDel

答えて

1

私の考え:

  • あなたのスクリプトをコンパイルするときに、スクリプトからアクセスできるように他のクラスを避けるために、独自のクラスローダを使用する必要があります。それがGAEで可能かどうかは不明です。
  • スクリプトがファイルssystemやネットワークなどにアクセスできないようにするには、JavaのSecurityManager機能を使用する必要があります.GASで可能かどうかは不明です。

上記の2つの項目だけを見ると、非常に複雑で脆弱に見えます。既存のサンドボックス機能を既存のプロジェクトとして見つけることができない場合は、それを離れてください。

あなたが正当であると判断した表現を可能にするドメイン固有の言語を設計することは、より安全であり、上記の項目を見ると、あなたは許可したいと思うところで非常に懸命に考える必要があります。そこから言語を設計することは大きなステップではありません。

groovyクロージャ(内部DSL)でDSLを実装しないよう注意してください。これはgroovyなので、あなたもハック可能です。あなたは余分な言語を定義し、それを解析する必要があります。私は文法を定義するためにパーサーコンビネータjparsecをお勧めします。その場合、コンパイラコンパイラは必要ありません。

http://jparsec.codehaus.org/

FYI、ここで私はjparsec(Groovyのコード)を書いた小さなパーサです:

//import some static methods, this will allow more concise code 
    import static org.codehaus.jparsec.Parsers.* 
    import static org.codehaus.jparsec.Terminals.* 
    import static org.codehaus.jparsec.Scanners.* 

    import org.codehaus.jparsec.functors.Map as FMap 
    import org.codehaus.jparsec.functors.Map4 as FMap4 
    import org.codehaus.jparsec.functors.Map3 as FMap3 
    import org.codehaus.jparsec.functors.Map2 as FMap2 

    /** 
    * Uses jparsec combinator parser library to construct an external DSL parser for the following grammar: 
    * <pre> 
    *  pipeline := routingStep* 
    *  routingStep := IDENTIFIER '(' parameters? ')' 
    *  parameters := parameter (',' parameter)* 
    *  parameter := (IDENTIFIER | QUOTED_STRING) ':' QUOTED_STRING 
    * </pre> 
    */ 
    class PipelineParser { 
     //======================================================= 
     //Pass 1: Define which terminals are part of the grammar 
     //======================================================= 
     //operators 
     private static def OPERATORS = operators(',', '(', ')', ':') 
     private static def LPAREN = OPERATORS.token('(') 
     private static def RPAREN = OPERATORS.token(')') 
     private static def COLON = OPERATORS.token(':') 
     private static def COMMA = OPERATORS.token(',') 

     //identifiers tokenizer 
     private static def IDENTIFIER = Identifier.TOKENIZER 
     //single quoted strings tokenizer 
     private static def SINGLE_QUOTED_STRING = StringLiteral.SINGLE_QUOTE_TOKENIZER 

     //======================================================= 
     //Pass 2: Define the syntax of the grammar 
     //======================================================= 
     //PRODUCTION RULE: parameter := (IDENTIFIER | QUOTED_STRING) ':' QUOTED_STRING 
     @SuppressWarnings("GroovyAssignabilityCheck") 
     private static def parameter = sequence(or(Identifier.PARSER,StringLiteral.PARSER), COLON, StringLiteral.PARSER, new FMap3() { 
      def map(paramName, colon, paramValue) { 
       new Parameter(name: paramName, value: paramValue) 
      } 
     }) 

     //PRODUCTION RULE: parameters := parameter (',' parameter)* 
     @SuppressWarnings("GroovyAssignabilityCheck") 
     private static def parameters = sequence(parameter, sequence(COMMA, parameter).many(), new FMap2() { 
      def map(parameter1, otherParameters) { 
       if (otherParameters != null) { 
        [parameter1, otherParameters].flatten() 
       } else { 
        [parameter1] 
       } 
      } 
     }) 

     //PRODUCTION RULE: routingStep := IDENTIFIER '(' parameters? ')' 
     @SuppressWarnings("GroovyAssignabilityCheck") 
     private static def routingStep = sequence(Identifier.PARSER, LPAREN, parameters.optional(), RPAREN, new FMap4() { 
      def map(routingStepName, lParen, parameters, rParen) { 
       new RoutingStep(
        name: routingStepName, 
        parameters: parameters ?: [] 
       ) 
      } 
     }) 

     //PRODUCTION RULE: pipeline := routingStep* 
     @SuppressWarnings("GroovyAssignabilityCheck") 
     private static def pipeline = routingStep.many().map(new FMap() { 
      def map(from) { 
       new Pipeline(
        routingSteps: from 
       ) 
      } 
     }) 

     //Combine the above tokenizers to create the tokenizer that will parse the stream and spit out the tokens of the grammar 
     private static def tokenizer = or(OPERATORS.tokenizer(), SINGLE_QUOTED_STRING, IDENTIFIER) 

     //This parser will be used to define which input sequences need to be ignored 
     private static def ignored = or(JAVA_LINE_COMMENT, JAVA_BLOCK_COMMENT, WHITESPACES) 

     /** 
     * Parser that is used to parse extender pipelines. 
     * <pre> 
     *  def parser=PipelineParser.parser 
     *  Pipeline pipeline=parser.parse(pipelineStr) 
     * </pre> 
     * Returns an instance of {@link Pipeline} containing the AST representation of the parsed string. 
     */ 
     //Create a syntactic pipeline parser that will use the given tokenizer to parse the input into tokens, and will ignore sequences that are matched by the given parser. 
     static def parser = pipeline.from(tokenizer, ignored.skipMany()) 
    } 
+0

ありがとうございます。私はこの方向を見始めると、それは最善の解決策のように見えます。はい、groovyを使ってアプリケーションエンジンにサンドボックスをセットアップすることは可能です。このプロジェクトがやっていることです:http://groovyconsole.appspot.com/ファイルを削除しようとすると、セキュリティの例外が発生します! –

1

いくつかの考えは:

  • あなたはJavaScriptやGroovyのを使用するかどうか、それはあなたがスクリプトに提供コンテキストで実行されるので、スクリプトがそうしないものにアクセスできないようにする必要があり(もちろん、このルートに行くかどうかを確認するために広範にテストする必要があります)。

  • 可能であれば、実行可能コードではなく、データとして指定されたフィルタ式を使用することで、より安全になるでしょう。もちろん、これはフィルターの式がどの程度複雑であるかによって異なります。おそらく、その表現をフィールド、コンパレータ、値などのようなものに分解して、データとして扱い、定期的に評価することができますか?

  • スクリプト言語を使用してユーザーが注入できることについて心配している場合は、おそらくJavaScriptでより安全です。私はパフォーマンスが問題になるはずはないと思っていますが、もう一度、広範なテストをお勧めします。

+0

確かに[the SecureASTCustomizer'](http://www.jroller.com/melix/entry/customizing_groovy_compilation_process )、Groovyはより安全ではないにしても安全です(少なくともカスタマイズ可能です)? –

0

私は、ユーザー入力で任意のコードを聞かせていないだろうが。それは脆弱で、安全ではなく、悪いユーザーエクスペリエンスです。あなたのユーザーについては何も知らず、質問に答えるのに多くの時間を費やすというのが私の推測です。あなたのフィルタのほとんどがシンプルならば、その代わりに少しのフィルタビルダーを作成してみましょう。

groovyとJavaScriptの間では、Groovyは理解しやすく、スクリプティングには優れていると思いますが、それは私の意見です。

関連する問題