Node/Express – ¿Cómo restringir el acceso a usuarios que no estén conectados a la misma red?

publicado por: Anonymous

Me encuentro con un problema que no sé como resolver y no encuentro nada al respecto. Imaginaos que tengo las siguientes rutas en una aplicación express :

// app.js
app.use('/users', require('./routes/users'));

// routes/users.js
router.use(accesoExterno);
router.route('/login').get(...).post(...).put(...)
...

En la base de datos, debe exisitir una columna accesoExterno de tipo boolean que diga si el usuario tiene privilegios para acceder de “forma externa”, es decir, que no esté conectado a la red desde donde lanzo el servidor.

¿Qué debería hacer en el middleware accesoExterno para realizar esta comprobación?

function accesoExterno(req, res, next){
  //PSEUDO-CODE
  db.users.get('accesoExterno')
  .then( tieneAcceso => {
    if(!tieneAcceso){
      // Si no tiene acceso comprobar que está conectado a la misma red
    }
  })
}

EDIT

Cosas que he probado:

  • req.host -> Me devuelve el host. Puedo comprobar si se está ejecutando desde “localhost”, lo cual sería una opción. Pero ¿y si entra por medio de “127.0.0.1” o directamente desde la IP?
  • req.ip -> Creo que esto me valdría, ya que si estoy conectado a mi red, me devuelve la IP de mi red, si no me devuelve ¿La IP de mi dispositivo?

Cualquier aclaración a mis dudas me sería de gran ayuda.

solución

El valor de req.ip te da el “supuesto” valor del ip del usuario que hace la petición. Si unes eso con la propia configuración de tu equipo puedes determinar si pertenece al mismo rango ip que tu.

Para determinar tu propia configuración puedes usar el módulo nativo os con la función os.networkInterfaces

De aquí en adelante solo te queda iterar en los valores y comprobar si al menos uno de ellos coincide con el de tu servidor. La función middleware sería algo así.

var os = require('os');
var ip = require('ip'); 

function accesoExterno(req, res, next){
    //PSEUDO-CODE
    db.users.get('accesoExterno').then( tieneAcceso => {
        if(!tieneAcceso) {
            if (inRange(req.ip)) {
                next();
            } else {
                res.status(401).send('Unauthorized');
            }
       }
    });
}

function inRange(currentIp) {
    // Obtengo la lista de interfaces
    var interfaces = os.networkInterfaces();

    for (var interf in interfaces) {
        // Interfaces es un objeto donde las llaves son el nombre del adaptador
        // El contenido es un arreglo de direcciones ip asignadas al adaptador
        // Pueden haber varias
        var currentInterface = interfaces[interf];

        for (var j = 0; j < currentInterface.length; j++) {
            // Es true si es 127.0.0.1 o similar. 
            if (!currentInterface[j].internal) {
                // Creamos la subnet para calcular
                var subnet = ip.subnet(currentInterface[j].address, currentInterface[j].netmask);
                // Si se encuentra al menos una coincidencia abortamos el ciclo retornando true
                if (subnet.contains(currentIp)) {
                     return true;
                }
            }
        }
    }

    // Si no se ha encontrado nada devolvemos false
    return false;
}

En el ejemplo he usado el modulo ip que trae algunas herramientas muy convenientes para el manejo de ip y subredes.

Puedes leer más información sobre este proceso en el artículo de la Wikipedia

https://en.wikipedia.org/wiki/Subnetwork

Ten en cuenta que req.ip puede no funcionar si la configuración trust-proxy está puesta en false y que este valor puede ser falsificado por el usuario o cualquiera de los proxys en la cadena.

Respondido por: Anonymous

Leave a Reply

Your email address will not be published. Required fields are marked *