Подтвердить что ты не робот

Обнаружение, если браузер использует режим Private Browsing

Я создаю экстрасеть для компании, параноидальной о безопасности. Они хотят удостовериться, что (среди прочего) их пользователи просматривают сайт с включенным режимом Private Browsing в своем веб-браузере, поэтому cookie и история не сохраняются.

Я нашел только это http://jeremiahgrossman.blogspot.com/2009/03/detecting-private-browsing-mode.html а также https://serverfault.com/info/18966/force-safari-to-operate-in-private-mode-and-detect-that-state-from-a-webserver

Идеальное решение не будет использовать никакой или минимальный javascript. Будет ли попытка установить уникальную работу cookie для всех браузеров и платформ? Кто-нибудь сделал это раньше?

спасибо!


update

http://crypto.stanford.edu/~collinj/research/incognito/ использует технику браузера CSS, описанную другими плакатами, благодаря подсказкам.

Мне нравится, потому что он маленький и изящный, но все же хочу иметь возможность делать это без javascript, если это возможно.

4b9b3361

Ответ 1

Обновление от июня 2019 года

Google удаляет возможность постоянно определять режим приватного просмотра в Chrome 76 и далее. Так что, если вы хотите обнаружить приватный просмотр, теперь это невозможно (если вы не найдете способ сделать это, которого Google не нашел). Возможность обнаружения приватного режима просмотра была признана ошибкой и никогда не предназначалась.

Для всех, кто сталкивался с этим вопросом, обратите внимание, что с 2014 года не существует надежного или точного способа определить, просматривает ли кто-то в режиме инкогнито/приват/безопасный просмотр через Javascript или CSS. Предыдущие решения, которые когда-то работали как хакерская история CSS, с тех пор стали недоступными для всех поставщиков браузеров.

Никогда не должно быть ситуации, когда когда-либо требуется обнаружение режима частного просмотра на обычном повседневном веб-сайте. Люди выбирают просмотр анонимно или не анонимно по своим причинам.

Браузеры, такие как Chrome и Firefox, больше не отключают такие функции, как localStorage. Они просто помещают пространство имен во временное местоположение, чтобы предотвратить появление ошибок на сайтах, которые его используют. По завершении просмотра пространство имен стирается и ничего не сохраняется. Если вы тестируете поддержку localStorage независимо от режима, она всегда будет возвращать true для браузеров, которые ее поддерживают.

Другие средства обнаружения частного режима в Chrome специально исправлены и больше не будут работать.

Если это требуется внутри компании, вам следует разработать плагин для браузера. В частности, Chrome и Firefox предоставляют внутренний API, который позволяет плагинам проверять, находится ли пользователь в режиме приватного просмотра/инкогнито, и соответственно действовать. Это не может быть сделано вне плагина.

Ответ 2

Здесь более простой способ определения режима конфиденциальности. Это работает только в Safari. Я создал его, потому что разрабатываемое веб-приложение использует localStorage. LocalStorage недоступен в Safari в режиме конфиденциальности, поэтому мое приложение не будет работать. При загрузке страницы запустите script ниже. Он показывает окно предупреждения, если мы не можем использовать 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.');
}

Ответ 3

ОБНОВЛЕНО: Chrome получил дальнейшее развитие и больше не оставляет места для обнаружения при использовании режима инкогнито.

Можно обнаружить включенные частные режимы просмотра для большинства используемых браузеров. Сюда входят Safari, Firefox, IE10, Edge и Google Chrome.


Firefox

Когда режим приватного просмотра Firefox включен, IndexedDB генерирует InvalidStateError, потому что он недоступен в режиме приватного просмотра.

Очень, если что:

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

Safari

Для Safari ключом является локальная служба хранения. Это отключено в режиме конфиденциальности. Так что попробуйте получить к нему доступ и использовать предложение try-catch. Следующий метод работает на устройствах OSX и iOS. Кредиты для этого метода собираются на этот вопрос и ответ

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/Край

Internet Explorer даже собирается отключить IndexedDB в режиме конфиденциальности. Так что проверь на существование. Но этого недостаточно, потому что старые браузеры, возможно, даже не имеют IDB. Так что сделайте еще одну проверку, например для событий, которые есть только в IE10 и последующих браузерах. Соответствующий вопрос по CodeReview можно найти здесь

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

Chrome

Обновление: это не работает с Chrome 76 (спасибо @jLynx)

Режим инкогнито Chromes может быть проверен файловой системой. Отличное объяснение можно найти здесь на 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
});

Ответ 4

Вот мой взгляд на обнаружение частного режима

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 нашел современный, более быстрый и синхронизированный способ попробовать его в Firefox (у них нет обслуживающего персонала в приватном режиме), похожий на т.е. не включающий indexedDB, но тест работает только на защищенных сайтах

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

Ответ 5

Нет никакой возможности для вашей веб-страницы абсолютно точно знать, что пользователь находится в режиме частного просмотра. Любые попытки проверить различные функции браузера должны будут часто меняться по мере обновления систем безопасности. Он может работать некоторое время в некоторых браузерах, но не во всех.

Если компания обеспокоена безопасностью, я предлагаю перевести свой собственный Firefox или Chromium-дистрибутив с заблокированными настройками конфиденциальности и разрешить только настраиваемому клиенту подключаться к экстрасети.

Ответ 6

Тройка localStorage исправлена ​​ошибка, и она больше не работает в Safari 11.0.

Есть интересная альтернатива, которая работает в Safari, Opera и Internet Explorer (а не в Chrome): эти браузер отправляют заголовок DNT: 1 (Do Not Track).

Он не на 100% надежный, поскольку этот заголовок может быть включен для обычного просмотра (он по умолчанию отключен), но он может помочь идентифицировать пользователей, не связанных с сохранением конфиденциальности.

Ответ 7

Я создал небольшую библиотеку, которая будет работать на всех основных протестированных платформах и браузерах: https://github.com/jLynx/PrivateWindowCheck

Вы можете просто позвонить

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

Ответ 8

Вы не собираетесь блокировать их, если у них нет закрытого браузера.

Почему у вас есть смарт-поле?

Будет ли попытка установить уникальную работу cookie для всех браузеров и платформ? Кто-нибудь сделал это раньше?

Я думаю, что самым элегантным решением было бы:

  • Выполните тест на утечку безопасности
  • Если тест на утечку безопасности выявил проблему
    • Сообщите пользователю, чтобы проверить настройки
    • Предложить режим конфиденциальности

Потому что, как вы сказали, не каждый может или должен включить режим конфиденциальности.

Ответ 9

Веб-браузеры ведут себя по-другому, когда активирован режим конфиденциальности.

Во многих браузерах кеширование ресурсов ограничено. Можно обнаружить где браузер был на основе их CSS-кеша. Его можно провести эту атаку без JavaScript.

EFF работает над проектом отпечатки пальцев. Части отпечатков пальцев браузера будут отличаться при активации режима конфиденциальности. Идем дальше, попробуйте.

Ответ 10

Я согласен с настроением DigitalSeas, что мы обычно не пытаемся определить, находится ли пользователь в режиме "частного просмотра". Однако недавно я обнаружил, что FireFox теперь подписывается на услугу "disconnect.me", которая предоставляет черный список URL, который они используют в своей "функция отслеживания" . Так как disconnect.me черным списком определенных социальных сетей (например, Facebook facebook.net), мы обнаружили, что их SDK не будут загружаться в FireFox. Поэтому представляется разумным, что мы можем попытаться обнаружить частный режим просмотра, чтобы предоставить пользователям более полезное и точное сообщение об ошибках.

С учетом этого оправдания этот gist утверждает, что обеспечивает обнаружение для частного просмотра в основных браузерах с использованием трюков, специфичных для этих браузеров. На момент написания этой статьи (сущность может быть обновлена ​​к тому моменту, когда вы ее прочитали) логика обнаружения выглядит следующим образом:

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);
        }
    );
}

Ответ 11

Хорошо, вы бы не различали частный режим от "блокировать все куки" таким образом, но, кроме этой редкой ситуации, я думаю, что она должна работать.


Большая проблема ИМО заключается в том, что это очень плохой дизайн сайта, не лучше, чем хороший "вам нужен браузер xxx, чтобы увидеть этот сайт", который был распространен в 90-х годах. Не у всех браузеров есть режим частного просмотра (насколько я презираю IE, например, вырезать пользователей IE7), и эти пользователи вообще не смогут получить доступ к вашему сайту.

Кроме того, когда я в Интернете, у меня часто есть несколько вкладок, открытых с несколькими веб-сайтами. Мне было бы очень неприятно переключиться в частный режим, чтобы увидеть этот сайт и не иметь доступа к другим сайтам одновременно.

Одна вещь, которую вы могли бы сделать, - это проектирование сайта с использованием сеансов вместо файлов cookie, поэтому они не будут сохранены (поскольку вы их не используете...). А что касается истории... действительно, какая проблема с этим?

Ответ 12

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);
});

Ответ 13

Я решил эту проблему, используя две HTML-страницы. На главной странице задается переменная статуса и устанавливается файл cookie. Вторая страница открывается в новом окне (не вкладка), читает файл cookie и устанавливает статус в значение cookie. В MSIE значение cookie передается на дочернюю страницу, когда главная страница находится в обычном режиме. Когда в режиме просмотра InPrivate значение cookie не передается на дочернюю страницу (но передается, если вы открываете новую вкладку).

Страница main.html:

<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>

Страница child.html:

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

Я использую режим просмотра InPrivate, чтобы предотвратить включение объектов-помощников браузера (BHO) и расширений браузера, поскольку BHO чаще всего являются вредоносными программами, которые могут изменять веб-страницы, даже если HTTPS и сильная аутентификация используются. Internet Explorer 9 имеет "Отключить панели инструментов и расширения при запуске InPrivate Browsing" в настройках "Конфиденциальность".

Однако это не самый лучший способ предотвратить распространение вредоносного браузера: вредоносное расширение может изменить поведение главной страницы, чтобы заставить его думать, что значение myCookie не установлено и. Мы ошибочно предположили, что находимся в режиме просмотра InPrivate.

Обратите внимание, что мне нужны файлы cookie для моего приложения, поэтому я не использую InPrivate Browsing для этой цели.

Ответ 14

Введите код для достижения следующих

1) В версии браузера браузера Firefox. Этот метод работает с версией >= 33.0 (поддерживает сервис-работников). Нельзя использовать этот метод со старыми (< 33,0) версиями.

2) Попробуйте установить сервисного работника. 3) Если вы можете установить, использовать или получить доступ к работнику службы, вы на 1000% не работаете в режиме частного просмотра, так как работники служб не могут взаимодействовать с обычным режимом просмотра Firefox. Я хочу, чтобы они были такими.

Цитата:

"В Firefox API-интерфейсы Service Worker скрыты и не могут использоваться, когда пользователь находится в режиме частного просмотра"

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

Ответ 15

Не уверен, что причина этого вопроса старая, но Firefox предоставляет документацию по как определить приватный режим просмотра. Однако он включает использование своих 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;
      }
    }

Ответ 16

При создании моего расширения Safari я обнаружил, что можно запросить логическое значение safari.self.browserWindow.activeTab.private. Ниже работало для меня, чтобы проверить, был ли браузер открыт в приват или нет, но только из расширения.

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.");}