Geekflare recibe el apoyo de nuestra audiencia. Podemos ganar comisiones de afiliación de los enlaces de compra en este sitio.
En Desarrollo Última actualización: 25 de septiembre de 2023
Compartir en:
Escáner de seguridad de aplicaciones web Invicti - la única solución que ofrece verificación automática de vulnerabilidades con Proof-Based Scanning™.

Aprendamos a proteger una API REST con tokens web JSON para evitar que los usuarios y las aplicaciones de terceros abusen de ella.

Construiremos un servicio de base de datos utilizando SQLite y permitiremos a los usuarios acceder a él a través de una API REST utilizando métodos HTTP como POST y PUT

Además, conoceremos por qué los tokens web JSON son una forma adecuada de proteger la API de reposo en lugar de la autenticación digest y básica. Antes de continuar, entendemos el término tokens web JSON, API REST y framework Flask

Tokens web JSON

El token web JSON, también conocido como JWT, es la forma segura de transferir tokens aleatorios entre dos partes o entidades. JSON se compone normalmente de tres partes como las siguientes

  • Carga útil
  • Cabecera
  • Firma

JSON utiliza dos tipos de formas de estructura cuando transfiere datos o información entre dos partes

  • Serializada
  • Deserializado

La forma serializada se utiliza cuando se transfieren datos a la red a través de cada solicitud y respuesta, mientras que la forma deserializada se utiliza cuando se leen y escriben datos en el token web

En la forma serializada, hay tres componentes

  • Cabecera
  • Carga útil
  • Firma

El componente de cabecera define la información criptográfica sobre las fichas. Por ejemplo

  • ¿Es un JWT ¿firmado o sin firmar?
  • Definir técnicas de algoritmo

La forma deserializada, a diferencia de la forma serializada, contiene dos componentes

  • Carga útil
  • Cabecera

API REST

API (interfaz de programación de aplicaciones) permite la comunicación entre dos aplicaciones para recuperar o enviar los datos. Existen dos tipos populares de API: la API web y la API de sistema

En este artículo, sólo nos ocuparemos de la API web. Existen dos tipos de API web

  • API de solicitud - respuesta: Rest, GraphQL, Llamada a procedimiento remoto (RPC)
  • API dirigida por eventos: WebHooks, Web Sockets, HTTP Streaming

La API REST pertenece a la categoría solicitud-respuesta. Hace uso de métodos HTTP como GET, POST y PUT para realizar las operaciones de la API

Un ejemplo clásico es cuando un usuario envía un método GET al servicio web para solicitar o recuperar un recurso específico o una colección de recursos. A continuación, el servidor devuelve el recurso específico o la colección de recursos al usuario que lo solicitó

Marco Flask

Flask es un marco de trabajo basado en python. Es un micro-marco utilizado por los desarrolladores de python para construir API de descanso. Se llama micro-marco porque permite a los desarrolladores, por ejemplo, añadir autenticación personalizada y cualquier otro sistema backend basado en preferencias

Empecemos con la implementación. La configuración de mi sistema es la siguiente

  • Ubuntu como SO
  • Python 2.7
  • Cartero

Configurar un entorno virtual utilizando virtualenv

Necesitamos configurar un entorno virtual para asegurarnos de que algunos paquetes no entrarán en conflicto con los paquetes del sistema. Utilicemos virtualenv para configurar un nuevo entorno virtual

Suponiendo que tiene el comando pip disponible en su sistema, ejecute el siguiente comando a través de pip para instalar

pip install virtualenv

Si no tiene pip en su máquina, entonces siga esta documentación para instalar pip en su sistema

A continuación, vamos a crear un directorio para almacenar o guardar nuestro entorno virtual. Utilice el comando mkdir que se muestra a continuación para crear un directorio

mkdir flaskproject

Cambie al directorio flaskproject utilizando el siguiente comando

cd

flaskproject
Dentro del directorio flaskproject, utilice la herramienta virtualenv para crear un entorno virtual como se muestra a continuación
virtualenv

flaskapi

Después de haber utilizado la herramienta virtualenv para crear el entorno virtual, ejecute el comando cd para cambiar al directorio flaskapi como entorno virtual y actívelo utilizando el siguiente comando

source bin/activar

Ejecute todas las tareas relacionadas con este proyecto dentro del entorno virtual

Instale los paquetes utilizando pip

Ahora es el momento de instalar paquetes como el framework flask y PyJWT que utilizaremos para construir la API restante y otros paquetes necesarios para nuestro proyecto API

Cree un archivo requirements.txt con los siguientes paquetes

Flask
datetime

uuid


Flask-SQLAlchemy

PyJWT

Instálelos con pip

pip install -r

requisitos.txt

Configurar una base de datos

Vamos a instalar SQLite

apt-get install sqlite3

Cree una base de datos llamada biblioteca. Dentro de esta base de datos, crearemos dos tablas, la tabla Usuarios y la tabla Autores

La tabla Usuarios contendrá los usuarios registrados. Sólo los usuarios registrados podrán tener acceso a la tabla Autores

La tabla Autores almacenará la información de los autores o detalles como el nombre del autor, el país de nacimiento, etc. enviados por los usuarios registrados

Cree la base de datos utilizando el siguiente comando

sqlite3 library.db

Puede comprobar si se ha creado correctamente la base de datos utilizando el siguiente comando

.databases

Abra un nuevo terminal y ejecute lo siguiente en el entorno virtual que hemos creado anteriormente

toque app.py

Pegue el siguiente código dentro del archivo llamado app.py

from flask import Flask, request, jsonify, make_response
from flask_sqlalchemy import SQLAlchemy
from werkzeug.security import generate_password_hash, check_password_hash
import uuid
import jwt
import datetime
from functools import wraps

La primera línea del código anterior importa paquetes como request y jsonify. Haremos uso de request para realizar un seguimiento de los datos a nivel de petición durante una petición y utilizaremos jsonify para dar salida a las respuestas en formato JSON

En la siguiente línea, importamos SQLAlchemy de flask_sqlalchemy para integrar las características de SQLAlchemy en flask

De werkzeug.seguridad, importamos generate_password_hash para generar hash de contraseñas para los usuarios y check_password_hash para comprobar la contraseña del usuario al comparar la contraseña enviada por los usuarios con las contraseñas de los usuarios almacenadas en la base de datos

Por último, importamos uuid también conocidos como identificadores únicos universales para generar números de identificación aleatorios para los usuarios

Aún así, dentro del archivo app.py, implemente los ajustes de configuración para la API de la librería utilizando el siguiente código dentro del archivo app.py

Coloque el siguiente código debajo de la sentencia import

app = Flask(__name__)

app.config['SECRET_KEY']='Th1s1ss3cr3t'
app.config['SQLALCHEMY_DATABASE_URI']='sqlite://///home/michael/geekdemos/geekapp/library.db'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = True

db

= SQLAlchemy(app)

Ahora cree dos modelos para las tablas Usuarios y Autores como se muestra a continuación. Copie y pegue el código dentro del archivo app.py

Coloque el código de abajo justo debajo de esta configuración de la base de datos db = SQLAlchemy(app)
clase

Users(db.Model):
 id = db.Column(db.Integer, primary_key=True)
 public_id = db.Column(db.Integer)
 name = db.Column(db.String(50))
 password = db.Column(db.String(50))
 admin = db.Column(db.Boolean)
class Autores(db.Model):
 id = db.Column(db.Integer, primary_key=True)
 name = db.Column(db.String(50), unique=True, nullable=False))
 book = db.Column(db.String(20), unique=True, nullable=False))
 country = db.Column(db.String(50), nullable=False))
 booker_prize = db.Column(db.Boolean)

Generar tablas de usuarios y autores

En el terminal, escriba el siguiente código dentro del entorno virtual para generar o crear las tablas de Usuarios y Autores como se muestra a continuación

from app import db

db

.create_all()

Después, abra el archivo app.py dentro del entorno virtual y cree otra función

Esta función generará tokens para permitir que sólo los usuarios registrados puedan acceder y realizar un conjunto de operaciones de la API contra la tabla Autores

Coloque este código debajo del modelo de base de datos para la tabla Autores

def token_required(f):
 @wraps(f)
 def decorator(*args, **kwargs):

 token = None

 if 'x-access-tokens' in request.headers:
 token = request.headers['x-access-tokens']

 if not token:
 return jsonify({'message': 'falta un token válido'})

 try:
 data = jwt.decode(token, app.config[SECRET_KEY])
 current_user = Users.query.filter_by(public_id=data['public_id']).first()
 except:
 return jsonify({'mensaje': 'el token no es válido'})

 return f(current_user, *args, **kwargs)
 return decorator

Crear rutas para la tabla de usuarios

Ahora vamos a crear una ruta para permitir que los usuarios se registren en la API de Autores mediante un nombre de usuario y una contraseña, como se muestra a continuación

De nuevo abra el archivo app.py dentro del entorno virtual y pegue el siguiente código debajo de la función token_required(f)

@app.route('/register', methods=['GET', 'POST'])
def signup_user():  
 data = request.get_json()

 hashed_password = generate_password_hash(data['password'], method='sha256')
 
 new_user = Users(public_id=str(uuid.uuid4()), name=datos['nombre'], password=contraseña_hashed, admin=False)
 db.session.add(nuevo_usuario)
 db.session.commit()

 return jsonify({'mensaje': 'registrado correctamente'})

Dentro del entorno virtual, cree otra ruta en el archivo app.py para permitir que los usuarios registrados inicien sesión

Cuando un usuario se registra, se genera un token aleatorio para que el usuario pueda acceder a la API de la biblioteca

Pegue el código siguiente debajo de la ruta anterior que hemos creado

@app.route('/login', methods=['GET', 'POST'])
def login_user(): 
 
 auth = request.authorization

 if not auth or not auth.username or not auth.password:
 return make_response('could not verify', 401, {'WWW.Authentication': 'Basic realm: "login required"'})

 user = Users.query.filter_by(name=auth.username).first()
     
 if check_password_hash(user.password, auth.password):  
    token = jwt.encode({'public_id': user.public_id, 'exp' : datetime.datetime.utcnow() datetime.timedelta(minutes=30)}, app.config['SECRET_KEY'])
 return jsonify({'token' : token.decode('UTF-8')})

 return make_response('could not verify', 401, {'WWW.Authentication': 'Basic realm: "login requerido"'})

Aún así, dentro del entorno virtual, cree otra ruta en el archivo app.py para obtener o recuperar todos los usuarios registrados

Este código comprueba todos los usuarios registrados en la tabla Usuarios y devuelve el resultado final en formato JSON

Pegue el código siguiente debajo de la ruta de inicio de sesión

@app.route('/users', methods=['GET'])
def get_all_users():  
   
  users = Users.query.all()

 result = []

 for user in users:
 user_data = {}
 user_data['public_id'] = user.public_id
 user_data['name'] = user.name
 user_data['password'] = user.password
 user_data['admin'] = user.admin
       
 result.append(user_data)

 return jsonify({'users': result})

Crear rutas para la tabla de autores

Vamos a crear rutas para la tabla Autores para permitir a los usuarios recuperar todos los autores de la base de datos, así como eliminar autores

Sólo los usuarios con tokens válidos pueden realizar estas operaciones de la API

Dentro del archivo app.py, cree una ruta para que los usuarios registrados puedan crear nuevos autores

Pegue este código debajo de la ruta que permite a un usuario recuperar todos los usuarios registrados

@app.route('/author', methods=['POST', 'GET'])
@token_required
def create_author(current_user):
   
 data = request.get_json()

 new_authors = Authors(name=data['name'], country=data['country'], book=data['book'], booker_prize=True, user_id=current_user.id)
 db.session.add(nuevos_autores)
 db.session.commit()

 return jsonify({'mensaje' : 'nuevo autor creado'})

A continuación, cree otra ruta para permitir que un usuario registrado con un token válido recupere todos los autores de la tabla Autores como se muestra a continuación

Pegue este código debajo de la ruta que permite a un usuario crear un nuevo autor

@app.route('/autores', methods=['POST', 'GET'])
@token_required
def get_authors(usuario_actual):

 authors = Autores.query.filter_by(id_usuario=id_actual.id).all()

 output = []
 for author in autores:

 author_data = {}
 author_data['nombre'] = autor.name
 author_data['book'] = author.book
 author_data['country'] = author.country
 author_data['booker_prize'] = author.booker_prize
 output.append(author_data)

 return jsonify({'list_of_authors' : output})

Por último, aún dentro del archivo app.py, cree una ruta para eliminar un autor especificado como se muestra a continuación

Pegue este código debajo de la ruta que permite a un usuario recuperar una lista de autores

@app.route('/autores/<id_autor>', methods=['BORRAR'])
@token_required
def borrar_autor(usuario_actual, autor_id):  
   author = Author.query.filter_by(id=author_id, user_id=current_user.id).first()
 if not author:   
      return jsonify({'message': 'author does not exist'})


 db.session.delete(author)
 db.session.commit()

 return jsonify({'message': 'Author deleted'})


if __name__ == '__main__':
 app.run(debug=True)

Después, guarde y cierre el archivo app.py dentro del entorno virtual

Probar la API de la biblioteca con Postman

En esta sección, haremos uso de la herramienta postman para enviar una solicitud a los servicios de la base de datos. Si no dispone de postman en su máquina, puede averiguar cómo descargarlo e instalarlo aquí

Aparte del cartero, podemos hacer uso de otras herramientas como Rizar para enviar peticiones al servidor

Abra un nuevo terminal y escriba lo siguiente

postman

El comando postman hará que su navegador web muestre la siguiente página

postman_signup

Puede decidir registrarse y crear una cuenta gratuita, pero nosotros la saltaremos y obtendremos acceso directo a la aplicación para probar la API de la biblioteca, como se muestra a continuación

Probar la biblioteca api

En esta sección, permitiremos que un usuario se registre en la API de la biblioteca proporcionando un nombre de usuario y una contraseña única en formato JSON mediante el método POST siguiendo los pasos que se indican a continuación

  • Haga clic en la pestaña denominada Cuerpo
  • A continuación, seleccione el botón sin procesar y elija el formato JSON
  • introduzca un nombre de usuario y una contraseña para registrarse como se muestra en la captura de pantalla
  • Junto al botón de envío, inserte la siguiente URL http://127.0.0.1/register
  • Por último, cambie el método a POST y pulse el botón enviar.

un usuario se registra en una api

Aparecerá la siguiente salida como se muestra a continuación

Ahora hemos registrado con éxito a un usuario. Vamos a permitir que el usuario que se acaba de registrar inicie sesión con el fin de generar un token aleatorio temporal para acceder a la tabla Autores siguiendo los siguientes pasos

  • Haga clic en la pestaña autorización.
  • En la sección tipo, seleccione autenticación básica.
  • A continuación, rellene el formulario de nombre de usuario y contraseña con el nombre de usuario y la contraseña con los que se registró anteriormente.
  • Por último, pulse el botón enviar para acceder y generar un token aleatorio.

Una vez que el usuario haya iniciado sesión correctamente, se generará un token aleatorio para el usuario como se muestra en la captura de pantalla

Haremos uso del token aleatorio generado para acceder a la tabla Autores

En esta sección, añadiremos la información de un autor a la tabla Autores mediante el método POST siguiendo los siguientes pasos

  • Haga clic en la pestaña de cabeceras
  • Incluye las siguientes cabeceras HTTP mostradas en la captura de pantalla

  • A continuación, haga clic en la pestaña cuerpo e introduzca los datos del nuevo autor
  • A continuación, pulse el botón enviar para añadir los datos del autor a la tabla Autores

También puede recuperar la información de los autores en la tabla Autores de la siguiente manera

  • Asegúrese de que su token generado se encuentra en la sección de encabezados. si no está ahí, deberá rellenarlo con su token.
  • Junto al botón de envío, introduzca esta URL http://127.0.0.1/authors
  • A continuación, cambie el método HTTP a GET y pulse el botón de envío para recuperar los datos de los autores.

Por último, puede eliminar el autor o autores en la tabla Autores mediante el método DELETE siguiendo los siguientes pasos

  • Asegúrese de que su token sigue en la sección de cabeceras. Puede comprobar la pestaña de cabeceras para asegurarse de que la información necesaria está en su sitio.
  • Junto al botón de envío, introduzca esta URL http://127.0.0.1/sam
  • A continuación, pulse el botón de envío para eliminar el usuario que ha especificado.

Puede encontrar el código fuente completo en Github. Puede clonarlo y comprobarlo en su máquina.

  • Michael Aboagye
    Autor
Gracias a nuestros patrocinadores
Más lecturas sobre desarrollo
Potencia tu negocio
Algunas de las herramientas y servicios que le ayudarán a hacer crecer su negocio.
  • Invicti utiliza el Proof-Based Scanning™ para verificar automáticamente las vulnerabilidades identificadas y generar resultados procesables en tan solo unas horas.
    Pruebe Invicti
  • Web scraping, proxy residencial, gestor de proxy, desbloqueador web, rastreador de motores de búsqueda, y todo lo que necesita para recopilar datos web.
    Pruebe Brightdata
  • Monday.com es un sistema operativo de trabajo todo en uno que te ayuda a gestionar proyectos, tareas, trabajo, ventas, CRM, operaciones, flujos de trabajo y mucho más.
    Prueba Monday
  • Intruder es un escáner de vulnerabilidades en línea que encuentra puntos débiles de ciberseguridad en su infraestructura, para evitar costosas violaciones de datos.
    Prueba Intruder