Tema 1. Parte IV:

Seguridad en APIs REST


Contenidos

  1. Autentificación con sesiones
  2. HTTP Basic
  3. Tokens
  4. OAuth

Autentificación con sesiones


Sesiones


Cookies


Mantenimiento de sesiones con cookies



API de sesiones

En casi todos los frameworks web las cookies de sesión son transparentes al desarrollador. Se nos da un API mediante el que podemos almacenar/recuperar objetos en la “sesión”, una especie de BD privada de cada usuario, guardada en el servidor


Sesiones en Express

var express = require('express');
var session = require('express-session');

var app = express();
app.use(session({secret:'123456'}));

//Ejemplo de uso de sesiones. No RESTful
app.post('/addProducto', function(pet, resp) {
    var obj = pet.query;
    if (!pet.session.prods)
        pet.session.prods = [];
    pet.session.prods.push(obj);
    console.log(pet.session.prods);
    resp.send("Añadido");
})

Autentificación con sesiones

Tras hacer login correctamente, guardamos en la sesión un dato indicando que el cliente se ha autentificado OK. Si no está en la sesión, no se ha autentificado

app.post('/doLogin', function(pet, resp) {
   if (pet.query.login=='usuario' && pet.query.password=='123456') {
        pet.session.usuarioActual = {login: pet.query.login};
        resp.send("Login OK");
   }
   else {
        resp.status(401);
        resp.send("login y/o password incorrecto");
   }
});

app.get('/doLogout', function(pet, resp) {
    pet.session.destroy();
    resp.send("logout");
});

app.get('/restringido', function(pet, resp) {
    if (pet.session.usuarioActual)
        resp.send("OK, tienes permiso");
    else {
        resp.status(401);
        resp.send("Debes autentificarte");
    }
});

Express hace sencillo modularizar el chequeo de autenticación

function checkAuth(pet, resp, next) {
    if (pet.session.usuarioActual)
        next();
    else {
        resp.status(401);
        resp.send("Debes autentificarte");      
    }
}

app.get('/restringido2', checkAuth, function(pet, resp) {
    resp.send("Si estás viendo esto es que eres importante!!!");
});

A favor de las sesiones


En contra de las sesiones

En teoría un API REST no debería guardar nada de estado entre peticiones


Autentificación con HTTP Basic


HTTP Basic

Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==

HTTP Basic (2)

401 UNAUTHORIZED HTTP/1.1
...
WWW-Authenticate: Basic realm="nombre del realm"

Cuando el navegador recibe un 401 + cabecera WWW-Authenticate hace que “salte” el típico cuadro de diálogo de login


A favor de HTTP Basic


En contra de HTTP Basic


Autentificación con tokens


Tokens

  1. Cuando se hace login correctamente el servidor nos devuelve un token (valor idealmente único e imposible de falsear)
  2. A partir de este momento para cualquier operación restringida debemos enviar el token en la petición

Similar a HTTP Basic pero se está enviando un dato no tan crítico


JSON Web Token (JWT)

    eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJob2xhIjoibXVuZG8ifQ.pJPDprjxsouVfaaXau-Fyspj6rpKc7_hCui1RSaERAE    

Comprobar un JWT


Fecha de expiración


Ejemplo en Node.js

var jwt = require('jwt-simple');
var moment = require('moment');

var payload = {
    login: 'pepito',
    exp: moment().add(7, 'days').valueOf()
}

var secret='123456';

var token = jwt.encode(payload, secret);
console.log(token);

var decoded = jwt.decode(token, secret);
console.log(decoded);

¿Dónde viaja el JWT?

Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9...

A favor de los tokens


OAuth


¿Qué es OAuth?



Más sobre OAuth


Ejemplo con Facebook

Como condición previa debemos tener una app dada de alta en FB como desarrolladores. Dicha app tiene un id único

Ejemplo del denominado implicit flow según OAuth 2

Documentación de FB

  1. Se hace una petición a https://www.facebook.com/dialog/oauth?client_id={id_de_la_app}&redirect_uri={redirect_uri}&response_type=token
  2. FB muestra una página de login para nuestra app
  3. Se hace una redirección a la redirect_uri. Dentro de la URL de la redirección aparecerá un access_token con un token para acceder al API.
  4. Para cualquier petición al API se debe usar un parámetro HTTP access_token con el token obtenido

¿Preguntas…?