web-dev-qa-db-fra.com

Détecter si un navigateur utilise le mode de navigation privée

Je construis un extranet pour une entreprise paranoïaque en matière de sécurité. Ils veulent s'assurer (entre autres) que leurs utilisateurs naviguent sur le site avec le mode de navigation privée activé dans leur navigateur Web afin qu'aucun cookie ou historique ne soit conservé.

Je n'ai trouvé que cela http://jeremiahgrossman.blogspot.com/2009/03/detecting-private-browsing-mode.html et https://serverfault.com/questions/18966/force-safari-to-operation-in-private-mode-and-detect-that-state-from-a-webserver

La solution idéale utiliserait pas ou peu de javascript. Est-ce que tenter de définir un cookie unique fonctionnerait pour tous les navigateurs et plates-formes? Quelqu'un a fait ça avant?

merci!


mise à jour

http://crypto.stanford.edu/~collinj/research/incognito/ utilise la technique CSS visitée des empreintes digitales du navigateur mentionnées par d'autres affiches - merci pour les conseils.

Je l'aime parce qu'il est petit et élégant, mais je veux quand même pouvoir le faire sans javascript si possible.

59
Steve

Mise à jour juin 2019

Google est supprimant la capacité pour détecter le mode de navigation privée de manière permanente dans Chrome 76 à partir de maintenant. Donc, si vous voulez détecter la navigation privée, il est maintenant impossible (sauf si vous trouvez un moyen de le faire que Google n'a pas trouvé.) La capacité de détecter le mode de navigation privée a été reconnue comme un bug et n'a jamais été voulue.

Pour toute autre personne rencontrant cette question, veuillez noter qu'à partir de 2014, il n'existe aucun moyen fiable ou précis de détecter si quelqu'un navigue en mode navigation privée/privée/sécurisée via Javascript ou CSS. Les solutions précédentes qui fonctionnaient autrefois comme le piratage de l'historique CSS ont depuis été rendues inutilisables par tous les fournisseurs de navigateurs.

Il ne devrait jamais y avoir de situation où la nécessité de détecter le mode de navigation privée sur un site Web quotidien normal soit nécessaire. Les gens choisissent de naviguer de manière anonyme et non anonyme pour leurs propres raisons.

Les navigateurs comme Chrome et Firefox ne désactivent plus les fonctionnalités telles que localStorage. Ils ne font que les nommer dans un emplacement temporaire pour empêcher les sites Web qui les utilisent de commettre des erreurs. Une fois que vous avez fini de naviguer, l'espace de noms est effacé et rien n'est enregistré. Si vous testez la prise en charge de localStorage quel que soit le mode, il retournera toujours vrai pour les navigateurs qui le prennent en charge.

D'autres moyens de détecter le mode privé dans Chrome spécifiquement ont été complètement corrigés et ne fonctionneront plus.

S'il est requis en interne par une entreprise, vous devez développer un plugin de navigateur. Chrome et Firefox, en particulier, exposent les API internes qui permettent aux plugins de vérifier si l'utilisateur est en mode navigation privée/navigation privée et d'agir en conséquence. Cela ne peut pas être fait en dehors d'un plugin.

48
Dwayne Charrington

Voici un moyen plus simple de détecter le mode de confidentialité. Cela fonctionne uniquement dans Safari. Je l'ai créé parce qu'une application web que je développe utilise localStorage. LocalStorage n'est pas disponible dans Safari en mode confidentialité, donc mon application ne fonctionnera pas. Au chargement de la page, exécutez le script ci-dessous. Il affiche une boîte d'alerte si nous ne pouvons pas utiliser localStorage.

try {
  // try to use localStorage
  localStorage.test = 2;        
} catch (e) {
  // there was an error so...
  alert('You are in Privacy Mode\nPlease deactivate Privacy Mode and then reload the page.');
}
40
Jez D

[~ # ~] mis à jour [~ # ~] : Chrome s'est développé davantage et ne laisse plus d'espace pour la détection lors de l'utilisation du mode navigation privée.

Il est possible de détecter les modes de navigation privée activés pour la majorité des navigateurs utilisés. Cela inclut Safari, Firefox, IE10, Edge et Google Chrome.


Firefox

Lorsque le mode de navigation privée de Firefox est activé, IndexedDB lance une InvalidStateError car elle n'est pas disponible en mode de navigation privée.

Trop si ça:

var db = indexedDB.open("test");
db.onerror = function(){/*Firefox PB enabled*/};
db.onsuccess =function(){/*Not enabled*/};

Safari

Pour Safari, la clé est le service de stockage local. Il est désactivé en mode confidentialité. Essayez donc d'y accéder et utilisez une clause try-catch. La méthode suivante fonctionne sur les appareils OSX et iOS. Les crédits pour cette méthode vont cette question et réponse

var storage = window.sessionStorage;
try {
    storage.setItem("someKeyHere", "test");
    storage.removeItem("someKeyHere");
} catch (e) {
    if (e.code === DOMException.QUOTA_EXCEEDED_ERR && storage.length === 0) {
        //Private here
    }
}

IE10/Edge

Internet Explore va même désactiver l'IndexedDB en mode confidentialité. Vérifiez donc l'existence. Mais cela ne suffit pas, car les anciens navigateurs n'ont peut-être même pas de IDB. Faites donc une autre vérification, par ex. pour les événements que seuls IE10 et le navigateur suivant ont/trigger. Une question connexe sur CodeReview peut être trouvée ici

if(!window.indexedDB && (window.PointerEvent || window.MSPointerEvent)){
 //Privacy Mode
}

Chrome

Mise à jour : Cela ne fonctionne pas depuis Chrome 76 (merci à @jLynx)

Le mode Chromes Incognito peut être vérifié par le système de fichiers. Une grande explication peut être trouvée ici sur SO

var fs = window.RequestFileSystem || window.webkitRequestFileSystem;
if (!fs) {
    console.log("FS check failed..");
    return;
}

fs(window.TEMPORARY, 100, function (fs) {}, function (err) {
//Incognito mode
});
22
manniL

Voici mon point de vue sur la détection du mode privé

function detectPrivateMode(cb) {
    var db,
    on = cb.bind(null, true),
    off = cb.bind(null, false)

    function tryls() {
        try {
            localStorage.length ? off() : (localStorage.x = 1, localStorage.removeItem("x"), off());
        } catch (e) {
            // Safari only enables cookie in private mode
            // if cookie is disabled then all client side storage is disabled
            // if all client side storage is disabled, then there is no point
            // in using private mode
            navigator.cookieEnabled ? on() : off();
        }
    }

    // Blink (chrome & opera)
    window.webkitRequestFileSystem ? webkitRequestFileSystem(0, 0, off, on)
    // FF
    : "MozAppearance" in document.documentElement.style ? (db = indexedDB.open("test"), db.onerror = on, db.onsuccess = off)
    // Safari
    : /constructor/i.test(window.HTMLElement) || window.safari ? tryls()
    // IE10+ & Edge
    : !window.indexedDB && (window.PointerEvent || window.MSPointerEvent) ? on()
    // Rest
    : off()
}

detectPrivateMode(function (isPrivateMode) {
    console.log('is private mode: ' + isPrivateMode)
})

edit a trouvé un moyen synkronas moderne et plus rapide de l'essayer dans firefox (ils n'ont pas de service workers en mode privé) similaire à ie don't inclure indexedDB mais le test ne fonctionne que dans les sites sécurisés

: "MozAppearance" in document.documentElement.style ? navigator.serviceWorker ? off() : on()
16
Endless

Il n'y a aucun moyen pour votre page Web de savoir, absolument avec certitude, que l'utilisateur est en mode de navigation privée. Toute tentative de vérification des diverses fonctionnalités du navigateur devra être modifiée à mesure que les implémentations de sécurité sont mises à jour. Cela peut fonctionner pendant un certain temps dans certains navigateurs, mais pas tous.

Si l'entreprise est préoccupée par la sécurité, je suggère de déployer votre propre distribution Firefox ou Chromium avec des paramètres de confidentialité verrouillés et de ne permettre à ce client personnalisé de se connecter à l'extranet.

14
Matt S

L'astuce localStorage est n bug qui a été corrigé , et cela ne fonctionne plus dans Safari 11.0.

Il existe une alternative intéressante qui fonctionne dans Safari, Opera et Internet Explorer (pas Chrome): ces navigateurs envoient un DNT: 1 en-tête (Ne pas suivre).

Il n'est pas fiable à 100% car cet en-tête peut être activé pour la navigation normale (il est désactivé par défaut), mais il peut aider à identifier les utilisateurs soucieux de la confidentialité.

4
Julien

Vous n'allez pas les bloquer s'ils n'ont pas activé la navigation privée.

Pourquoi avoir une boîte de message intelligente?

Est-ce que tenter de définir un cookie unique fonctionnerait pour tous les navigateurs et plates-formes? Quelqu'un a fait ça avant?

Je pense que la solution la plus élégante serait de:

  • Effectuer un test de fuite de sécurité
  • Si le test de fuite de sécurité révèle un problème
    • Dites à l'utilisateur de vérifier les paramètres
    • Suggérer un mode de confidentialité

Parce que, comme vous l'avez dit, tout le monde ne peut pas ou n'a pas besoin d'activer le mode de confidentialité.

3
Lee Louviere

J'ai construit une petite bibliothèque qui fonctionnera sur toutes les principales plates-formes et navigateurs que j'ai testés: https://github.com/jLynx/PrivateWindowCheck

Vous pouvez simplement appeler

isPrivateWindow(function(is_private) {
    if(is_private)
        alert('Private');
    else
        alert('Not Private');
});
3
jLynx

Je suis d'accord avec le sentiment de DigitalSeas selon lequel nous ne devrions généralement pas essayer de détecter si l'utilisateur est en mode "navigation privée". Cependant, j'ai récemment découvert que FireFox s'abonne désormais à un service appelé "déconnecter.me", qui fournit la liste noire d'URL qu'ils utilisent dans leur "protection contre le suivi" . Étant donné queonnect.me met sur liste noire certains réseaux sociaux (par exemple, Facebook facebook.net ), nous avons constaté que leurs SDK ne se chargeraient pas dans FireFox. Par conséquent, il semble raisonnable que nous puissions essayer de détecter le mode de navigation privée afin de fournir un message d'erreur plus utile et précis à nos utilisateurs.

Avec cette justification à l'écart, ce Gist prétend fournir une détection pour la navigation privée dans les principaux navigateurs en utilisant des astuces spécifiques à ces navigateurs. Au moment d'écrire ces lignes (le Gist peut avoir été mis à jour au moment où vous lisez ceci) la logique de détection est la suivante:

function retry(isDone, next) {
    var current_trial = 0, max_retry = 50, interval = 10, is_timeout = false;
    var id = window.setInterval(
        function() {
            if (isDone()) {
                window.clearInterval(id);
                next(is_timeout);
            }
            if (current_trial++ > max_retry) {
                window.clearInterval(id);
                is_timeout = true;
                next(is_timeout);
            }
        },
        10
    );
}

function isIE10OrLater(user_agent) {
    var ua = user_agent.toLowerCase();
    if (ua.indexOf('msie') === 0 && ua.indexOf('trident') === 0) {
        return false;
    }
    var match = /(?:msie|rv:)\s?([\d\.]+)/.exec(ua);
    if (match && parseInt(match[1], 10) >= 10) {
        return true;
    }
    return false;
}

function detectPrivateMode(callback) {
    var is_private;

    if (window.webkitRequestFileSystem) {
        window.webkitRequestFileSystem(
            window.TEMPORARY, 1,
            function() {
                is_private = false;
            },
            function(e) {
                console.log(e);
                is_private = true;
            }
        );
    } else if (window.indexedDB && /Firefox/.test(window.navigator.userAgent)) {
        var db;
        try {
            db = window.indexedDB.open('test');
        } catch(e) {
            is_private = true;
        }

        if (typeof is_private === 'undefined') {
            retry(
                function isDone() {
                    return db.readyState === 'done' ? true : false;
                },
                function next(is_timeout) {
                    if (!is_timeout) {
                        is_private = db.result ? false : true;
                    }
                }
            );
        }
    } else if (isIE10OrLater(window.navigator.userAgent)) {
        is_private = false;
        try {
            if (!window.indexedDB) {
                is_private = true;
            }                 
        } catch (e) {
            is_private = true;
        }
    } else if (window.localStorage && /Safari/.test(window.navigator.userAgent)) {
        try {
            window.localStorage.setItem('test', 1);
        } catch(e) {
            is_private = true;
        }

        if (typeof is_private === 'undefined') {
            is_private = false;
            window.localStorage.removeItem('test');
        }
    }

    retry(
        function isDone() {
            return typeof is_private !== 'undefined' ? true : false;
        },
        function next(is_timeout) {
            callback(is_private);
        }
    );
}
2
Jackson

Navigateurs Web se comportent différemment lorsque le mode de confidentialité est activé.

Sur de nombreux navigateurs, la mise en cache des ressources est limitée. Il est possible de détecter où un navigateur a été en fonction de leur cache CSS. Il est possible de mener cette attaque sans JavaScript .

L'EFF travaille sur un projet pour navigateurs d'empreintes digitales . Certaines parties de l'empreinte digitale du navigateur seront différentes lorsque le mode de confidentialité est activé. Allez-y, essayez-le .

2
rook

Eh bien, vous ne distingueriez pas vraiment le mode privé de "bloquer tous les cookies" de cette façon, mais à part cette situation rare, je suppose que cela devrait fonctionner.


Le gros problème de l'OMI, c'est qu'il s'agit d'une conception de site très très mauvaise, pas meilleure que le bon vieux "vous avez besoin du navigateur xxx pour voir ce site Web" qui était courant dans les années 90. Tous les navigateurs n'ont pas de mode de navigation privée (autant que je méprise IE, vos utilisateurs d'IE7 par exemple) et ces utilisateurs ne pourront pas du tout accéder à votre site.

De plus, lorsque je suis sur Internet, j'ai souvent plusieurs onglets ouverts avec plusieurs sites Web. Ce serait vraiment ennuyeux pour moi de devoir passer en mode privé juste pour voir ce site Web et ne pas pouvoir accéder aux autres sites en même temps.

Une chose que vous pourriez faire serait de concevoir le site à l'aide de sessions au lieu de cookies, afin qu'ils ne soient pas stockés (car vous ne les utilisez pas ...). Et quant à l'histoire ... vraiment, quel est le problème avec ça?

1
nico
function isPrivate(callback) {
  callback || (callback = function(){});
  var fs = window.RequestFileSystem || window.webkitRequestFileSystem;

  if(fs){
    return fs(window.TEMPORARY, 1, callback.bind(this, false), callback.bind(this, true));
  }

  if(window.indexedDB && /Firefox/.test(window.navigator.userAgent)){
    try {
      var db       = window.indexedDB.open('test');
      var tryes    = 0;
      var interval = limit = 10;

      var wait = function(check){
        if(tryes >= limit){ return callback(true); } // Give up
        return window.setTimeout(check, ++tryes * interval);
      }

      var evaluate = function(){
        return db.readyState === 'done' ? callback(!db.result) : wait(evaluate);
      }

      return wait(evaluate);
    } catch (e) {
      return callback(true);
    }
  }

  if (!!window.navigator.userAgent.match(/(MSIE|Trident|Edge)/)){
    try {
      return callback(!window.indexedDB);
    } catch (e) {
      return callback(true);
    }
  }

  try {
    window.openDatabase(null, null, null, null);
    return callback(false);
  } catch (e) {
    return callback(true);
  }
}

isPrivate( function(isPrivate) {
  console.log('Private mode ===>', isPrivate);
});
1
Chicho

Écrire du code pour réaliser le suivi

1) Dans la version du navigateur de test Firefox. Cette méthode fonctionne avec la version> = 33.0 (prend en charge les travailleurs de service). Impossible d'utiliser cette méthode avec les anciennes versions (<33.0).

2) Essayez de définir le technicien de service. 3) Si vous pouvez définir, utiliser ou accéder à un travailleur de service, vous n'êtes pas à 1000% en mode de navigation privée car les travailleurs de service ne peuvent pas interagir avec le mode de navigation privée de Firefox. Je souhaite qu'ils puissent l'être.

Citation:

"Dans Firefox, les API Service Worker sont masquées et ne peuvent pas être utilisées lorsque l'utilisateur est en mode de navigation privée"

https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API/Using_Service_Workers

0
douglas

Je ne sais pas si sa cause est ancienne, mais Firefox fournit de la documentation sur comment détecter le mode de navigation privée . Cependant, cela implique d'utiliser une de leurs importations DXR PrivateBrowsingUtils :

try {
      // Firefox 20+
      Components.utils.import("resource://gre/modules/PrivateBrowsingUtils.jsm");
      if (!PrivateBrowsingUtils.isWindowPrivate(window)) {
        ...
      }
    } catch(e) {
      // pre Firefox 20 (if you do not have access to a doc. 
      // might use doc.hasAttribute("privatebrowsingmode") then instead)
      try {
        var inPrivateBrowsing = Components.classes["@mozilla.org/privatebrowsing;1"].
                                getService(Components.interfaces.nsIPrivateBrowsingService).
                                privateBrowsingEnabled;
        if (!inPrivateBrowsing) {
          ...
        }
      } catch(e) {
        Components.utils.reportError(e);
        return;
      }
    }
0
aug

J'ai résolu ce problème en utilisant deux pages HTML. La page principale définit une variable d'état et définit un cookie. La deuxième page est ouverte dans une nouvelle fenêtre (pas d'onglet), lisez le cookie et définissez le statut sur la valeur du cookie. Sous MSIE, la valeur du cookie est transmise à la page enfant lorsque la page principale en mode normal. En mode de navigation InPrivate, la valeur du cookie n'est pas transmise à la page enfant (mais est transmise si vous ouvrez un nouvel onglet).

Le main.html page:

<script>     
var myCookie="nocookie";
document.cookie="checkInPrivate=1";
var h=window.open("child.html", "_blank", "left=9999,height=200,width=200");
setTimeout(function() {
    var status=null;
    if (myCookie=="nocookie") {
        status="unable to determine if we are InPrivate Browsing mode (child page did not set the cookie)";
    } else if (myCookie.indexOf("checkInPrivate")>=0) {
        status="not in InPrivate Browsing mode (child page did set the cookie)";
    } else {
        status="in InPrivate Browsing mode (child page set the cookie value but it was not provided)";
    }
    alert(status);
}, 200);
</script>

Le child.html page:

Detecting MSIE's InPrivate Browsing mode...
<script>
window.opener.myCookie=document.cookie;
window.close();
</script>

J'utilise le mode de navigation InPrivate afin d'empêcher les objets d'aide au navigateur (BHO) et les extensions de navigateur d'être activés, car les BHO sont le plus souvent des malwares qui peuvent modifier les pages Web même si HTTPS et une authentification forte sont utilisés. Internet Explorer 9 possède une "Désactiver les barres d'outils et les extensions lorsque la navigation InPrivate démarre" dans ses paramètres "Confidentialité".

Cependant, ce n'est pas le moyen ultime d'empêcher une extension de navigateur malveillante: une extension malveillante peut changer le comportement de la page principale pour lui faire penser que la valeur myCookie n'a pas été définie et. Nous supposerions à tort que nous sommes en mode de navigation InPrivate.

Notez que j'ai besoin de cookies pour mon application, donc je n'utilise pas la navigation InPrivate à cette fin.

0
Julien Kronegg

Lors de la création de mon extension Safari, j'ai découvert qu'il était possible d'interroger le booléen safari.self.browserWindow.activeTab.private . Ci-dessous a fonctionné pour moi de vérifier si le navigateur était ouvert en privé ou non, mais uniquement à partir de l'extension.

isPrivate = false;
try {
isPrivate = safari.self.browserWindow.activeTab.private;
} catch (_) {
isPrivate = true;
}
if (isPrivate === true){
console.log("Private window.");}
else {
console.log("Not private window.");}

Source: developer.Apple.com | Propriété d'instance privée

0
Robin Oberg