Deno, como entorno de ejecución moderno para JavaScript y TypeScript, ofrece varias ventajas en términos de seguridad. Su enfoque en la seguridad por diseño incluye la gestión de permisos granular y un runtime sin acceso implícito al sistema. Sin embargo, la seguridad en aplicaciones Deno no solo depende del entorno, sino también de cómo se implementan funcionalidades clave como la autenticación y autorización. Este artículo explora cómo construir aplicaciones seguras en Deno con ejemplos prácticos y buenas prácticas.
Introducción a la seguridad en Deno
Ventajas de Deno en términos de seguridad
- Sistema de permisos: Deno requiere permisos explícitos para acceder a archivos, red y entorno.
- Tipado estático: TypeScript mejora la robustez del código.
- Integración nativa con WebAssembly (WASM): Reduce vulnerabilidades por código nativo inseguro.
A pesar de estas ventajas, los desarrolladores deben implementar medidas adicionales para proteger sus aplicaciones, especialmente en lo relacionado con la autenticación y autorización.
Autenticación en Deno
La autenticación verifica la identidad de los usuarios. Una implementación segura considera:
- Uso de protocolos modernos como OAuth 2.0 o OpenID Connect (OIDC).
- Encriptación de contraseñas con algoritmos seguros (bcrypt, Argon2).
- Tokens seguros (JWT con HS256 o RS256).
Ejemplo práctico: Autenticación basada en JWT
import { create, verify } from "https://deno.land/x/djwt/mod.ts";
const secretKey = "your-secret-key";
// Generar un token
async function generateToken(payload: Record<string, unknown>) {
const jwt = await create({ alg: "HS256", typ: "JWT" }, payload, secretKey);
return jwt;
}
// Verificar un token
async function verifyToken(token: string) {
try {
const payload = await verify(token, secretKey, "HS256");
return payload;
} catch (error) {
throw new Error("Token inválido");
}
}
// Ejemplo de uso
const token = await generateToken({ id: 1, role: "admin" });
console.log("Token generado:", token);
const payload = await verifyToken(token);
console.log("Payload verificado:", payload);
Buenas prácticas para la autenticación
- Usar HTTPS: Protege los tokens en tránsito.
- Implementar expiración de tokens: Minimiza riesgos en caso de compromiso.
- Almacenar contraseñas de forma segura:
import { hash, compare } from "https://deno.land/x/bcrypt/mod.ts";
const password = "securepassword";
const hashedPassword = await hash(password);
console.log("Contraseña hasheada:", hashedPassword);
const isValid = await compare(password, hashedPassword);
console.log("Contraseña válida:", isValid);
Autorización en Deno
La autorización determina qué recursos puede acceder un usuario autenticado.
Ejemplo práctico: Middleware para roles
Un middleware puede garantizar que solo ciertos roles accedan a rutas específicas:
import { Context } from "https://deno.land/x/oak/mod.ts";
async function roleMiddleware(ctx: Context, next: () => Promise<unknown>, allowedRoles: string[]) {
const token = ctx.request.headers.get("Authorization")?.replace("Bearer ", "");
if (!token) {
ctx.response.status = 401;
ctx.response.body = { error: "Token no proporcionado" };
return;
}
try {
const payload = await verifyToken(token);
if (!allowedRoles.includes(payload.role)) {
ctx.response.status = 403;
ctx.response.body = { error: "Acceso denegado" };
return;
}
await next();
} catch (error) {
ctx.response.status = 401;
ctx.response.body = { error: "Token inválido" };
}
}
// Ejemplo de uso
router.get(
"/admin",
(ctx, next) => roleMiddleware(ctx, next, ["admin"]),
(ctx) => {
ctx.response.body = { message: "Bienvenido, admin" };
},
);
Buenas prácticas para la autorización
- Principio de menor privilegio: Limitar accesos a lo estrictamente necesario.
- Políticas basadas en roles (RBAC): Simplifican la gestión de permisos.
- Registro de eventos de acceso: Proporciona trazabilidad.
Medidas adicionales de seguridad
- CORS: Configurar correctamente para evitar accesos no autorizados.
import { oakCors } from "https://deno.land/x/cors/mod.ts";
app.use(oakCors({
origin: "https://example.com",
}));
- Validación de datos:
import { z } from "https://deno.land/x/zod/mod.ts";
const userSchema = z.object({
username: z.string().min(3),
password: z.string().min(8),
});
try {
const userData = userSchema.parse({ username: "test", password: "secure" });
console.log("Datos válidos:", userData);
} catch (error) {
console.error("Error de validación:", error);
}
- Monitoreo y auditoría: Implementar registros de eventos sensibles.
- Uso de secretos seguros: Gestionar claves de API y configuraciones sensibles mediante herramientas como Deno Deploy Secrets.
Conclusión
La seguridad en aplicaciones Deno va más allá de las capacidades intrínsecas del entorno. Una implementación adecuada de autenticación y autorización, junto con medidas complementarias, garantiza aplicaciones robustas y protegidas contra amenazas modernas. Aplicar las mejores prácticas descritas y mantenerse actualizado con las últimas vulnerabilidades es esencial para mantener la confianza y la integridad de tus aplicaciones.