Pertanyaan Java dan XSS: Bagaimana cara html melepaskan string JSON untuk melindungi terhadap XSS?


Di Java, kita punya beberapa kode yang mengambil objek java yang kompleks dan membuat serial ke json. Ia kemudian menulis bahwa json langsung ke markup halaman, dalam tag skrip, menugaskannya ke variabel.

// Get object as JSON using Jackson
ObjectWriter jsonWriter = new ObjectMapper().writer().withDefaultPrettyPrinter();
String json = jsonWriter.writeValueAsString(complexObject);

// Write JSON out to page, and assign it to a javascript variable.
Writer out = environment.getOut();
out.write("var data = " + json);

Objek yang kompleks dapat memiliki konten pengguna akhir di dalamnya, yang dapat membuka kita untuk serangan XSS.

Bagaimana saya bisa mendapatkan versi json dari objek java kompleks yang masing-masing memiliki atribut json HTML lolos, untuk melindungi terhadap injeksi XSS?

Saya sudah membaca OWASP XSS Guide dan yang terbaik yang saya miliki sejauh ini adalah ini, yang HTML luput dari seluruh string JSON, kemudian membatalkan kutipan, sehingga dapat ditetapkan ke variabel dalam javascript. Saya yakin ada cara yang lebih baik untuk melakukan ini, tetapi ini sepertinya berhasil. Ada saran?

private String objectToHtmlEscapedJson(Object value) {
    try {
        String result = jsonWriter.writeValueAsString(value);
        result = StringEscapeUtils.escapeHtml(result);
        result = result.replace(""", "\"");
        return result;
    } catch (JsonProcessingException e) {
        return "null";
    }
}

4
2018-06-14 12:31


asal


Jawaban:


Sebuah pendekatan yang mungkin bisa untuk iterate atas entri objek dan secara individual melepaskan setiap kunci dan nilai setelah node dibangun oleh perpustakaan pilihan Anda.

Mengikuti komentar saya di atas, saya telah menerapkan solusi rekursif sederhana menggunakan keduanya Jackson (dari pertanyaan Anda) dan GSON, perpustakaan yang berbeda di mana objek sedikit lebih mudah untuk dibangun dan kode lebih mudah dibaca. Mekanisme melarikan diri yang digunakan adalah OWASP Java Encoder:

Jackson

private static JsonNode clean(JsonNode node) {
    if(node.isValueNode()) { // Base case - we have a Number, Boolean or String
        if(JsonNodeType.STRING == node.getNodeType()) {
            // Escape all String values
            return JsonNodeFactory.instance.textNode(Encode.forHtml(node.asText()));
        } else {
            return node;
        }
    } else { // Recursive case - iterate over JSON object entries
        ObjectNode clean = JsonNodeFactory.instance.objectNode();
        for (Iterator<Map.Entry<String, JsonNode>> it = node.fields(); it.hasNext(); ) {
            Map.Entry<String, JsonNode> entry = it.next();
            // Encode the key right away and encode the value recursively
            clean.set(Encode.forHtml(entry.getKey()), clean(entry.getValue()));
        }
        return clean;
    }
}

GSON

private static JsonElement clean(JsonElement elem) {
    if(elem.isJsonPrimitive()) { // Base case - we have a Number, Boolean or String
        JsonPrimitive primitive = elem.getAsJsonPrimitive();
        if(primitive.isString()) {
            // Escape all String values
            return new JsonPrimitive(Encode.forHtml(primitive.getAsString()));
        } else {
            return primitive;
        }
    } else { // Recursive case - iterate over JSON object entries
        JsonObject obj = elem.getAsJsonObject();
        JsonObject clean = new JsonObject();
        for(Map.Entry<String, JsonElement> entry :  obj.entrySet()) {
            // Encode the key right away and encode the value recursively
            clean.add(Encode.forHtml(entry.getKey()), clean(entry.getValue()));
        }
        return clean;
    }
}

Contoh masukan (kedua pustaka):

{
    "nested": {
        "<html>": "<script>(function(){alert('xss1')})();</script>"
    },
    "xss": "<script>(function(){alert('xss2')})();</script>"
}

Contoh keluaran (kedua pustaka):

{
    "nested": {
        "&lt;html&gt;": "&lt;script&gt;(function(){alert(&#39;xss1&#39;)})();&lt;/script&gt;"
    },
    "xss": "&lt;script&gt;(function(){alert(&#39;xss2&#39;)})();&lt;/script&gt;"
}

3
2018-06-15 08:35



kupikir Jawaban Paul Benn adalah pendekatan terbaik secara keseluruhan, tetapi jika Anda tidak ingin beralih ke node json, Anda dapat mempertimbangkan untuk menggunakannya Encode.forHtmlContent, yang tidak luput dari kutipan. Saya merasa ini mungkin aman karena saya tidak bisa memikirkan bagaimana memperkenalkan kutipan tambahan ke string yang dikutip dapat menyebabkan eksploit. Saya akan serahkan kepada pembaca untuk meninjau dokumen dan memutuskan sendiri!

ivy.xml

<dependency org="org.owasp.encoder" name="encoder" rev="1.2.1"/>

dan beberapa kode untuk melakukan pengkodean html

private String objectToJson(Object value)
{
    String result;
    try
    {
        result = jsonWriter.writeValueAsString(value);
        return Encode.forHtmlContent(result);
    }
    catch (JsonProcessingException e)
    {
        return "null";
    }
}

1
2018-06-18 12:05