web-dev-qa-db-ja.com

ブラウザがプライベートブラウジングモードを使用しているかどうかを検出する

私は、セキュリティに偏執的な会社のためにエクストラネットを構築しています。彼らは(特に)ユーザーがWebブラウザでプライベートブラウジングモードをオンにしてサイトを閲覧し、Cookieや履歴が保持されないようにします。

私はこれだけを見つけました http://jeremiahgrossman.blogspot.com/2009/03/detecting-private-browsing-mode.html および https://serverfault.com/questions/18966/force-safari-to-operate-in-private-mode-and-detect-that-state-from-a-webserver

理想的なソリューションでは、javascriptを使用しないか、最小限に抑えます。一意のCookieを設定しようとすると、すべてのブラウザーとプラットフォームで機能しますか?誰もこれをやったことがありますか?

ありがとう!


更新

http://crypto.stanford.edu/~collinj/research/incognito/ は、他のポスターが言及しているブラウザーのフィンガープリンターのCSS訪問テクニックを使用しています。ヒントをありがとう。

小さくてエレガントなので気に入っていますが、可能であればjavascriptなしでもできるようにしたいです。

59
Steve

2019年6月更新

Googleは 機能の削除 Chrome 76以降で永久にプライベートブラウジングモードを検出します。したがって、プライベートブラウジングを検出したい場合、それは不可能です。 Googleが見つけられなかった方法)プライベートブラウジングモードを検出する機能はバグとして認識されており、意図されていませんでした。

この質問に出くわした人には、2014年時点で、誰かがJavascriptまたはCSSを介してシークレット/プライベート/セーフブラウジングモードでブラウジングしているかどうかを検出するための信頼できる正確な方法はありません。 CSS履歴ハックのように機能していた以前のソリューションは、その後すべてのブラウザーベンダーによって使用できなくなりました。

通常の日々のWebサイトでプライベートブラウジングモードを検出する必要がある状況は決してありません。人々は自分の理由で匿名で閲覧することを選択しています。

ChromeおよびFirefoxは、localStorageなどの機能を無効にしなくなりました。それを使用するWebサイトがエラーを起こさないように、一時的な場所に単に名前空間を追加します。モードに関係なくlocalStorageのサポートをテストしている場合、それをサポートするブラウザーに対しては常にtrueを返します。

Chrome=でプライベートモードを検出する他の手段は、特に完全にパッチが適用されており、動作しなくなります。

会社の内部で必要な場合は、ブラウザプラグインを開発する必要があります。 Chromeと、特にFirefoxは、ユーザーがプライベートブラウジング/シークレットモードになっているかどうかをプラグインが確認できる内部APIを公開します。プラグインの外部では実行できません。

48

プライバシーモードを検出する簡単な方法を次に示します。これはSafariでのみ機能します。開発中のWebアプリがlocalStorageを使用しているため、作成しました。 LocalStorageは、プライバシーモードではSafariで使用できないため、アプリは動作しません。ページの読み込み時に、以下のスクリプトを実行します。 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

[〜#〜] updated [〜#〜]: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の鍵は、ローカルストレージサービスです。プライバシーモードでは無効になっています。そのため、アクセスして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/Edge

Internet Explorerは、プライバシーモードのときにIndexedDBを無効にします。存在を確認してください。しかし、それだけでは十分ではありません。古いブラウザにはIDBさえないかもしれないからです。別のチェックを行います、例えばIE10以降のブラウザのみが持つ/トリガーするイベントの場合。 CodeReviewの関連する質問は here にあります。

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

Chrome

Update:Chrome 76(@jLynxのおかげで)

Chromeのシークレットモードはファイルシステムで確認できます。素晴らしい説明があります ここ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

これがプライベートモードの検出に関する私の見解です

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

編集 firefox(privatモードでサービスワーカーがいない)で試してみるための最新の、より高速なsynkronasの方法を見つけました。

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

Webページが、ユーザーがプライベートブラウジングモードであることを絶対に確認する方法はありません。さまざまなブラウザ機能を確認する試みは、セキュリティの実装が更新されるたびに頻繁に変更する必要があります。一部のブラウザではしばらく動作しますが、すべてではありません。

会社がセキュリティを懸念している場合は、プライバシー設定をロックダウンして独自のFirefoxまたはChromiumディストリビューションを展開し、そのカスタムクライアントのみがエクストラネットに接続できるようにすることをお勧めします。

14
Matt S

localStorageトリックは 修正されたバグ であり、Safari 11.0ではもう機能しません。

Safariで動作する興味深い代替手段があります。OperaおよびInternet Explorer(Chromeではない):これらのブラウザーはDNT: 1ヘッダー(追跡しない)。

このヘッダーは通常のブラウジングで有効にできるため(デフォルトでは無効になっています)、100%の信頼性はありませんが、プライバシーを意識したユーザーを識別するのに役立ちます。

4
Julien

プライベートブラウジングが有効になっていない場合、それらをブロックしません。

なぜスマートなメッセージボックスがあるのですか?

一意のCookieを設定しようとすると、すべてのブラウザーとプラットフォームで機能しますか?誰もこれをやったことがありますか?

最もエレガントな解決策は次のとおりだと思います:

  • セキュリティリークテストを実行する
  • セキュリティリークテストで問題が明らかになった場合
    • 設定を確認するようユーザーに指示する
    • プライバシーモードを提案する

あなたが言ったように、誰もがプライバシーモードを有効にできるわけではないからです。

3
Lee Louviere

私がテストしたすべての主要なプラットフォームとブラウザで動作する小さなライブラリを構築しました: https://github.com/jLynx/PrivateWindowCheck

あなたは単に呼び出すことができます

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

通常、ユーザーが「プライベートブラウジング」モードにあるかどうかを検出しようとすべきではないというDigitalSeasの感情に同意します。しかし最近、FireFoxが「disconnect.me」というサービスにサブスクライブしていることを発見しました。このサービスは、 「トラッキング保護」機能 で使用するURLブラックリストを提供します。 disconnect.meは特定のソーシャルネットワーク(例:Facebookの facebook.net )をブラックリストに登録しているため、SDKはFireFoxにロードされないことがわかりました。したがって、より便利で正確なエラーメッセージをユーザーに提供するために、プライベートブラウジングモードを検出しようとすることは理にかなっています。

this Gist は、正当な理由がないため、これらのブラウザーに固有のトリックを使用して、主要なブラウザーでのプライベートブラウジングの検出を提供すると主張しています。この記事の執筆時点(この記事を読むまでに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);
        }
    );
}
2
Jackson

Webブラウザー 異なる動作 プライバシーモードがアクティブな場合。

多くのブラウザでは、リソースのキャッシュが制限されています。 CSSキャッシュに基づいて ブラウザがあった場所 を検出することが可能です。この攻撃を行うことは可能です JavaScriptなし

EFFは 指紋ブラウザ へのプロジェクトに取り組んでいます。プライバシーモードがアクティブになると、ブラウザの指紋の一部が異なります。どうぞ、 試してみてください

2
rook

プライベートモードと "すべてのCookieをブロックする"を区別するわけではありませんが、まれな状況を除けば、動作するはずです。


IMOの大きな問題は、これが非常に悪いサイトデザインであり、90年代によく見られた「このWebサイトを表示するにはブラウザxxxが必要」というよりも良くないことです。すべてのブラウザにプライベートブラウジングモードがあるわけではありません(IEを軽usersしている限り、たとえばIE7ユーザーを切り取っているなど)。これらのユーザーはサイトにまったくアクセスできません。

また、インターネットを使用しているとき、複数のWebサイトでいくつかのタブが開いていることがよくあります。そのWebサイトを表示するためだけにプライベートモードに切り替える必要があり、同時に他のサイトにアクセスできないのは、本当に面倒です。

できることの1つは、Cookieの代わりにセッションを使用してサイトを設計することです。そのため、セッションは保存されません(使用しないので...)。そして、歴史については...本当に、それに関する問題は何ですか?

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

以下を達成するためのコードを書く

1)Firefoxのテストブラウザバージョン。このメソッドは、バージョン33.0以上で機能します(Service Workerをサポートします)。古い(<33.0)バージョンではこのメソッドを使用できません。

2)Service Workerを設定してみてください。 3)Service Workerを設定、使用、またはアクセスできる場合、Firefoxのプライベートブラウジングモードではサービスワーカーとやり取りできないため、プライベートブラウジングモードではありません。私は彼らがそうであることを望みます。

見積もり:

「Firefoxでは、Service Worker APIは非表示であり、ユーザーがプライベートブラウジングモードの場合は使用できません」

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

0
douglas

この質問の原因が古いかどうかはわかりませんが、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;
      }
    }
0
aug

2つのHTMLページを使用してこの問題を解決しました。メインページはステータス変数を定義し、Cookieを設定します。 2番目のページが新しいウィンドウ(タブではない)で開かれ、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's InPrivate Browsing mode...
<script>
window.opener.myCookie=document.cookie;
window.close();
</script>

BHOはほとんどの場合、HTTPSと強力な認証が使用されている場合でもWebページを変更できるマルウェアであるため、ブラウザーヘルパーオブジェクト(BHO)とブラウザー拡張機能が有効にならないように、InPrivateブラウズモードを使用しています。 Internet Explorer 9の[プライバシー]設定には、[InPrivateブラウズの開始時にツールバーと拡張機能を無効にする]があります。

ただし、これは悪意のあるブラウザー拡張機能を防ぐための究極の方法ではありません。悪意のある拡張機能により、メインページの動作が変更され、myCookie値が設定されていないと見なされる場合があります。 InPrivateブラウズモードにあると誤って想定します。

アプリケーションにはCookieが必要なので、その目的でInPrivateブラウズを使用しないことに注意してください。

0
Julien Kronegg

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

ソース: developer.Apple.com | Instance Property private

0
Robin Oberg