Sobre la Autenticación


La seguridad de Kamin Ledger se basa en la criptografía asimétrica. Cada registro está protegido por un par de claves pública y privada. Las claves públicas se registran en el ledger y cada operación del libro se verifica comprobando las firmas proporcionadas.

Hay dos tipos principales de solicitudes al ledger: mutaciones y lecturas.

Una mutación representa cualquier tipo de solicitud para almacenar o modificar un registro en el ledger.


Autenticación mediante la firma del cuerpo de una mutación

Las solicitudes de mutación siempre contienen una carga útil diseñada para transmitir toda la información necesaria para realizar la mutación. Por ello, las mutaciones son más directas y seguras. El principal mecanismo de seguridad para las mutaciones está contenido en el arreglo proofs que se proporciona en el objeto meta como parte de la carga útil. Por ejemplo, un cuerpo de solicitud para crear una billetera se ve así:

{
    "hash": "<hash of the data>",
    "data": {
        "handle": "wallet-handle"
    },
    "meta": {
        "proofs": [
            {
                "method": "ed25519-v2",
                "public": "<public key>",
                "result": "<signature of the hash>",
                "digest": "<hash of the data>",
                "custom": {
                    "moment": "2023-02-20T21:42:10.279Z"
                }
            }
        ]
    }
}

Pasos para firmar un objeto como el anterior:

  1. Serializar los datos
  2. Hashear los datos serializados
  3. Firmar el hash con una o más claves privadas

Las claves utilizadas para firmar serán empleadas por el ledger para verificar si está permitido ejecutar la solicitud en cuestión.

Pasos para verificar una mutación entrante:

  1. Serializar los datos
  2. Hashear los datos serializados
  3. Comparar el hash recibido con el hash del payload
  4. Verificar cada firma recibida utilizando las claves públicas del arreglo de firmas y el hash calculado

Si los pasos anteriores se completan exitosamente, esto significa que el payload recibido es válido y que fue enviado por los propietarios de las claves públicas proporcionadas. Todavía es necesario verificar los permisos de esas claves públicas para asegurarse de que están autorizadas a realizar la operación requerida.


Autenticación con token JWT

El mecanismo de firma anterior no funciona para las solicitudes de lectura, ya que son solicitudes GET sin un cuerpo que firmar. En una lectura, la URL, los parámetros de consulta y los encabezados definen lo que devuelve la API, así que no hay carga útil a la cual adjuntar un arreglo proofs. Las lecturas se autentican con un JWT en su lugar.

En Kamin, toda solicitud de lectura requiere un token JWT, enviado en el encabezado Authorization:

Authorization: Bearer <jwt>

El token se valida en cada solicitud: se comprueban su formato, su firma y su expiración.

Estructura del token

Un JWT de Kamin se firma con EdDSA (ed25519). El encabezado nombra la clave de verificación y el algoritmo:

{
    "alg": "EdDSA",
    "kid": "<base64 public key used to verify the signature>"
}
CampoTipoDescripción
algStringAlgoritmo usado para firmar el token.
Solo acepta:
EdDSA
kidStringClave pública en base64 que el ledger usa para verificar la firma del token.

La carga útil lleva los claims estándar:

{
    "iss": "backend",
    "sub": "<public key or handle of the signer>",
    "aud": "<ledger-handle>",
    "iat": 1753130217,
    "exp": 1753133817
}
ClaimTipoDescripción
issStringEmisor: un identificador del cliente.
por ejemplo:
backend
subStringSujeto: la identidad del firmante, ya sea una clave pública o un handle.
audStringAudiencia: el ledger al que está dirigido el token.
por ejemplo:
<ledger-handle>
iatNumberHora de emisión, en segundos desde epoch.
expNumberHora de expiración, en segundos desde epoch. El token se rechaza después de ella.

jti (un id único del token que evita reenvíos) y hsh (un hash sha256 de la solicitud que ata el token a una sola solicitud) también se aceptan, pero son opcionales.

Firmar el token

El cliente posee una clave privada ed25519 cuya clave pública está registrada en el ledger. Para autenticar una lectura:

  1. Construye el encabezado y la carga útil como arriba, con iat en la hora actual y exp poco después.
  2. Firma el header.payload codificado con la clave privada usando EdDSA.
  3. Envía el resultado como Authorization: Bearer <jwt>.

El ledger busca la clave pública a partir de kid, verifica la firma y comprueba exp. Si algún paso falla, la solicitud se rechaza.

Usa el validador de JWT para decodificar un token, inspeccionar su encabezado y sus claims, y verificar su firma contra una clave pública.


Historial de cambios
1.0.1
  • Cambiado Ampliar la sección de autenticación con token JWT para explicar cómo se construye y se firma el token
1.0.0
  • Agregado Versión inicial