12

クライアント(ブラウザー)とサーバー(Java Rhinoコンテキスト内)の両方で実行されるJavaScript関数がいくつかあります。これらは小さな関数であり、基本的には明確に定義され、グローバルやクロージャに依存しない小さなバリデーターであり、自己完結型で移植性があります。

次に例を示します。

function validPhoneFormat(fullObject, value, params, property) {
    var phonePattern = /^\+?([0-9\- \(\)])*$/;
    if (value && value.length && !phonePattern.test(value))
        return [ {"policyRequirement": "VALID_PHONE_FORMAT"}];
    else
        return [];
}

物事をドライに保つために、私のサーバーコードはこれらの各関数のハンドルを取得し、それらに対してtoString()を呼び出して、JSONオブジェクトの一部としてブラウザーに返します。このようなもの:

      { "name" : "phoneNumber",
        "policies" : [ 
            { "policyFunction" : "\nfunction validPhoneFormat(fullObject, value, params, property) {\n    var phonePattern = /^\\+?([0-9\\- \\(\\)])*$/;\n    if (value && value.length && !phonePattern.test(value)) {\n        return [{\"policyRequirement\":\"VALID_PHONE_FORMAT\"}];\n    } else {\n        return [];\n    }\n}\n"
            }
          ]
      }

次に、私のブラウザのJSコードはこの応答を受け取り、そのコンテキストでこの関数のインスタンスを次のように作成します。

eval("var policyFunction = " + this.policies[j].policyFunction);

policyFailures = policyFunction.call(this, form2js(this.input.closest("form")[0]), this.input.val(), params, this.property.name));

これはすべて非常にうまく機能します。ただし、このコードをJSLintで実行すると、次のメッセージが返されます。

[エラー]ValidatorsManager.js:142:37:evalは悪です。

多くの場合、evalは危険な場合があることを理解しています。しかし、それを使わずにそのようなメカニズムを他にどのように実装できるかはわかりません。これを実行し、JSLintバリデーターを通過させる方法はありますか?

4

7 に答える 7

13

これらの関数文字列をサーバーからクライアントに渡すだけであり、評価されるものを制御できるため、私はそれについて心配しません。

一方、逆の方向に進み、クライアントから渡されたコードの評価をサーバー上で行う場合、それはまったく別の話になります...

アップデート:

コメントで検証オプションを無効にすると、将来のエラーを見逃す可能性があるため、関数全体ではなく関数名を渡し、関数ライブラリをサーバーとクライアントにミラーリングすることをお勧めします。したがって、関数を呼び出すには、次のコードを使用します。

var policyFunction = YourLibraryName[this.policies[j].policyFunctionName];
var policyArguments = this.policies[j].policyArguments;

policyFunction.apply(this, policyArguments); 

更新 2:

JSLint を使用して次のコードを正常に検証できました。これにより、必要に応じて非常に少数のケースで検証を「無効にする」ことができますeval。同時に、JSLint は引き続き通常のeval呼び出しを検証します。このメソッドを使用する場合はすべて、将来の開発者がこのメソッドを使用しないようにするためのフラグをスローする必要があります。

var EVAL_IS_BAD__AVOID_THIS = eval;
EVAL_IS_BAD__AVOID_THIS(<yourString>);
于 2012-10-30T20:51:56.423 に答える
5

関数をJSONの文字列としてエンコードしないでください。JSONは、動作と混同しているコンテンツ用です。

代わりに、実際の関数を許可するJSファイルを返すことができると思います。

 { name : "phoneNumber",
    policies : [ 
        { policyFunction : function() {
              whateverYouNeed('here');
          }
        }
      ]
  }

しかし、それは技術的な問題を解決しますが、それでも素晴らしいアイデアではありません。


ここでの本当の解決策は、ロジックをコンテンツから完全に移動することです。dataType小さな検証関数でいっぱいのJSファイルをインポートし、JSONなどのプロパティに基づいて必要に応じて呼び出します。この機能があなたが言うように小さくて移植可能であるならば、これは達成するのが簡単であるはずです。

データをすべてコードと絡ませることは、通常、苦痛につながります。JSを静的にインクルードしてから、静的にインクルードされたコードを実行するためにJSONデータを動的にリクエスト/インポート/クエリする必要があります。

于 2012-10-30T20:58:20.587 に答える
4

すべての状況で eval を使用することは避けます。コーディングできない理由はありません。コードをクライアントに送信する代わりに、1 つの含まれているスクリプト ファイルでサーバー上にホストされたままにします。

それができない場合は、動的に生成された JavaScript ファイルを作成し、応答を介して必要なパラメーターを渡し、クライアント側でスクリプトを動的にロードすることもできます。eval を使用する理由はまったくありません。

それが役立つことを願っています。

于 2012-10-30T20:57:32.160 に答える
1

ごくわずかな解析で、次のようにすることができました。

var body = this.policies[j].policyFunction.substr;
body = body.substr(body.indexOf("(") + 1);
var arglist = body.substr(1, body.indexOf(")"));
body = body.substr(arglist.length + 1);
var policyFunction = new Function(arglist, body);

これは少しの検証を提供し、文字通りの使用を避け、evalコードと同期して動作します。しかし、それは確かevalに変装しており、XSS 攻撃を受けやすいです。悪意のある人がこの方法でコードをロードして評価できる場合、あなたを救うことはできません。だから、本当に、それをしないでください。適切な URL のタグを追加する<script>と、確実に安全になります。そうですね、申し訳ありませんが安全です。

PS。上記のコードが機能しない場合はお詫び申し上げます。意図を示すだけで、テストしていません。また、括弧の数え方などを間違えた場合はお詫びします。それはどうしても。

于 2012-10-30T22:20:01.497 に答える
1

使用できます

setInterval("code to be evaluated", 0);

内部的には、setInterval に文字列を渡すと、eval() と同様の関数が実行されます。

しかし、私はそれについて心配しません。eval() が悪であることを知っていて、適切な予防策を講じていれば、実際には問題にはなりません。Eval は GoTo に似ています。それらを適切に使用するには、注意して何をしているのかを認識しておく必要があります。

于 2012-10-30T20:52:10.217 に答える
0

最初に心に留めておくべきことは、jsLint は「気分を害する」ということを強調していることです。ベスト プラクティスに従っていない箇所を指摘するように設計されていますが、完璧ではないコードでも問題なく動作する可能性があります。jsLint のアドバイスに従う必要はありません。

そうは言っても、eval悪であり、事実上すべての場合において、常にそれを回避する方法があります。

この場合、require.js、yepnope.js、またはスクリプトを個別にロードするように設計されたその他のライブラリなどのライブラリを使用できます。これにより、動的に必要な JavaScript 関数を含めることができますが、必要はありませんeval()

おそらく他にもいくつかの解決策があるでしょうが、それが私の頭に浮かんだ最初の解決策でした。

それが役立つことを願っています。

于 2012-10-30T20:55:05.477 に答える