Detect if browser is using Private Browsing mode

I am creating an extranet for a company paranoid about security. They want to make sure that (among other things) their users browse the site with Private Browsing turned on in their web browser, so cookies and history are not saved.

I only found this http://jeremiahgrossman.blogspot.com/2009/03/detecting-private-browsing-mode.html as well as https://serverfault.com/questions/18966/force-safari-to-operate-in -private-mode-and-detect-that-state-from-a-webserver

An ideal solution would not use any or minimal javascript. Will there be an attempt to set a unique cookie operation for all browsers and platforms? Has anyone done this before?

thank!




update

http://crypto.stanford.edu/~collinj/research/incognito/ uses the CSS browser technique described by other posters, thanks to the tips.

I like it because it is small and elegant, but still want to be able to do this without javascript, if possible.

+61
javascript html security browser cookies
May 18 '10 at 20:28
source share
16 answers

June 2019 update

Google removes the ability to constantly determine the private browsing mode in Chrome 76 onwards. So if you want to detect private browsing, now it’s not possible (unless you find a way to do it that Google did not find). The ability to detect a private view was recognized as a mistake and was never intended.

For anyone who has come across this question, please note that since 2014 there is no reliable or accurate way to determine if someone is viewing in incognito / private / secure browsing through Javascript or CSS. Previous solutions that once worked as a CSS hacker story have since become inaccessible to all browser providers.

There should never be a situation where the discovery of a private browsing mode on a regular everyday website is ever required. People choose to browse anonymously or non-anonymously for their own reasons.

Browsers such as Chrome and Firefox no longer disable features such as localStorage. They simply put the namespace in a temporary location to prevent errors on sites that use it. When you finish browsing, the namespace is erased and nothing is saved. If you test localStorage support regardless of mode, it will always return true for browsers that support it.

Other private mode detection tools in Chrome are specially fixed and will no longer work.

If this is required internally, you should develop a browser plugin. In particular, Chrome and Firefox provide an internal API that allows plugins to check whether the user is in private browsing / incognito mode and act accordingly. This cannot be done outside the plugin.

+51
Mar 25 '14 at 1:41
source share

Here's an easier way to determine your privacy mode. This only works in Safari. I created it because the web application being developed uses localStorage. LocalStorage is not available in Safari in privacy mode, so my application will not work. When loading the page, run the script below. It shows a warning window if we cannot use 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
Jul 19 '13 at 8:44
source share

UPDATED : Chrome has been further developed and no longer leaves room for detection when using incognito mode.

Private browsing modes can be detected for most browsers in use. This includes Safari, Firefox, IE10, Edge, and Google Chrome.




Firefox

When Firefox's private browsing mode is enabled, IndexedDB throws an InvalidStateError because it is not available in private browsing mode.

Very, if that:

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

Safari

For Safari, the key is the local storage service. This is disabled in privacy mode. So try to access it and use the try-catch clause. The following method works on OSX and iOS devices. Loans for this method are collected for this question and answer.

 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 Explorer is even about to disable IndexedDB in privacy mode. So check for existence. But this is not enough, because older browsers may not even have IDBs. So do one more check, for example for events that are only in IE10 and subsequent browsers. The relevant question on CodeReview can be found here.

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

Chrome

Update : this does not work with Chrome 76 (thanks @jLynx)

Chromes incognito mode can be checked by the file system. A great explanation can be found here on 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
Dec 25 '16 at 15:00
source share

Here is my view on private mode discovery

 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 found a modern, faster and more synchronized way to try it in Firefox (they do not have attendants in private mode), similar to i.e. not including indexedDB, but the test only works on secure sites

 : "MozAppearance" in document.documentElement.style ? navigator.serviceWorker ? off() : on() 
+16
May 7 '16 at 16:37
source share

There is no way for your web page to know exactly what the user is in private browsing mode. Any attempts to test various browser features will need to change frequently as security systems are updated. It may work for some time in some browsers, but not in all.

If the company is concerned about security, I suggest moving your own Firefox or Chromium distribution with locked privacy settings and allowing only a custom client to connect to the extranet.

+14
May 18 '10 at 20:38
source share

The triple localStorage bug has been fixed and it no longer works in Safari 11.0.

There is an interesting alternative that works in Safari, Opera, and Internet Explorer (not Chrome): these browsers send the DNT: 1 (Do Not Track) header.

It is not 100% reliable, since this header can be enabled for normal viewing (it is disabled by default), but it can help identify users who are not involved in maintaining confidentiality.

+4
Jul 12 '17 at 9:49 on
source share

I created a small library that will work on all major tested platforms and browsers: https://github.com/jLynx/PrivateWindowCheck

You can just call

 isPrivateWindow(function(is_private) { if(is_private) alert('Private'); else alert('Not Private'); }); 
+4
Mar 18 '19 at 23:56
source share

You are not going to block them if they do not have a closed browser.

Why do you have a smart box?

Will there be an attempt to set a unique cookie operation for all browsers and platforms? Has anyone done this before?

I think the most elegant solution would be:

  • Perform a safety leak test
  • If a security leak test detects a problem
    • Notify user to check settings
    • Suggest privacy mode

Because, as you said, not everyone can or should enable privacy mode.

+3
Oct 25 '11 at 16:26
source share

Web browsers behave differently when privacy mode is activated.

In many browsers, resource caching is limited. You can find where the browser was based on their CSS cache. It is possible to carry out this attack without JavaScript .

EFF is working on a fingerprint project. Parts of the fingerprint of the browser will differ when privacy mode is activated. Go ahead, try it .

+2
May 19 '10 at 11:21
source share

I agree with DigitalSeas’s mood that we usually don’t try to determine if the user is in “private browsing” mode. However, I recently discovered that FireFox is now subscribing to the “disconnect.me” service, which provides a blacklist of URLs that they use in their “tracking function” . Since disconnect.me is a blacklist of certain social networks (for example, Facebook facebook.net ), we found that their SDKs will not load in FireFox. Therefore, it seems reasonable that we can try to detect a private browsing mode to provide users with a more useful and accurate error message.

Given this excuse, this gist claims to provide detection for private browsing in major browsers using tricks specific to those browsers. At the time of this writing (an entity can be updated by the time you read it), the discovery logic is as follows:

 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
Apr 27 '16 at 19:39
source share

Well, you wouldn’t distinguish private mode from “block all cookies” in this way, but besides this rare situation, I think it should work.




IMO’s big problem is that it’s a very poor site design, no better than the good “you need xxx browser to see this site”, which was distributed in the 90s. Not all browsers have a private browsing mode (as far as I despise IE, for example, cut IE7 users), and these users will not be able to access your site at all.

In addition, when I am on the Internet, I often have several tabs open with several websites. It would be very unpleasant for me to switch to private mode to see this site and not have access to other sites at the same time.

One thing you could do is design your site using sessions instead of cookies, so they won’t be saved (since you don’t use them ...). And as for the story ... really, what's the problem with that?

+1
May 18 '10 at 20:39
source share
 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
Apr 2 '19 at 19:00
source share

I solved this problem using two HTML pages. A status variable is set on the main page and a cookie is set. The second page opens in a new window (not a tab), reads the cookie and sets the status to cookie. In MSIE, the cookie value is passed to the child page when the main page is in normal mode. When in InPrivate browsing mode, the cookie value is not passed to the child page (but passed if you open a new tab).

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> 

Page child.html :

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

I use InPrivate browsing mode to prevent the inclusion of browser helper objects (BHOs) and browser extensions, since BHOs ​​are most often malicious programs that can modify web pages even if HTTPS and strong authentication are used. Internet Explorer 9 has "Disable toolbars and extensions when starting InPrivate Browsing" in the "Privacy" settings.

However, this is not the best way to prevent the spread of a malicious browser: a malicious extension can change the behavior of the main page to make it think that myCookie not set and. We mistakenly assumed that we were in InPrivate browsing mode.

Please note that I need cookies for my application, so I do not use InPrivate Browsing for this purpose.

0
Jul 17 '13 at 23:34 on
source share

Enter the code to achieve the following

1) In the browser version of the Firefox browser. This method works with version> = 33.0 (supports service workers). You cannot use this method with older (<33.0) versions.

2) Try installing a service worker. 3) If you can install, use or access a service employee, you are not working in private browsing mode for 1000%, since service workers cannot interact with the normal Firefox browsing mode. I want them to be like that.

Quote:

"In Firefox, the Service Worker APIs are hidden and cannot be used when the user is in private browsing mode"

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

0
04 Oct '16 at 22:48
source share

Not sure if the reason for this is old, but Firefox provides documentation on how to define a private view . However, it does include the use of its 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
08 Mar '17 at 1:19 on
source share

When I created my Safari extension, I found that I could query the boolean value safari.self.browserWindow.activeTab.private . The following worked for me to check if the browser was open privately or not, but only from the 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 | Private property of an instance

0
Mar 24 '19 at 13:37
source share



All Articles