5

バックエンドと対話するユーザー向けサービスで構成されたこの単純な JSON システムを見てください。

import java.util.*;
import com.json.parsers.*;
import org.json.simple.*;

class Main{static {
    String s = new java.util.Scanner(System.in).useDelimiter("\\A").next();
    UserFacingService.handleMessage(s);
}}

class UserFacingService {
    static void handleMessage(String s) {
        JSONParser parser = JsonParserFactory.getInstance().newJsonParser();
        Map js = parser.parseJson(s);
        if (commandAllowed(js))
            Backend.handleMessage(s);
        else
            System.out.println("unauthorized!");
    }
    static boolean commandAllowed(Map js) {
        if (js.get("cmd").equals("bad stuff"))
            return false;
        return true;
    }
}

class Backend {
    static void handleMessage(String s) {
        JSONObject js = (JSONObject) JSONValue.parse(s);
        String cmd = (String)js.get("cmd");
        if (cmd.equals("bad stuff")) {
            doBadStuff();
        } else if (cmd.equals("ping")) {
            doPong();
        }
    }
    static void doBadStuff() { System.out.println("doing bad stuff"); }
    static void doPong() { System.out.println("doing pong"); }
}

ユーザー向けサービス ( quick-jsonを使用) は、ユーザーがバックエンド ( json-simpleを使用) に悪いことをさせないようにします。ユーザーをシミュレートするために、stdin from を使用していMainます。実際のシナリオでBackendは、別のサーバーまたは古いレガシー/バイナリ コード上にあるため、Java オブジェクトを受け入れるように単純に変更することはできません。認証は とは別に行う設計になっていBackendます。AdminFacingServiceこれは、管理者のみがアクセスできる別のクラスを作成するかif (userIsAdmin) return true;UserFacingService.commandAllowed.

ご覧のとおり、意図したとおりに動作します。

$ CP=.:json-simple-1.1.1.jar:quick-json-1.0.2.3.jar
$ javac -cp $CP A.java && echo '{"cmd": "ping"}' | java -cp $CP Main
doing pong
Exception in thread "main" java.lang.NoSuchMethodError: main

送信{"cmd": "bad stuff"}すると、ユーザー向けサービスはコマンドを拒否する必要があります。

$ CP=.:json-simple-1.1.1.jar:quick-json-1.0.2.3.jar
$ javac -cp $CP A.java && echo '{"cmd": "bad stuff"}' | java -cp $CP Main
unauthorized!
Exception in thread "main" java.lang.NoSuchMethodError: main

それもうまくいきます。しかし、ユーザーが を送信する{"cmd": "bad\u0020stuff"}と、悪いことが起こります。

$ CP=.:json-simple-1.1.1.jar:quick-json-1.0.2.3.jar
$ javac -cp $CP A.java && echo '{"cmd": "bad\u0020stuff"}' | java -cp $CP Main
doing bad stuff
Exception in thread "main" java.lang.NoSuchMethodError: main

しかし、どのように?ユーザー向けサービスがこれをキャッチしないのはなぜですか?

4

4 に答える 4

2

なるほど。2 つの異なるパーサーを使用しています。もともと私は、これらはさまざまな点で寛大だと思っていました。「ポステルの法則」は UI には最適ですが、プログラミング インターフェイスには危険です。特に、ヘアリー解析は脆弱性を作成するのに最適です。

(もう一度!) RFC4627 を見ると、JSON では \u 表記が有効です。パーサーの 1 つが壊れているようで、データを正しく解釈しません。

通常、解析は 1 回だけです。かなりの数のバグが、複数回の解析に起因します。JSON のデータが再度必要な場合は、明らかに仕様内にあるフォーマッターと対処しなければならないバグのある実装を使用して、抽出して再エンコードします。

興味深いことに、テキスト形式は非常に単純であるはずですが、この種の影響を受けやすいのです。したがって、単純な (ASN.1 ではない) バイナリ形式を優先し、高品質のライブラリを使用してください。


コマンドラインでユーザーデータを使用して毎回新しいプロセスを開始していると誤って想定した元の回答:

これは、JSON の解析とは関係なく、すべてコマンド ラインに入力する内容と関係があります。コマンドラインに信頼できないデータを入れるのは悪い考えです。これは、SQL インジェクション、XSS、LDAP インジェクション、HTTP 要求/応答分割などと同様に、脆弱性の「インジェクション」クラスに属します。これらの脆弱性のほとんどは、タイトなフォーマット ライブラリによって解決できます。コマンド ラインはいたるところにあるため、完全に避けるか、Base64 エンコーディングなどを使用することをお勧めします。

OWASP にはCommand Injectionに関するページがあります。

「Java プログラミング言語バージョン 4.0 のセキュア コーディング ガイドライン」には、ガイドライン 3-4 があります。

(また、リクエストごとに新しい Java プロセスを開始すると、簡単に DoS 攻撃を受けやすくなります。)

于 2013-10-30T22:37:54.803 に答える
2

入力として を使用すると、最初のパーサーはstringを返すbad\u0020stuffオブジェクトjsを返すため、 を返します。2 番目のパーサーは、return のオブジェクトを返します(スペースに変換されます)。したがって、コマンドが実行されます。js.get("cmd")bad\u0020stuffcommandAllowedtruejsjs.get("cmd")bad stuff\u0020bad stuff

最初のパーサーは、Unicode エスケープを解釈しないため、RFC4627 に従っていません。

于 2013-12-08T02:28:54.487 に答える
0

仕様に適切に従っている JSON ライブラリを使用できない場合は...

org.apache.commons3.lang.StringEscapeUtils.unescapeJava(cmd).equals("bad stuff")

この SO の質問を確認してくださいJava で Java 文字列リテラルをエスケープ解除する方法は?

于 2013-11-18T19:45:08.953 に答える