0

URL を正規表現と照合して、「シャットダウン」コマンドを反映しているかどうかをテストしています。

シャットダウンを実行する URL は次のとおりです。

/exec?debug=true&command=shutdown&f=0

これは、シャットダウンを実行する別の、正当ではあるが紛らわしい URL です。

/exec?commando=yes&zcommand=34&command=shutdown&p

ここで、 command=...パラメータが1 つしかなく、それがcommand=shutdownであることを確認する必要があります。または、最初の command=...パラメータがcommand=shutdownであることを確認して生きることもできます。

要求された正規表現のテストは次のとおりです。

/exec?version=0.4&command=shutdown&out=JSON&zcommand=1

一致する必要があります

/exec?version=0.4&command=startup&out=JSON&zcommand=1&commando=shutdown

一致しないはずです

/exec?command=shutdown&out=JSON

一致する必要があります

/exec?version=0.4&command=admin&out=JSON&zcommand=1&command=shutdown

一致しないはずです

これが私のベースラインです-上記のテストに合格する正規表現-最後のものを除くすべて:

^/exec?(.*\&)*command=shutdown(\&.*)*$

問題は、複数の command=... が発生することです。最初のコマンドはシャットダウンされません。

私は後読みを使用してみました:

^/exec?(.*\&)*(?<!(\&|\?)command=.*)command=shutdown(\&.*)*$

しかし、私は得ています:

Look-behind group does not have an obvious maximum length near index 31

アトミックグループ化も試しました。無駄に。次の式を NOT マッチにすることはできません:

/exec?version=0.4&command=admin&out=JSON&zcommand=1&command=shutdown

すべてのテストに合格する正規表現を手伝ってくれる人はいますか?

明確化

私はあなたにいくつかの文脈を借りていることがわかりました。

私の仕事は、システムのすべてのサーブレットの入り口を保護し、開いている HTTP セッションがある (つまり、ログインが成功したことを確認する) フィルターを構成することです。フィルタを使用すると、ログインを必要としない URL を構成することもできます。

いくつかの例外は簡単です: /login はログインを必要としません。localhost への呼び出しにはログインは必要ありません。

しかし、複雑になることもあります。他のコマンドはログインを要求できますが、ログインを要求できない shutdown コマンドのように (その奇妙な理由は私の質問の範囲外です)。

これはセキュリティ上の問題であるため、ユーザーが単に &command=shutdown を URL に追加してフィルターをバイパスすることを許可することはできません。

したがって、正規表現が本当に必要です。そうしないと、構成仕様を再定義する必要があります。

4

8 に答える 8

1

複数の手順でそれを行う必要があります。

(1)一致するものを探す^(?=\/exec\?).*?(?<=[?&])command=([^&]+)

(2)一致するかどうかを確認しますshutdown

于 2012-10-05T16:27:12.157 に答える
1

Ok。素晴らしい回答をありがとうございました!私はいくつかの提案を試し、他のものと格闘しましたが、全体として、適切な正規表現が存在したとしても、それはひどいものに見え、保守できず、厄介な大学の演習としてはうまく機能する可能性があることに同意する必要がありますが、実際のシステムではそうではありません構成。

また、ここにはフィルターが含まれており、フィルターは既に独自の URI を解析しているため、すべての URI 部分を文字列に貼り付けて正規表現と照合するのはまったくばかげていることにも気付きました。私が考えていたことは何でしょう??

したがって、フィルターとその構成を再設計します。

どうもありがとう、人々!私は助けに感謝します:)

ノーム・ロテム。

PS - userXXXX ニックネームを取得したのはなぜですか? 非常に奇妙な...

于 2012-10-06T23:24:58.360 に答える
0

最初の一致を受け入れるだけで十分な場合は'\\Wcommand=([^&]+)、最初のグループを使用してフェッチすることができます。

それ以外の場合は、2 回呼び出しMatcher.findて後続の一致をテストし、最終的に最初の一致を使用することができますが、なぜ単一の複雑な正規表現でこれを行う必要があるのでしょうか?

于 2012-10-05T16:40:44.167 に答える
0

これが単一の正規表現で実行できる場合は、そうなる可能性があります。複雑すぎて判読不能になり、ロジックの意図が失われるため保守できなくなります。それが「文書化」されていたとしても、Java を知っているだけの人にとっては、それほど明白ではありません。

このような問題を解決することは、ハンマーでねじを打ち込むことがハンマーとねじの両方を悪用するのと同様に、正規表現の乱用です。

はるかに優れたアプローチは、URIオブジェクト全体、ドメイン、およびすべてを解析し、クエリ パラメーターを取得してから、それらをウォークスルーし、ビジネス ロジックに基づいてシャットダウンとそうでないものを決定する単純なループを作成することです。 . そうすれば、それは単純で、自己文書化され、おそらくより効率的になります (それは問題ではありません)。

問題に直面したときに、「分かった、正規表現を使用する」と考える人もいます。現在、彼らには 2 つの問題があります。-- ジェイミー・ザウィンスキー

反対票を投じてください。ただし、この特定の例の最善の解決策は正規表現ではありません。「明確化」を考えると、なおさらです。

特に、コードを人々と共有しなければならないビジネス環境では、現在一緒に仕事をするだけでなく、将来の人材プールも未知数です。「受け入れられた」回答は、企業のコードレビューに合格することはありません。ザウィンスキーの言葉は、まさにこの状況に当てはまります!

于 2012-10-05T16:46:31.230 に答える
0

このテスト済み (および完全にコメント済み) の正規表現ソリューションは、すべての要件を満たしています。

import java.util.regex.*;
public class TEST {
    public static void main(String[] args) {
        Pattern re = Pattern.compile(
            "  # Match URI having command=shutdown query variable value. \n" +
            "  ^                          # Anchor to start of string.   \n" +
            "  (?:[^:/?\\#\\s]+:)?        # URI scheme (Optional).       \n" +
            "  (?://[^/?\\#\\s]*)?        # URI authority (Optional).    \n" +
            "  [^?\\#\\s]*                # URI path.                    \n" +
            "  \\?                        # Literal start of URI query.  \n" +
            "    # Match var=value pairs preceding 'command=xxx'.        \n" +
            "  (?:                        # Zero or more 'var=values'    \n" +
            "    (?!command=)             # only if not-'command=xxx'.   \n" +
            "    [^&\\#\\s]*              # Next var=value.              \n" +
            "    &                        # var=value separator.         \n" +
            "  )*                         # Zero or more 'var=values'    \n" +
            "  command=shutdown           # variable and value to match. \n" +
            "    # Match var=value pairs following 'command=shutdown'.   \n" +
            "  (?:                        # Zero or more 'var=values'    \n" +
            "    &                        # var=value separator.         \n" +
            "    (?!command=)             # only if not-'command=xxx'.   \n" +
            "    [^&\\#\\s]*              # Next var=value.              \n" +
            "  )*                         # Zero or more 'var=values'    \n" +
            "  (?:\\#\\S*)?               # URI fragment (Optional).     \n" +
            "  $                          # Anchor to end of string.", 
            Pattern.CASE_INSENSITIVE | Pattern.UNICODE_CASE | Pattern.COMMENTS);
        String s = "/exec?version=0.4&command=shutdown&out=JSON&zcommand=1";
            // Should match
//      String s = "/exec?version=0.4&command=startup&out=JSON&zcommand=1&commando=shutdown";
            // Should fail to match 
//      String s = "/exec?command=shutdown&out=JSON";
            // Should match
//      String s = "/exec?version=0.4&command=admin&out=JSON&zcommand=1&command=shutdown";
        // Should fail to match";
        Matcher m = re.matcher(s);
        if (m.find()) {
            // Successful match
            System.out.print("Match found.\n");
        } else {
            // Match attempt failed
            System.out.print("No match found.\n");
        } 
    }
}

上記の正規表現は、任意のスキーム、権限、パス、クエリ、またはフラグメント コンポーネントを持つ任意の RFC3986 有効な URI と一致しますが"command"、値が正確である必要があるクエリ変数が 1 つ (かつ 1 つだけ) ある必要がありますが、大文字と小文字は区別されません"shutdown"

慎重に作成された複雑な正規表現は、(上記のように) 適切なインデントとコメント付きの手順で記述されていれば、問題なく使用できます (そして保守可能です)。(正規表現を使用して URI を検証する方法の詳細については、私の記事正規表現 URI 検証を参照してください)

于 2012-10-06T00:37:51.800 に答える
0

command=shutdown の最初の出現に一致させるには、次を使用します。

Pattern.compile("^((?!command=).)+command=shutdown.*$");

結果は次のようになります。

"/exec?version=0.4&command=shutdown&out=JSON&zcommand=1" => false
"/exec?command=shutdown&out=JSON" => true
"/exec?version=0.4&command=startup&out=JSON&zcommand=1&commando=shutdown" => false
"/exec?commando=yes&zcommand=34&command=shutdown&p" => false

'command=' を 1 つだけ含む文字列に一致させたい場合は、次のようにします。

Pattern.compile("^((?!command=).)+command=shutdown((?!command=).)+$");

正規表現で「not」修飾子を使用することは意図されたものではなく、パフォーマンスが最適ではない可能性があることに注意してください。

于 2012-10-05T17:32:18.837 に答える
0

私はJavaコーダーではありませんが、これを試してください(Perlで動作します)>>

^(?=\/exec\?)(?:[^&]+(?<![?&]command)=[^&]+&)*(?<=[?&])command=shutdown(?:&|$)
于 2012-10-05T16:50:48.563 に答える
-1

これを試して:

Pattern p = Pattern.compile(
    "^/exec\\?(?:(?:(?!\\1)command=shutdown()|(?!command=)\\w+(?:=[^&]+)?)(?:&|$))+$\\1");

またはもう少し読みやすく:

^/exec\?
(?:
  (?:
    (?!\1)command=shutdown()
    |
    (?!command=)\w+(?:=[^&]+)?
  )
  (?:&|$)
)+$
\1

正規表現の本体は、シャットダウン コマンドまたは名前が ではないパラメータのいずれかに一致する代替ですcommand。シャットダウン コマンドと一致する場合、そのブランチの空のグループは空の文字列を「キャプチャ」します。チェックボックスとしてのみ使用し、パラメータの 1 つがシャットダウンコマンドであることを確認するだけなので、何も消費する必要はありません。

否定先読み - (?!\1)- は、2 つ以上のシャットダウン コマンドに一致することを防ぎます。それが本当に必要かどうかはわかりませんが、(1) 「逆アサーション」を否定する方法と、(2) 特定の状況で参照するグループの前に逆参照を表示できることを示す良い機会です (前方参照として知られています)。

URL 全体が消費されると、後方参照 ( \1) はゼロ幅アサーションのように機能します。パラメータの 1 つが であった場合command=shutdown、後方参照は成功します。そうしないと、参照先のグループが一致に参加していないため、空の文字列との一致のみを試みても失敗します。

しかし、私は他のレスポンダーに同意する必要があります。正規表現がこれほど複雑になったら、別のアプローチに切り替えることを真剣に考えるべきです。


編集: それは私のために働きます。これがデモです。

于 2012-10-05T20:47:03.643 に答える