Arquitectura y seguridad en intranets modernas

Arquitectura y seguridad en intranets modernas

Históricamente, una intranet era sinónimo de un servidor físico escondido detrás de un firewall corporativo, accesible solo si estabas en la oficina o conectado a través de una VPN lenta. Hoy, el trabajo remoto, la adopción de la nube y las expectativas de los usuarios han transformado ese concepto.

Muchas empresas construyen hoy sus intranets con frameworks modernos de aplicaciones de página única (SPA) como React o Angular, y las alojan en infraestructuras de nube pública como AWS, Azure, Vercel o Firebase. La pregunta entonces es cómo hacer que un portal web accesible públicamente a nivel de red siga siendo una intranet privada y segura. La respuesta está en la arquitectura Zero Trust (confianza cero) y en una gestión de identidad sólida.

Arquitectura de una intranet moderna

Cuando usamos React o Angular desplegamos aplicaciones estáticas (HTML, CSS y JS). Esas aplicaciones corren en el navegador del usuario, no en el servidor. Por eso la arquitectura típica se divide en tres capas:

CapaFunciónEjemplos
Presentación (Frontend SPA)La aplicación alojada en un CDN públicoCloudFront, Azure Static Web Apps
Identidad (IdP)Maneja autenticación y autorizaciónMicrosoft Entra ID, Okta, Auth0, Google Workspace
Datos y lógica (Backend/APIs)Microservicios que solo responden con un token JWT válidoServicios REST en la nube

El portal web en sí está en Internet público, pero los datos están protegidos por capas de identidad y seguridad.

La identidad es el nuevo perímetro

En este modelo la red deja de ser el perímetro de seguridad: la identidad lo reemplaza.

  • Autenticación obligatoria (OIDC/OAuth2): el SPA no debe mostrar ninguna información sensible hasta que el usuario inicie sesión a través del IdP de la empresa.
  • JSON Web Tokens (JWT): una vez autenticado, el frontend recibe un token de acceso que debe adjuntar a cada petición hacia el backend.
  • CORS y CSRF: los backends deben configurarse de manera estricta para aceptar peticiones solo desde el dominio exacto donde está alojada la intranet.

Ruta protegida en React

En React se usa un proveedor de autenticación (por ejemplo Auth0 o MSAL para Microsoft) para proteger las rutas. Una "ruta privada" redirige al usuario al login si no está autenticado.

// PrivateRoute.jsx (React)
import React from 'react';
import { Navigate, Outlet } from 'react-router-dom';
import { useAuth0 } from '@auth0/auth0-react';

const PrivateRoute = () => {
  const { isAuthenticated, isLoading } = useAuth0();

  if (isLoading) {
    return <div>Cargando Intranet...</div>;
  }

  // Si no esta autenticado, redirige al login.
  // Si lo esta, renderiza el componente hijo (la Intranet)
  return isAuthenticated ? <Outlet /> : <Navigate to="/login" replace />;
};

export default PrivateRoute;

Interceptor HTTP en Angular

En Angular no basta con proteger la ruta con un AuthGuard: cada petición HTTP que sale hacia los microservicios debe llevar el token de seguridad. Esto se logra con un interceptor HTTP.

// auth.interceptor.ts (Angular)
import { Injectable } from '@angular/core';
import { HttpRequest, HttpHandler, HttpEvent, HttpInterceptor } from '@angular/common/http';
import { Observable } from 'rxjs';
import { AuthService } from './auth.service';

@Injectable()
export class AuthInterceptor implements HttpInterceptor {
  constructor(private authService: AuthService) {}

  intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    const token = this.authService.getAccessToken();

    if (token) {
      request = request.clone({
        setHeaders: {
          Authorization: `Bearer ${token}`
        }
      });
    }

    return next.handle(request);
  }
}

Validación del token en el backend

El frontend puede ser manipulado en el navegador del usuario, así que la verdadera seguridad reside en el backend, que debe validar matemáticamente la firma del JWT antes de devolver datos corporativos.

// authMiddleware.js (Node.js / Express)
const jwt = require('jsonwebtoken');
const jwksClient = require('jwks-rsa');

// Cliente para obtener la llave publica del IdP (Auth0, Entra ID, etc.)
const client = jwksClient({
  jwksUri: 'https://tu-tenant.auth0.com/.well-known/jwks.json'
});

function getKey(header, callback){
  client.getSigningKey(header.kid, function(err, key) {
    var signingKey = key.publicKey || key.rsaPublicKey;
    callback(null, signingKey);
  });
}

const verificarToken = (req, res, next) => {
  const token = req.headers.authorization?.split(' ')[1];

  if (!token) return res.status(401).json({ message: 'Acceso Denegado' });

  jwt.verify(token, getKey, { algorithms: ['RS256'] }, (err, decoded) => {
    if (err) return res.status(401).json({ message: 'Token invalido corporativo' });

    req.empleado = decoded;
    next();
  });
};

module.exports = verificarToken;

Medidas adicionales para intranets públicas

  • Cifrado de extremo a extremo (TLS 1.3): todo el tráfico, sin excepción, debe ir por HTTPS.
  • WAF (Web Application Firewall): colocar un WAF frente al CDN y los APIs para filtrar ataques como inyección SQL o DDoS.
  • Prevención de indexación: al estar en Internet público hay que asegurarse de que los motores de búsqueda no indexen el portal. Se usa un archivo robots.txt restrictivo (Disallow: /) y la cabecera X-Robots-Tag: noindex, nofollow.

Conclusión

Construir una intranet corporativa con React o Angular alojada en infraestructura pública es viable y recomendable por su escalabilidad y rendimiento. Requiere, eso sí, un cambio de mentalidad: abandonar la falsa sensación de seguridad de las redes privadas y adoptar un enfoque Zero Trust, donde el código delega la autenticación a proveedores de identidad robustos y el backend nunca confía en el frontend, verificando cada solicitud de forma individual.

© Arturo Juárez Monroy