Implementando un Servidor Seguro con Autenticación y Cifrado en Python

En este artículo, quiero compartir contigo un ejercicio práctico que he realizado recientemente, donde combino varios conceptos esenciales para la programación segura en Python.

El objetivo de este proyecto es crear un servidor seguro con autenticación y cifrado, permitiendo que los clientes puedan enviar mensajes protegidos mediante AES y autenticarse mediante JWT (JSON Web Tokens).


📌 Objetivos del Proyecto

Este ejercicio me ha permitido poner en práctica: ✅ La gestión de usuarios con autenticación JWT.
✅ La encriptación y desencriptación de datos con AES.
✅ La implementación de un servidor Flask con seguridad.
✅ El uso de sockets seguros para la comunicación entre cliente y servidor.


1️⃣ Creando la API REST Segura con Flask y JWT

Para manejar la autenticación, decidí utilizar JWT, que permite generar un token seguro para los usuarios registrados.

Primero, instalé las dependencias necesarias:

pip install flask flask-jwt-extended

Luego, implementé la API:

from flask import Flask, request, jsonify
from flask_jwt_extended import create_access_token, jwt_required, JWTManager

app = Flask(__name__)
app.config["JWT_SECRET_KEY"] = "clave_super_segura"
jwt = JWTManager(app)

usuarios = {"admin": "admin123"}

@app.route("/login", methods=["POST"])
def login():
    datos = request.get_json()
    usuario, clave = datos.get("usuario"), datos.get("clave")
    
    if usuarios.get(usuario) == clave:
        token = create_access_token(identity=usuario)
        return jsonify({"token": token})
    
    return jsonify({"error": "Credenciales incorrectas"}), 401

@app.route("/datos", methods=["GET"])
@jwt_required()
def obtener_datos():
    return jsonify({"mensaje": "Acceso permitido, datos enviados."})

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

🔹 Explicación:

  • Si un usuario envía las credenciales correctas (POST /login), el servidor le devuelve un token JWT.
  • Para acceder a los datos (GET /datos), el usuario debe incluir ese token en la solicitud.

🔐 Seguridad: Esta autenticación evita que usuarios no autorizados accedan a información sensible.


2️⃣ Cifrando y Descifrando Datos con AES

Para garantizar la seguridad de los datos en tránsito, utilicé AES para cifrar los mensajes enviados al servidor.

Primero, instalé la librería PyCryptodome:

pip install pycryptodome

Luego, implementé la función de cifrado y descifrado:

from Crypto.Cipher import AES
import os

def cifrar(mensaje, clave):
    cifrador = AES.new(clave, AES.MODE_EAX)
    nonce = cifrador.nonce
    mensaje_cifrado, tag = cifrador.encrypt_and_digest(mensaje.encode())
    return nonce, mensaje_cifrado, tag

def descifrar(nonce, mensaje_cifrado, clave):
    cifrador = AES.new(clave, AES.MODE_EAX, nonce=nonce)
    mensaje_descifrado = cifrador.decrypt(mensaje_cifrado)
    return mensaje_descifrado.decode()

🔹 Explicación:

  • Genero una clave de 16 bytes para cifrar y descifrar los mensajes.
  • Uso el modo EAX de AES, que es seguro y fácil de implementar.
  • Nonce es un valor aleatorio único para cada cifrado, evitando ataques de repetición.

🔐 Seguridad: Cualquier mensaje enviado queda encriptado, evitando que terceros lo intercepten en texto plano.


3️⃣ Implementando un Servidor con Sockets Seguros

El siguiente paso fue proteger la comunicación con SSL/TLS para evitar que los datos sean interceptados.

Creé un servidor seguro con sockets y SSL:

import socket
import ssl

contexto = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
contexto.load_cert_chain(certfile="cert.pem", keyfile="key.pem")

servidor = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
servidor.bind(("127.0.0.1", 4443))
servidor.listen(1)

conn, addr = servidor.accept()
ssl_conn = contexto.wrap_socket(conn, server_side=True)

mensaje = ssl_conn.recv(1024)
print(f"Mensaje recibido: {mensaje.decode()}")

ssl_conn.send("Respuesta segura".encode())
ssl_conn.close()

Luego, el cliente seguro con SSL:

import socket
import ssl

contexto = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
contexto.load_verify_locations("cert.pem")

cliente = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
ssl_cliente = contexto.wrap_socket(cliente, server_hostname="127.0.0.1")

ssl_cliente.connect(("127.0.0.1", 4443))
ssl_cliente.send("Hola, servidor seguro!".encode())

respuesta = ssl_cliente.recv(1024)
print(f"Respuesta del servidor: {respuesta.decode()}")

ssl_cliente.close()

🔹 Explicación:

  • Carga un certificado SSL/TLS (cert.pem) para cifrar la conexión.
  • El servidor acepta conexiones seguras y el cliente solo se conecta si la verificación SSL es correcta.

🔐 Seguridad: Evita que alguien pueda interceptar la comunicación entre cliente y servidor.


🔎 Resultados y Beneficios

Este ejercicio me ha permitido: ✅ Asegurar las comunicaciones con SSL.
Proteger los datos enviados con AES.
Implementar autenticación con JWT para controlar el acceso.
Crear un servidor multicliente con hilos.


🎯 Conclusión

Este proyecto me ha permitido integrar seguridad en aplicaciones web y en red, asegurando que los datos viajen protegidos contra ataques.

Si estás interesado en aprender más sobre seguridad en programación, te recomiendo que practiques con estos ejemplos y los adaptes a tus necesidades. 🚀

¿Tienes alguna duda o sugerencia? ¡Déjala en los comentarios!

Deja un comentario

Información básica sobre protección de datos Ver más

  • Responsable: Tomas Gonzalez.
  • Finalidad:  Moderar los comentarios.
  • Legitimación:  Por consentimiento del interesado.
  • Destinatarios y encargados de tratamiento:  No se ceden o comunican datos a terceros para prestar este servicio.
  • Derechos: Acceder, rectificar y suprimir los datos.
  • Información Adicional: Puede consultar la información detallada en la Política de Privacidad.

error: Content is protected !!

Descubre más desde Tomás González: Formador y Desarrollador Web

Suscríbete ahora para seguir leyendo y obtener acceso al archivo completo.

Seguir leyendo

Este sitio web utiliza cookies, si necesitas más información puedes visitar nuestra política de privacidad    Ver
Privacidad