La seguridad de nuestras API: JWT

   Después de este vídeo

Aprenderás a:

  • Distinguir autenticación de autorización.
  • Conocer qué es un Token. 
  • Identificar los conceptos relacionados con JWT, campos y estructura.
  • Diseñar la generación de un Token para la API Escuela Norte.
  • Seguir el paso a paso de los vídeos ¡Aplica ya! para implementar seguridad JWT.

Cursos Institucionales.
El Aprendizaje Hecho Fácil. ¡Disfrútalo!

¿Qué es autenticar?


Tomaremos como base esta definición:

   La autenticación

“Es el acto o proceso de confirmar que algo (o alguien) es quien dice ser.

A la parte que se identifica se le llama probador. A la parte que verifica la identidad se la llama verificador.

Por ejemplo: El probador es nuestro cliente que necesita acceder a un endpoint de nuestra API Escuela Norte. El verificador es nuestro módulo diseñado para autenticarlo verificando que el que accede sea un usuario que tiene permisos para hacer uso de nuestros recursos. Para poder tener autenticación es necesaria, como condición previa, la existencia de identidades biunívocamente identificadas de tal forma que se permita su identificación.  Wikipedia

¿Qué es un Token?


   El Token —referencia (un identificador) 

Un token de software es un token de seguridad digital para sistemas de autenticación de dos factores. 

La tokenización es el proceso de reemplazar datos confidenciales con símbolos de identificación únicos que retienen toda la información esencial sobre los datos sin comprometer su seguridad.

“Un token JWT generalmente contiene un cuerpo con información sobre el usuario autenticado (identificador de sujeto, reclamos, etc.), el emisor del token, la audiencia (destinatario) al que está destinado el token y un tiempo de vencimiento (después del cual el token es inválido). El token también contiene una firma criptográfica como se detalla en RFC 7518. Esta firma es generada por una clave privada conocida solo por el servidor de autenticación”  Microsoft

En la ilustración se resume el proceso de solicitudes y respuestas con el token generado por la API y relacionado en cada petición subsiguiente del cliente como parte del encabezado del mensaje. Nuevamente se valida la autenticidad

APIS - SEGURIDAD - JWT LOGO - EASY TO MAKE

JSON Web Token


¿Por qué JWT?

El almacenamiento de credenciales y la seguridad de Internet son variables críticas a la hora de transmitir datos o información entre clientes y servidores. El estándar JWT permite garantizar que la información transmitida no ha sido modificada en el recorrido. Esta validación se logra de modo local, en el cliente gracias a este estándar, haciendo uso de un Token

Los JWT se pueden firmar usando un secreto (con el algoritmo HMAC ) o un par de claves pública / privada usando RSA o ECDSA .

El token es realmente una cadena de texto que tiene tres partes codificadas en Base64, cada una de ellas separadas por un punto, como se ve en la imagen:

Las partes – estructura

JWT ha diseñado el estándar con 3 partes que conforman el token

Header

El encabezado generalmente consta de dos partes: el tipo de token, que es JWT, y el algoritmo de firma que se utiliza, como HMAC SHA256 o RSA. La cadenad e texto generada en formato JSON está codificado en Base64Url para formar la primera parte del JWT.

Payloads

Carga Útil
La segunda parte del token es la carga útil, que contiene las notificaciones. Las afirmaciones son declaraciones sobre una entidad (normalmente, el usuario) y datos adicionales. Hay tres tipos de reclamaciones: reclamaciones registradas , públicas y privadas. Forma parte de esta los ClaimsReclamos: Se trata de un conjunto de reclamos predefinidos que no son obligatorios, pero sí recomendados, para proporcionar un conjunto de reclamos útiles e interoperables. Algunos de ellos son: iss (emisor), exp (tiempo de vencimiento), sub (asunto), aud (audiencia) entre otros.

Verify Signature

Firma
Para crear la parte de la firma, debe tomar el encabezado codificado, la carga útil codificada, un secreto, el algoritmo especificado en el encabezado y firmarlo.

Por ejemplo, si desea utilizar el algoritmo HMAC SHA256, la firma se creará de la siguiente manera:

HMACSHA256(
  base64UrlEncode(header) + "." +
  base64UrlEncode(payload),
  secret) 

La firma se usa para verificar que el mensaje no se haya modificado en el camino y, en el caso de los tokens firmados con una clave privada, también puede verificar que el remitente del JWT es quien dice ser.

El resultado son tres cadenas de URL Base64 separadas por puntos que se pueden pasar fácilmente en entornos HTML y HTTP, mientras que son más compactas en comparación con estándares basados en XML como SAML. En una aproximación inicial y como ejemplo de nuestra API Escuela Norte, tenemos:


HEADER
{
  "alg": "HS256",
  "typ": "JWT"
}

PAYLOAD : DATOS
{
  "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name": "Cesar Brown",
  "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress": "brown@gmail.com",
  "http://schemas.microsoft.com/ws/2008/06/identity/claims/role": "Keymaster",
  "nbf": 1641305140,
  "exp": 1641305260,
  "iss": "https://localhost:7295/",
  "aud": "https://localhost:7295/"
}

VERIFICACIÓN DE LA FIRMA , SIGNATURE
HMACSHA256(
  base64UrlEncode(header) + "." +
  base64UrlEncode(payload),
  
your-256-bit-secret

) secret base64 encoded

TOKEN
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
.eyJodHRwOi8vc2NoZW1hcy54bWxzb2FwLm9yZy93cy8yMDA1LzA1L2lkZW50aXR5L2NsYWltcy9uYW1lIjoiQ2VzYXIgQnJvd24iLCJodHRwOi8vc2NoZW1hcy54bWxzb2FwLm9yZy93cy8yMDA1LzA1L2lkZW50aXR5L2NsYWltcy9lbWFpbGFkZHJlc3MiOiJkYmFjZXNhckBvdXRsb29rLmNvbSIsImh0dHA6Ly9zY2hlbWFzLm1pY3Jvc29mdC5jb20vd3MvMjAwOC8wNi9pZGVudGl0eS9jbGFpbXMvcm9sZSI6IktleW1hc3RlciIsIm5iZiI6MTY0MTMwNTE0MCwiZXhwIjoxNjQxMzA1MjYwLCJpc3MiOiJodHRwczovL2xvY2FsaG9zdDo3Mjk1LyIsImF1ZCI6Imh0dHBzOi8vbG9jYWxob3N0OjcyOTUvIn0
.ky1mAo4CAUYxazBifiJQpwxlNDk_K3uMGaXhgeBssvs 
Al intentar modificar o cambiar un solo carácter de la firma, ahora tendremos el siguiente resultado corrupto, donde puedes observar la diferencia a la firma anterior:
"{\"http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name\":\"Cesar Brown\",
\"http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress\"
:\"dbacesar@outlook.com\",\"http://schemas.microsoft.com/ws/2008/06/identity/claims/role\
":\"Keymaster\",\"nbf\":1641304M\f\u000b\b�^\u001c\b��M�\fL�
\rL��\u000b\b�\\�Ȏ��\u001d\u001d\u001c\u001c΋��\u001b��[\u001a\u001b��\u000e�̎MKȋ\b�]Y\b���\u001
d\u001d\u001c\u001c΋��\u001b��[\u001a\u001b��\u000e�̎MKȟ" 

  401
Si el usuario cliente no está autorizado y debe solicitar su token, se desplegará un error de tipo response HTTP 401 como se observa en la imagen:

Cuando las credenciales del usuario no corresponden a las digitadas se activa un error HTTP 404 como se observa:

  Base64Url
Namespace:Microsoft.IdentityModel.Tokens

Convierte la cadena especificada, que codifica datos binarios como dígitos base-64-url, en una matriz de enteros sin signo de 8 bits equivalente.

Los esquemas de codificación Base64 son comúnmente usados cuando se necesita codificar datos binarios para que sean almacenados y transferidos sobre un medio diseñado para tratar con datos textuales. Esto es para asegurar que los datos se mantienen intactos y sin modificaciones durante la transmisión. Mozilla.org

Campos estándar JWT


CódigoNombreDescripción
Campos de reclamo estándarLos borradores de Internet definen los siguientes campos estándar (“reclamos”) que se pueden utilizar dentro de un conjunto de reclamos de JWT.
issEditorIdentifica al principal que emitió el JWT.
subSujetoIdentifica el sujeto del JWT.
audAudienciaIdentifica los destinatarios a los que está destinado el JWT. Cada director destinado a procesar el JWT debe identificarse con un valor en el reclamo de audiencia. Si el principal que procesa el reclamo no se identifica con un valor en el audreclamo cuando este reclamo está presente, entonces el JWT debe ser rechazado.
expTiempo de expiraciónIdentifica el tiempo de vencimiento en y después del cual el JWT no debe aceptarse para su procesamiento. El valor debe ser NumericDate: [9] ya sea un número entero o decimal, que representa los segundos después de 1970-01-01 00: 00: 00Z .
nbfNo antesIdentifica la hora en la que el JWT comenzará a ser aceptado para su procesamiento. El valor debe ser NumericDate.
iatEmitido enIdentifica el momento en que se emitió el JWT. El valor debe ser NumericDate.
jtiID de JWTIdentificador único del token que distingue entre mayúsculas y minúsculas, incluso entre diferentes emisores.
Campos de encabezado de uso comúnLos siguientes campos se utilizan comúnmente en el encabezado de un JWT
typTipo de tokenSi está presente, debe configurarse como un tipo de medio IANA registrado .
ctyTipo de contenidoSi se emplea la firma anidada o el cifrado, se recomienda configurarlo en JWT; de lo contrario, omita este campo. [1]
algAlgoritmo de código de autenticación de mensajesEl emisor puede configurar libremente un algoritmo para verificar la firma en el token. Sin embargo, algunos algoritmos compatibles son inseguros. [10]
kidID de claveUna pista que indica qué clave usó el cliente para generar la firma del token. El servidor comparará este valor con una clave en el archivo para verificar que la firma es válida y el token es auténtico.
x5cCadena de certificado x.509Una cadena de certificados en formato RFC4945 correspondiente a la clave privada utilizada para generar la firma del token. El servidor utilizará esta información para verificar que la firma sea válida y que el token sea auténtico.
x5ux.509 URL de la cadena de certificadosUna URL donde el servidor puede recuperar una cadena de certificados correspondiente a la clave privada utilizada para generar la firma del token. El servidor recuperará y utilizará esta información para verificar que la firma sea auténtica.
critCríticoUna lista de encabezados que el servidor debe entender para aceptar el token como válido

La solicitud y respuesta con JWT


En el diagrama de secuencia encontramos una diversidad de métodos manejados por la clase KeyApiController con tareas muy especiales como la validación de las credenciales del cliente-usuario y generación del Token que será remitido como parte del Response.

Una vez implementado nuestro módulo para la generación de un Token, el proceso y resultado sería el siguiente con el nuevo endpoint KeyAPI para el manejo de la seguridad de nuestra API:
Una vez realizado el envío de las credenciales que corresponden al parámetros de validación de Login:
A través de la URL que apunta al endpoint y método GET:

Obtenemos la respuesta API a la solicitud del usuario una vez generado el Token dentro del Response body:

   CONTRARRESTANDO LA VULNERABILIDAD

Todo sistema propende a la Entropía. Aquí encontrarás recomendaciones para enfrentar potenciales fallos con JWT.

 Paso a paso

En el vídeo ¡Aplica ya! de esta lección desarrollaremos los siguientes pasos:

Parte I : Implementando la seguridad

  1. Configurar un nuevo nodo para Autenticación:
    Capa: Presentación > Appsetting.json
  2. Agregar el NuGet > Microsoft.AspNetCore.Authentication.JwtBearer 
  3. Configuramos el servicio middleware y definimos los schemas:
    Capa: Presentación > Program.cs.
    Código de esta sección en la pestaña superior > ‘Materiales’.
  4. Declara el uso del servicio de autenticación > UseAuthentication();
    Capa: Presentación > Program.cs.

Parte II : La autenticación

El cliente debe validar sus credenciales en nuestra app y solicitar un token. Nuestra API debe generar este token que formará parte del Header del request del cliente > Hedear > Key.

  1. Implementar una clase que gestione la autenticación del usuario-cliente, generando una nueva entidad en el modelo
    Capa: Core, Entidades.
  2. Implementar una clase API que gestione la autenticación:
    Capa: Presentación, Controller.

Parte III : El Token

Implementar el proceso de generar token.

  1. Generar el método que gestione el Header del token:
    Capa: Presentación, Controller.
    Inyectar el servicio por constructor.
    Crear la variable para las credenciales.
    Crear la variable para los Claims.
    Generar la firma, signature.
  2. Probar el token utilizando la URL respectiva en el cliente:
    …/api/{ActionResult}
  3. Ajustar código para activar el servicios de —login y que un usuario con perfil autorizado pueda utilizar los endpoints por Swagger.

Parte IV: Servicio de creación y autenticación de usuarios

Este servicio la desarrollaremos en las siguientes lecciones.

     Laboratorio ¡Aplica ya!

¡Manos a la obra!
Aplica el paso a paso en la siguiente colección de vídeos…

Guía de bolsillo JWT


Descargar EASY TO MAKE - jwt-handbook-v0_14_1

Código para el servicio


Recomendación: Intenta digitarlo y comprender su lógica.

// SEGURIDAD...
builder.Services.AddAuthentication(auth =>
{
auth.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
auth.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
}).AddJwtBearer(opt =>
{ 
opt.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
ValidateAudience = true,
ValidateLifetime = true,
ValidateIssuerSigningKey = true,
ValidIssuer = builder.Configuration["JWT:Issuer"],
ValidAudience = builder.Configuration["JWT:Audience"],
IssuerSigningKey = new SymmetricSecurityKey(
Encoding.UTF8.GetBytes(builder.Configuration["JWT:Key"]))
};
});