Pregunta

La siguiente pregunta es más complejo de lo que puede parecer.

asumir que Tengo un objeto JSON arbitraria, uno que pueda contener cualquier cantidad de datos incluidos otros objetos JSON anidados. Lo que quiero es un hash criptográfico / Recopilación de los datos JSON, sin tener en cuenta el JSON real de formato en sí (por ejemplo: haciendo caso omiso de las nuevas líneas y el espaciamiento diferencias entre el JSON tokens).

La última parte es un requisito, como se generará / leído por una variedad de (de) serializadores en una serie de diferentes plataformas de la JSON. Sé de al menos una biblioteca JSON para Java que elimina por completo el formato al leer los datos durante la deserialización. Como tal, se romperá el hash.

La cláusula de datos arbitrarios anterior también complica las cosas, ya que me impide tomar campos conocidos en un orden dado y la concatenación de ellos antes de Hasing (piensa más o menos cómo hashCode no criptográfica de Java () funciona el método).

Por último, hashing todo el JSON cadena como un trozo de bytes (antes de deserialización) tampoco es deseable, ya que hay campos en el JSON que deben ser ignorados cuando se calcula el hash.

No estoy seguro de que es una buena solución a este problema, pero la bienvenida a cualquier enfoque o pensamientos =)

¿Fue útil?

Solución

El problema es común cuando se calculan valores hash para cualquier formato de datos donde se permite la flexibilidad. Para solucionar esto, es necesario canonicalize la representación.

Por ejemplo, el protocolo OAuth1.0a, que se utiliza por Twitter y otros servicios para la autenticación, requiere un control seguro del mensaje de solicitud. Para calcular el hash, OAuth1.0a dice que necesita a primera alfabetizar los campos, a diferenciarlos por saltos de línea, eliminar los nombres de campo (que son bien conocidos), y el uso de líneas en blanco para valores vacíos. La firma o de hash se calcula sobre el resultado de ese canónicos.

XML DSIG funciona de la misma manera - que necesita para canonicalize el XML antes de firmarlo. Hay una propuesta W3 tipo sobre este , porque es un requisito fundamental para firma. Algunas personas lo llaman C14N.

No sé de una norma canónicos para JSON. Vale la pena investigar.

Si no hay uno, que sin duda puede establecer una convención para su uso de la aplicación en particular. Un comienzo razonable podría ser:

  • lexicográfico ordenar las propiedades de nombre
  • comillas dobles se utilizan en todos los nombres
  • comillas dobles se utilizan en todos los valores de cadena
  • ningún espacio, o un espacio, entre los nombres y el colon, y entre los dos puntos y el valor
  • sin espacios entre los valores y la siguiente coma
  • cualquier otro espacio en blanco se derrumbó ya sea a un solo espacio o nada - elige uno
  • excluir cualquier propiedad que no desea firmar (un ejemplo es la propiedad que tiene la firma en sí)
  • firmar el resultado, con su algoritmo
  • elegido

También puede que quiera pensar acerca de cómo pasar esa firma en el objeto JSON - posiblemente establecer un nombre de propiedad bien conocida, como "Nichols-hmac" o algo así, que obtiene los base64 versión del hash codificado. Esta propiedad tendría que ser excluido explícitamente por el algoritmo de hash. Entonces, cualquier receptor de la JSON sería capaz de comprobar el hash.

La representación canónica no tiene por qué ser la representación se pasa alrededor de la aplicación. Sólo necesita ser producido fácilmente dado un objeto JSON arbitraria.

Otros consejos

En lugar de inventar su propio JSON normalización / canónicos es posible que desee utilizar bencode . Semánticamente es la misma como JSON (composición de los números, cadenas, listas y dicts), pero con la característica de codificación inequívoca de que es necesario para hash criptográfica.

bencode se utiliza como un formato de archivo torrent, cada cliente bittorrent contiene una implementación.

Este es el mismo problema que causa problemas con firmas S / MIME y las firmas XML. Es decir, hay múltiples representaciones equivalentes de los datos a firmar.

Por ejemplo, en JSON:

{  "Name1": "Value1", "Name2": "Value2" }

vs.

{
    "Name1": "Value\u0031",
    "Name2": "Value\u0032"
}

O dependiendo de su aplicación, esto puede incluso ser equivalentes:

{
    "Name1": "Value\u0031",
    "Name2": "Value\u0032",
    "Optional": null
}

Canonicalización podría resolver ese problema, pero es un problema que no es necesario en absoluto.

La solución fácil si usted tiene el control sobre la especificación es envolver el objeto en algún tipo de contenedor para protegerlo de ser transformado en una representación "equivalente" pero diferente.

es decir. evitar el problema al no firmar el objeto "lógico", pero la firma de una representación en serie particular de su lugar.

Por ejemplo, JSON Objetos -> texto UTF-8 -> Bytes. Firmar los bytes como bytes , a continuación, transmitir ellos como bytes por ejemplo, por la codificación Base64. Puesto que usted está firmando los bytes, las diferencias como espacios en blanco son parte de lo que está firmado.

En lugar de tratar de hacer esto:

{  
   "JSONContent": {  "Name1": "Value1", "Name2": "Value2" },
   "Signature": "asdflkajsdrliuejadceaageaetge="
}

Sólo hacer esto:

{
   "Base64JSONContent": "eyAgIk5hbWUxIjogIlZhbHVlMSIsICJOYW1lMiI6ICJWYWx1ZTIiIH0s",
   "Signature": "asdflkajsdrliuejadceaageaetge="

}

es decir. no firme el JSON, signo los bytes de la codificada JSON.

Sí, esto significa que la firma ya no es transparente.

JSON-LD puede hacer normalitzation.

Se tendrá que definir su contexto.

RFC 7638: JSON Web Key (JWK) Huella digital incluye un tipo de canonización. Aunque RFC7638 espera un conjunto limitado de miembros, que sería capaz de aplicar el mismo cálculo para cualquier miembro.

https://tools.ietf.org/html/rfc7638#section-3

Me haría todos los campos en un orden determinado (alfabéticamente por ejemplo). ¿Por qué arbitrarias de datos marcan una diferencia? Usted puede simplemente repetir las propiedades de reflexión (ALA).

Alternativamente, Me gustaría ver en la conversión de la cadena JSON en bruto en una cierta forma canónica bien definido (quitar todo el formato superflous) -. Y hash que

Nos encontramos con un problema sencillo con hash cargas útiles codificados en JSON. En nuestro caso utilizamos la metodología siguiente:

  1. los datos se convierten en objeto JSON;
  2. Codificar JSON carga útil en base 64
  3. Mensaje digest (HMAC) la carga útil base64 generado.
  4. carga útil de base 64
  5. Transmisión.

Ventajas del uso de esta solución:

  1. Base64 producirá la misma salida para una carga útil dada.
  2. Desde la firma resultante se deriva directamente de la carga útil codificado en base 64 y desde base64-carga útil será intercambiada entre los puntos extremos, vamos a estar seguros de que la firma y la carga útil se mantendrán.
  3. Esta solución resuelve los problemas que surgen debido a la diferencia en la codificación de caracteres especiales.

Desventajas

  1. La codificación / decodificación de la carga útil puede agregar una sobrecarga
  2. datos codificados en Base64
  3. es normalmente 30 +% más grande que la carga útil originales.
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top