Detectar si una pagina web ya esta abierta

Publicado en 'Programación' por UnderUp, 8 May 2014.





  1. UnderUp

    UnderUp Miembro maestro

    Registro:
    31 Dic 2009
    Mensajes:
    282
    Likes:
    41




    Hola amigos del foro.

    Consulta:
    Como puedo saber si una pagina web ya esta abierta en otra ventana/pestaña del mismo navegador?

    En Firefox, Chrome, IE, etc se pueden abrir varias pestañas/ventanas. Se puede abrir la misma web en mas de una pestaña/ventana.

    La cuestion es que ambas ventanas/pestañas compratiran la misma sesion y los cookies.

    Lo que deseo es, que si le usuario intenta abrir la web en una nueva pestaña/ventana del mismo navegador, detectarlo e impedir que lo haga.

    Se que eso debera hacerse del lado del cliente, por eso debera ser usando javascript/jquery.

    Por fi, si alguno lo sabe, se lo agradecere de sobre manera.
     


  2. Google

    Google Miembro frecuente

    Registro:
    4 May 2014
    Mensajes:
    113
    Likes:
    16
    No recuerdo muy bien.. pero creo que eso se podía hacer con Javascript (alert)
     
  3. UDcream

    UDcream Miembro de bronce

    Registro:
    13 Ago 2012
    Mensajes:
    1,701
    Likes:
    362
    No entiendo muy bien tu pregunta pero si te referies por ejemplo a abrir 2 cuentas de Facebook
    una la abres normal y en otra pestaña abres modo incognito y te permitira iniciar sesion con 2 cuentas distintas
     
  4. UnderUp

    UnderUp Miembro maestro

    Registro:
    31 Dic 2009
    Mensajes:
    282
    Likes:
    41
    En el mensaje inicial menciono ello, que se debe hacer con javascript/jquery. De todas formas, gracias por tu aporte.
     
  5. Google

    Google Miembro frecuente

    Registro:
    4 May 2014
    Mensajes:
    113
    Likes:
    16

    No sé si conoces esta web, pero ahi puedes pedir ayuda.


    :hi:
     
  6. DuckDuckGo

    DuckDuckGo Miembro nuevo

    Registro:
    5 May 2014
    Mensajes:
    32
    Likes:
    21
    Hola UnderUp :hi:
    Entiendo en cierto modo tu idea, pero solo déjame aclararte un par de cosas:
    - Cuando abres una misma sesión en diferentes navegadores, es probable que no puedas controlarlo con javascript, ya que si bien puede ser el mismo usuario, se crearán diferentes sesiones, en todo caso podrías controlarlo con PHP y MySQL, guardando la IP desde donde se inicia sesión y comparándola con la próxima sesión, ya que en todos los navegadores de tu computador la IP será la misma.
    - En caso que abras en un mismo navegador diferentes pestañas y quieras detectar si se ha iniciado sesión, y has guardado una galletita, por ejemplo con el ID del usuario (en código javascript se haría con document.cookie = 'usuario=ID_USUARIO', reemplazando el ID del usuario), debes comparar antes de eso si ya existe la galletita (en código javascript puede ser
    if (document.cookie.indexOf('usuario=') > -1) {
    // Ya existía la galletita
    alert('Va de retro satanás, que tu sesión iniciada ya está');
    } else {
    // No existía la galletita, se la crea
    document.cookie = 'usuario=1';
    }), además podrías ocultar o redirigir a otra parte al usuario, NO PUEDES cerrar la pestaña o ventana automáticamente, a menos que haya sido generada meramente con javascript (mediante un pop-up por ejemplo).
    Algunas veces me es complicado explicarme, espero haber podido ayudado en algo.
    Un saludo y nos vemos ya sabes dónde (en el buscador que no es ni Google ni Bing :D)
     
    A Edux147 le gustó este mensaje.
  7. UnderUp

    UnderUp Miembro maestro

    Registro:
    31 Dic 2009
    Mensajes:
    282
    Likes:
    41
    Sr. DuckDuckGo

    Muchas gracias por responder. Percibo que eres una persona entendido en el tema.

    Te respondo entre lineas:

    Lo que comentas no viene al caso, pero ampliando el tema, se que cuando se abre una sesion se genera una cookie, la cual identifica esa sesion Asi que, yendo al tema de seguridad, robando las cookies, te puedes hacer con una sesion ajena.
    Hay otras formas de identificar de manera unica a un equipo+navegador sin necesidad de cookies.

    Volviendo al tema, lo que pretendo es saber si en un mismo navegador + pc ya se encuentra mi pagina abierta en otra ventana/pestaña. Si ya esta abierta en otro lado, simplemente no cargar la pagina en darle el foco a la otra ventana/pestaña.

    Entiendo la idea, pero no has contemplado si el usuario refresca la pagina (F5); ya que si lo hace, cuando el usuario refreque la pagina, la galletita ya estaria ahi, por lo tanto, segun tu algoritmo, al refrescar la pagina saltaria el "Va de retro", asi sea la unica pestaña/ventana con la web cargada en cuestion.

    No te preocupes, al menos yo te entendi muy bien, lo lo explicaste de forma bastante clara y entendible. Y como te digo lineas arriba, pareces ser una persona entendida en el tema.

    Mas bien yo estaba pensando usar el objeto window, (window.name), asignarle un nombre al objetto window cuando el usuario se loguee, y cuando ya entre a la pagina logueada, chequear esa propiedad (Asi no guardamos galletitas que puedan ser robadas). De esa forma identificams mejor al usuario, y asi se roben las galleras, puedo identificar que es no es una sesion valida.

    Ademas, si abren otra pestaña, el windows.name se inicializaria en blanco, cosas que chaparia que no es una sesion valida o tomaria acciones.

    He estado haciendo pruebas preliminares, y parece que al refrescar la pagina (F5), la propiedad window.name se pierde. Creo que se debe a que estoy usando frames. Tengo ue hacer algunas pruebas para ver si al refrescar /F5) se pierde o no el valor de la propiedad.

    Espero tus comentarios.
     
  8. DuckDuckGo

    DuckDuckGo Miembro nuevo

    Registro:
    5 May 2014
    Mensajes:
    32
    Likes:
    21
    Hola amigo UnderUp, por favor no me digas señor que me siento algo vejestorio :biggrin:

    Te confesaré que llevo algunos años programando en Javascript y jamás me había enterado que el objeto global window tenía un atributo llamado name :w0w: debe ser como una etiqueta más de la estructura HTML (que tienen atributo name e id), en fin, lo que mencionas está muy bien, pero yo te recomendaría que te decantes más por tecnologías algo más modernas (ni tanto) como el objeto localStorage que te permitirá validar en cierto modo si la sesión (en un mismo navegador) ya se ha iniciado.

    Estuve jugando un rato con el código y aquí te lo paso https: //cloudup.com/cOTyg0EFKm3 (borra el espacio en la URL y descárgalo, creo que lo caracteres especiales no se visualizan bien)

    Si quieres verlo en ejecución, entra a https: //i.cloudup.com/uMjxp37mZF.html (para probarlo abre varias veces este link)

    Espero te sea de utilidad :yeah:
    Para terminar un consejo de un conejo: jamás, pero jamás confíes en Javascript, como dices es muy fácil copiar las galletitas e iniciar sesión en otra parte si se depende de ellas (por eso es recomendable usar sesiones alojadas en servidor) y por otra parte, tanto tu método como el mío son vulnerables, por ejemplo que pasa si yo abro mi consola y pongo window.name='UN_ID_DE_SESION' o también podría poner window.localStorage.id = 'UN_ID_DE_SESION', en realidad querer controlar todo con Javascript es un craso error que cometen algunos desarrolladores, te recomiendo que consideres también validar en el lado del servidor cualquier acción.

    Una anécdota que me pasó fue al registrarme en un conocido servicio de nube (no diré cual) y al intentar poner la contraseña como '1234' me decía que solo aceptaban contraseñas de más de 6 caracteres :oops: lo que hice fue abrir la consola, borrar el atributo pattern (del input en HTML5) presionar guardar... ¿y qué crees? se guardó correctamente :w0w: el servidor no me dijo nada, solo el cliente estaba verificando que mi contraseña tenga más de 6 caracteres :plop:

    Un saludo y espero sigas experimentando con las tecnologías web! :)
     
  9. UnderUp

    UnderUp Miembro maestro

    Registro:
    31 Dic 2009
    Mensajes:
    282
    Likes:
    41
    Hola DuckDuckGo

    Vuelvo a incidir... es evidente que conoces bastate del tema.
    Tienes razon, apartede validar en el cliente, hay que validar del lado del servidor tambien.

    Continuando con el tema.

    He estado haciendo pruebas, y al asignar un window.name, se mantiene la permanencia asi se refresque la pagina.
    Asi que, esa propiedad se comporta como una galletita (permanencia) mientras la ventana/pestaña se mantenga abierta. Claro que mucho mejor qu egalletita, ya que al no ser galletita, es menos evidente.
    Anteriormente no me funcionaba por que la web la corro (Y fuerzo que corra asi) dentro de in iframe.
    Claro que al ser javascript, puede ser accedido y no ser seguro, pero se plantea que se almacena el dato en un lugar mucho mucho menos evidente.
    Para un posible atacante, lo primero que intentaria secuestrar son las cookies.

    Te comento mas o menos lo que voy haciendo/probando:

    1) Robar una sesion de PHP es sumamente facil, jalando el dato de la cookie PHPSESSID (O al go asi, no recuerdo bien el nombre d ela cookie).

    Por cierto, me percato que la web peruhardware no tiene esa cookie muy a pesar que esta en PHP. Pero veo que usa varias tras cookies. Supongo que una de esas un una combinacion de esas seran la puerta de acceso para identificar al usuario/sesion.

    2) La idea es identificar al usuario por la cookie PHPSESSID + datoAdicional

    datoAdicional seria un dato generado del lado del cliente (Usando javascript) para identificar al navegador de forma unica.

    (SO + arquitectura + navegador + version navegador + cant plugins instalados + nombres plugins instalados + versiones plugins instalados + etc) Todo dato posible que se pueda sacar al cliente usando javascript.

    Con esa combinacion unica, y sacandole un hash, genero una clave unica para ese navegador en ese momento; y ese dato lo guardo com nombre de la ventana (window.name)

    Este dato permanecera vivo mientras la ventana este abierta, cuando lo cierre, el dato morira, y claro, permanecera viva asi refresque la ventana.

    3) Ese tado es transmitido al servidor unicamente al momento del logueo del usuario (Unica vez) y es registrado del lado del servidor.
    El codigo javascript que genera el hash y lo envia al server se ejecuta un una fraccion de codigo muy pequeño e inmediatamente regirige la pagina a la web con la sesion ya iniciada.
    De ver el codigo, el atacante lo podria ver con las herramientas de desarrollo del navegador (Firefox o chrome), pero veria el codigo pero no lo podria ejecutar, ya que eljavascript esincrustado y es un aseccion unica. Solo se puede ver e codigo descargado, pero no lo podria ejecutar, ya que la ejecucion sucede cuando se descarga, y no se almacena ya que inmediatamente se redirige la pagina. Lo podria ver pero como historial.

    4) Una vez logueado la sesion, cada peticion del cliente debera incluir el hash generado (Ya conocido por el server). Asi que el servidor cotejara el PHPSESSID y el hash. Comprobante de esa forma la validez de la peticion. Si se detecta que el PHPSESSID no empareha con el hash (dato que identifica la ventana del navegador) registrado el en server, se toman acciones (Se bloquea la peticion, se bloquea al usuario etc etc) y se alerta el usuario victima

    Consderaciones para el atacante:
    Todo esto lo hacemos considerando las siguientes condiciones que se deben dar para que el atacante haga su intento:

    1) Como PHPSESSID con el dato de sesion vive solo durante la sesion (Una vez el usuario cierra su sesion, el dato cambia). El atacante debera tener acceso a la cookie de la victima mientras la victima tenga una sesion abierta viva (Consideremos que la cookie tiene vencimiento, asi que si cierra el navegador sin cerrar sesion, la cookie caduca).
    En otra situacion, esa cookie no le serviria de nada al atacante.
    Eso que debemos tomar en cuenta que para que el usuaro logre tener acceso a la cookie, ha tenido que tener acceso fisico al equipo de la victima o meterle algun troyano o algun tipo de engaño para tener acceso a la cookie de forma remota.

    Haciendo las pruebas:
    1) Ataque de ejemplo A:
    - Abro sesion en navegador01.
    - Abro navegador02 y accedo a la misma url (Puede ser otro navegdor en la misma pc o en otra pc. Seria el navegador del atacante)
    - Copio la cookie PHPSESSID de navegador01 a navegador02.
    - Refresco pagina en navegador02. (Hasta este punto, sin ma modificacion hecha, el atacante ya tendria acceso a la sesion de la victima, y la victima no se daria por enterado, ya que el servidor identifica la sesion del navegador01 y navegador02 como la misma, y rsponde a ambos navegadores sin alertarse.
    - Ya con los cambios hechos, el navegador02 es asociado con la sesion de la victima, pero al cotejar el hash, el hash es diferente, y se detecta el fraude. Se devueve un mensaje de sesin corrupta y se marca el intento de acceso fraudulento para que el la proxima peticion del navegador01 se mande tambien un mensaje alertando del caso, o tmbien se podria bloquear el usuario, ya que de seguro el atacante volvera a intentar el accseso.
    - Hasta aqui, el primer caso funciona.

    2) Ataque de ejemplo B:
    - Abro navegador01 y me logueo (Abro una sesion).
    - Abro una nueva pestaña en navegador01 e ingreso la url.
    - La peticion al servidor se envia con un hash diferente (El window.name no ha sido generado, ya que este dato se genera en la pagina de logueo por unica vez).
    - El servidor detecta que no es el mismo hash, y alerta del caso.

    Hasta aca ya lo tengo hecho y funciona, lo que me falta es:
    - Identificar que el acceso se intento desde el mismo navegador y avisarle al usuario que ya tiene una ventana/pestaña abierta en el navegador.
    Para ello, se debe volver a identificar el navegador (Generando nuevamente el hash en la nueva ventana/pespaña) y denegar la segunda pesta{a/ventana, o igualmente abrirla de forma nornal (En caso sea mismo equipo/navegador.

    Espero no haber sido muy extenso en mi post, y haber sido comprensible no aburrido.

    Espero tus comentarios.

    Por cierto, tambien estava averigundo como mandar los formularios al servidor de forma crifrada (Sin usar https).
    Imagina que si cifro el formulario, y encima uso https, seria un doble cifrado.

    PD01. Atendiendo a tu comentario, tienes razon. Por la consola javascripp pueden modificar el window.name, pero para llegar a eso, el atacante ha tenido que estudiar mucho el tema, para haber identificado la forma de seguridad aplicada, l forma como genera el hash, la forma como se hace la peticion al servidor, etc.

    PD02: He revisado brevemente el ejemplo que me pusiste, y veo que u descargas toda la web, y muestras o ocultas el div si el dato guardado es el mismo.
    Por lo que veo, el objeto window.localStorage se mantiene entre varias pestañas para la misma web. En cambio el window.name, es diferente para cada pestaña.
    Se que el ejemplo que me pones es valido ya que es solo html, pero en mi caso, el php no envia la pagina, asi que en el html generado no habra div que ocultar. No se si me dejo entender, pero gracias por el dato.
    Vuelvo a incidir, se nota que sabes bastante del tema.
     
    Última edición: 14 May 2014
  10. DuckDuckGo

    DuckDuckGo Miembro nuevo

    Registro:
    5 May 2014
    Mensajes:
    32
    Likes:
    21
    Gracias por el dato, no sabía que podían ser tan inseguras las sesiones en PHP :paz:. Lo llevas bastante claro, mientras más datos encriptes para validar la sesión más aumentará la seguridad, pero más tiempo de ejecución (aunque sean centésimas de segundo) necesitará tu código.
    Saludos :hi:
     
  11. gnox

    gnox Miembro maestro

    Registro:
    3 Ene 2013
    Mensajes:
    794
    Likes:
    252
    Si me permiten aportar un granito ...

    - Para forzar que todo vaya hacia una ventana , todos los links de a href, open(url...) etc deberian usar la clausula target hacia tu window.name generado.
    -Si estas usando php hay un parametro (set cookie httponly) que hace que las cookies solo sean disponibles para el HttpServer y no para el DOM del browser (javascript) "manteniendo la privacidad" de la sesión.
    - El codigo de hasheo al ser javascript se puede visualizar y ejecutar en cualquier browser, via Xss o desde una consola; aparte lo que quieres hashear ya esta en el user-agent-header del http request (navegador, version, sistema operativo); preferible deberia ser generado del lado del servidor tomando como dato principal la IP del usuario. Se puede hacer mas dificil la lectura del javascript si usas herramientas de compactacion y obfuscamiento tipo UglifyJS.
    - Un ataque man in middle puede extraer las cookies (y hasta todo el contenido http) solo con los paquetes tcp (usando wireshark o tcpdump), solo sabiendo la ip destino sea en red local o si esta publicado en internet el sitio; para evitarlo es preferible implementar https.
    - Cada campo de la aplicacion deberia ser prevalidado para que no contenga html/js (para evitar Xss) .
    - Encriptacion de la informacion depende del volumen de datos, rehacer el encriptamiento en transporte es rehacer la rueda : https, si vas a ha hacer un codigo de encriptar y de ahi pasarlo por https seria lo mismo de subir el algoritmo de SSL/RSA de 512 a 1024 o a 2048 o a 4096 al generar el certificado.
    - El hecho de no permitirle abrir mas ventanas al usuario hace que la aplicacion sea lineal y no multitarea pero esto ya depende de la habilidad de los usuarios que tengas.
     
  12. UnderUp

    UnderUp Miembro maestro

    Registro:
    31 Dic 2009
    Mensajes:
    282
    Likes:
    41
    Hola gnox.
    Gracias por tu aporte. Es bueno saber que en este foro hay gente que conoce bastante del tema.

    Te comento entre lineas.

    El tema de prohibir otras ventanas/pestañas ya lo solucione, y funciona. Me ayudo mucho el aporte del usuario DuckDuckGo, ya que me comento de localStorage que desconocia y que me resulto muy util para solventar el tema.

    El parametro que mencionas lo desconocia. Gracias por el dato! Segun entiendo, al usar ese parametro, las cookies no seran accesibles desdde javascript (Lo cual es bueno, asi no se podra manipularlo) y solo estara disponible al server.

    Efectivamente, el codigo para el hasheo esta en javascript, pero este solo se carga (por un instante muy corto) en el browser si y solo si el usuario se loguea. Asi que si el usuario no se loguea de forma valida, ese codigo nunca llegara al browser.

    Tambien tienes razon, me di cuenta de ello. Es por ello que parte del emparejamiento lo hago sacando datos del cliente desde el server (Los que se pueda sacar, como navegaror, versio, SO, etc). Pero tambien genero hash desde otros datos del browser que solo puedo recolectar con JS (Informacion referente a los plugins instalados).

    De esa forma, aparte de validar el navegador, version, SO, tambien valido los plugins instalados y las respectivas versiones. De esa forma, se estrecha mas la ventana que tiene el posible atacante.

    Tambien tienes razon. Pero el tema es que a corto plazo no veo poner https. Es mas, es muy posible que el servicio se de en un server alquilado, y como es para empezar, sera con el que tiene ma menos cuota. Asi que veo formas de mitigar en lo que se pueda cualquier intento de acceso no autorizado.

    Eso ya esta hecho.

    Tambien tienes razon. La cuestion es que si no tengo https; si chapan los paquetes al vuelo, el dato estara cifrado, y como lo ven como texto plano, el atacante podria presumir que el dato que ha chapado es valido.

    Ese tema tambien ya lo resolvi.
    No se permite que el usuario abra una nueva ventana/pestaña e ingrese la url de forma manual. En ese caso rebotara la peticion.
    En cambio, dentro de una sesion ya abierta, colocando un boton/link y usando window.open; si puedo abrir una nueva ventana/pestaña. Notese que solo lo podran hacer desde una ventana con la sesion ya iniciada.

    Adicionalmente, si el se detecta condiciones que definan un ataque por robo de cookies y/o sesion, la peticion se rechaza y se marca en la db el intento de ataque. De sa forma, es posible alertar al usuario victima.
    Si hay un X cantidad de intentos de ataque, ya se bloquea la cuenta del ususario.

    Espero sus comentarios.
     
  13. DuckDuckGo

    DuckDuckGo Miembro nuevo

    Registro:
    5 May 2014
    Mensajes:
    32
    Likes:
    21
    Genio total! :wow: tampoco lo conocía, gracias por tu aporte :yeah:
    Te daría me gusta, pero PH no me deja aún :ptm:
     
Etiquetas: