¿Es segura esta metodología de firma?

1

Estoy trabajando en la autenticación de mi JSON-RPC API y mi estrategia de trabajo actual es usar solicitudes firmadas enviadas a través de POST sobre SSL .

Me pregunto si alguien puede ver alguna vulnerabilidad que no haya tenido en cuenta con el siguiente método de firma.

Todas las comunicaciones entre el cliente y el servidor se realizan a través de las solicitudes POST enviadas a través de SSL . Las solicitudes inseguras de http son denegadas directamente por el servidor de la API.

Dependencias

var uuid = require('node-uuid');
var crypto = require('crypto');
var moment = require('moment');
var MyAPI = require('request-json').newClient('https://api.myappdomain.com');

Vars

var apiVersion = '1.0';
var publicKey = 'MY_PUBLIC_KEY_UUID';
var secretKey = 'MY_SECRET_KEY_UUID';

Solicitar objeto

var request = {
    requestID : uuid.v4(),
    apiVersion : apiVersion,
    nonce : uuid.v4(),
    timestamp : moment.utc( new Date() ),
    params : params
}

Firma

var signature = crypto.createHmac('sha512',secretKey).update(JSON.stringify(request)).digest('hex');

Empaque de carga útil (Enviado como texto claro a través de POST a través de TLS)

var payload = {
    request: request,
    publicKey : publicKey,
    signature : signature
}

Solicitud POST

MyAPI.post('/', payload, function(error, response, body){
    console.log(result);
});

Carga útil resultante

{
  "request" : {
    "requestID" : "687de6b4-bb02-4d2c-8d3a-adeacd2d183e",
    "apiVersion" : "1.0",
    "nonce" : "eb7e4171-9e23-408a-aa2b-cd437a78af22",
    "timestamp" : "2014-05-23T01:36:52.225Z",
    "params" : {
      "class" : "User"
      "method" : "getProfile",
      "data" : {
        "id" : "SOME_USER_ID"
      }
    }
  },
  "publicKey" : "PUBLIC_KEY",
  "signature" : "7e0a06b560220c24f8eefda1fda792e428abb0057998d5925cf77563a20ec7b645dacdf96da3fc57e1918950719a7da70a042b44eb27eabc889adef95ea994d1",
}

Server-Side

Y luego, en el lado del servidor, ocurre lo siguiente para autenticar la solicitud:

  1. PUBLIC_KEY se utiliza para buscar el SECRET_KEY en la base de datos.
  2. SECRET_KEY se usa para crear un HMAC del objeto request a partir de la carga útil.
  3. El hash enviado en la carga útil se compara con el hash creado en el servidor. Si coinciden, el PUBLIC_KEY se autentica.
  4. El timestamp se evalúa y la autenticación se rechaza si la solicitud es demasiado antigua; de lo contrario, la marca de tiempo se autentica.

Según tengo entendido, este es un método seguro para firmar y autenticar solicitudes enviadas a través de SSL . ¿Esto es correcto?

Gracias de antemano por cualquier ayuda.

    
pregunta AJB 23.05.2014 - 04:07
fuente

1 respuesta

1

Una pregunta que quizás quiera considerar es por qué cree que las solicitudes firmadas son necesarias si todas las API son solo SSL. SSL proporciona tanto tamper como amp; volver a reproducir la protección, por lo que, a menos que tenga otras inquietudes, esto puede ser redundante.

Aunque planeas usar SSL en todas partes, ¡es genial! Mis comentarios a continuación exploran la posibilidad de que no haya SSL en uso.

1 - URL & HTTP Verb no está firmado

En su muestra anterior, el destino previsto de la carga útil no se incluye en la firma de la carga útil. Considere si la carga útil podría ser capturada, podría ser redirigida a otra ubicación no deseada. Quizás una solicitud destinada a ser enviada a / users / 123 se enrute a / users / 456, o una solicitud enviada a 'v1.api.mysite.com' se envíe a 'v2.api.mysite.com', o un POST se cambia a un PATCH.

2 - Soporte de desplazamiento de teclas

Esto puede estar fuera del alcance de su pregunta, pero no veo soporte para lanzar la clave de firma sin la posibilidad de un impacto en el cliente. Sería ventajoso si su servicio pudiera mantener dos secretos autorizados para una identificación pública determinada. De esta manera, la llave podría rotarse regularmente (por ejemplo, por precaución) sin una estrecha coordinación entre el cliente y el cliente; servicio.

3 - Firmando 'Agility'

¿Qué sucede con su aplicación si se encuentra una nueva debilidad en SHA2 o en la construcción actual de HMAC? ¿Qué sucede si tiene un cliente que prefiere usar ECDSA sobre HMAC? Considere tener un número de versión o un identificador de 'esquema' de firma como parte de la carga útil firmada. De esta manera, su servicio puede comprender qué enfoque ha utilizado el cliente para firmar la carga útil.

4 - Demasiado viejo

Usted menciona en su publicación que el servicio puede rechazar solicitudes que son demasiado antiguas (para mitigar los ataques de repetición). ¿Qué pasa si el cliente no está de acuerdo con su definición de demasiado viejo? Considere permitir que el cliente especifique qué edad es demasiado antigua en la carga útil firmada. Nuevamente, esto no es tanto una debilidad en su enfoque al generar firmas, sino más bien un comentario sobre el protocolo en general.

5 - Otras liendres

  • El campo 'nonce' parece redundante. Ya tienes un GUID aleatorio que sirve como ID de solicitud, a menos que tu servicio requiera el nonce, esto se puede eliminar de forma segura.

  • Dependiendo de su analizador JSON (& cómo / cuándo se deseraliza), es posible que esto no detecte todas las modificaciones a su carga útil. Por ejemplo, si modifico la carga útil para escapar de un personaje que no requiere escape, el resultado es semánticamente equivalente. Debido a que está deseralizando el JSON antes de verificar si se ha modificado, puede ser vulnerable a los ataques que intentan explotar su deseralizador, o ataques dirigidos a errores sutiles en la forma en que se manejan los personajes escapados.

Pero, por último, repito lo que dije anteriormente: la firma de su solicitud puede ser redundante cuando solo admite SSL como transporte. Simplemente autenticar a su interlocutor puede ser suficiente.

    
respondido por el Tails 24.05.2014 - 18:18
fuente

Lea otras preguntas en las etiquetas