freedomofpress / securedrop

GitHub repository for the SecureDrop whistleblower platform. Do not submit tips here!
https://securedrop.org/
Other
3.6k stars 686 forks source link

detect Tor Browser and slider setting #6795

Open Thorin-Oakenpants opened 1 year ago

Thorin-Oakenpants commented 1 year ago

is this still a feature you provide, or would like to fix? I see the user agent regex was recently updated, so I suspect you still do?

Currently, when I visit the site I see a large pink box with You are not anonymous while using this browser! and instructions to go download Tor Browser and return. This is on both current alpha and stable. And also when using .onion.

I tried three times in #5052 to offer a solution, but after six months of nothing but crickets, I deleted my offers and left. A conversation I had at a recent Tor Project conference reminded me of this, so I will reach out one last time

Would you like a rock solid, 100% guaranteed (JS client side) test that works on all platforms and all forks (e.g. tails) to detect Tor Browser. This does not rely on detecting results that can be enabled in Firefox (via privacy.resistFingerprinting) or spoofed by an extension or even changed via override prefs. It does not need to be updated (unless some major refactoring happens upstream) - it has worked for me for the last 5+ years in all my testing. It doesn't care about the OS. It doesn't care about release changes or versions. It doesn't provide false positives such as Mullvad Browser (which is 99% Tor Browser minus the tor part). If you are interested, then speak up now :)

If this is not something you do any more, then feel free to close. I am going to name drop someone for visibility @eloquence , thanks :)

Disclosure: I do not work for Tor Project but am "entangled" there and in geckoland with fingerprinting

Thorin-Oakenpants commented 1 year ago

OK, I guess this isn't something that is needed anymore. Closing.

zenmonkeykstop commented 1 year ago

Apologies @Thorin-Oakenpants! we've been a bit all over the place lately! this would definitely be a good addition, and we'd be happy to get a PR.

Thorin-Oakenpants commented 1 year ago

I won't be adding a PR, but here is some code for you. This is approximately 5-15ms or so to check in gecko (non-gecko fails immediately). Double check it, since it's a modified cut-copy from my own (which is more complex). The timeout is because extensions can cause resource:// to be blocked silently

it's pretty simple - it tries to load a web accessible resource and if it can, you must be tor browser

const get_isTB = () => new Promise(resolve => {
    setTimeout(() => resolve(false), 150)
    function exit(value) {
        return resolve(value)
    }
    try {
        let css = document.createElement("link")
        css.href = "resource://torbutton-assets/aboutTor.css"
        css.type = "text/css"
        css.rel = "stylesheet"
        document.head.appendChild(css)
        css.onload = function() {
            exit(true)
        }
        css.onerror = function() {
            exit(false)
        }
        document.head.removeChild(css)
    } catch(e) {
        exit(false)
    }
})

Promise.all([
    get_isTB(),
]).then(function(result){
    if (true === result[0]) {
        // hooray

    } else {
        // show warning

    }
})

Now, I have to say, after five years or so, it looks like we might lock all off this off (i.e resource:// and chrome:// in web content), but I'm going to convince apps team to leave the file as still accessible - we're not trying to hide that we are Tor Browser. But just in case, keep the old code lying around (although TBH, the old code is failing AFAICT)

eloquence commented 1 year ago

@Thorin-Oakenpants Thanks for this! As far as I can tell, the code is not currently failing on SecureDrop itself (which you can test on https://demo-source.securedrop.org/ or an SD instance like nytimes.securedrop.tor.onion) but on https://securedrop.org/ (i.e. the website about SecureDrop, which displays the "You are not using Tor" message even in Tor Browser). The logic for both is here: https://github.com/freedomofpress/securedrop/blob/develop/securedrop/static/js/source.js https://github.com/freedomofpress/securedrop.org/blob/develop/client/tor/js/detect-tor.js

A more resilient solution that we can use across both seems certainly desirable and worth testing. I'll open an issue over in securedrop.org and cross-reference it, but please let us know if you're also able to repro the issue on https://demo-source.securedrop.org/, which in Tor Browser should only display a more generic JavaScript warning if JS is enabled.

Thorin-Oakenpants commented 1 year ago

As far as I can tell, the code is not currently failing on SecureDrop itself

edit, forgot to finish this sentence. Sorry, see my comment in OP. I did test, but now I have no idea what I tested

const is_likely_tor_browser = function () {
    return (
        // Tor Browser has the Tor/FF UA string
        window.navigator.userAgent.match(TBB_UA_REGEX) &&
        // Tor Browser always reports a GMT timezone
        new Date().getTimezoneOffset() == 0 &&
        // Tor Browser always reports device dimensions being the same
        // as window dimensions -- this is only true in a browser that
        // implements letterboxing, such as Firefox configured with
        // privacy.resistFingerprinting=true
        window.screen.width == window.innerWidth &&
        window.screen.height == window.innerHeight
    )
}

yeah, this is not very robust. We will probably not make screen match inner, we will probably not use GMT (but offsets will remain 0), userAgent can be misleading (e.g. FF caps windows at 10, and windows 10 is the min requirement in FF116+ - so next ESR this would almost become pointless), etc

const is_tor_browser seems more robust :)

do you also want 100% foolproof OS detection (I see a is_likely_mobile_tor_browser)? Do you want slider checks?

eloquence commented 1 year ago

Thanks, that makes sense to me! The mobile vs. desktop detection is useful, because we advise mobile users through a custom warning to switch to the desktop version of Tor Browser for the purpose of using SecureDrop.

Thorin-Oakenpants commented 1 year ago

BTW I am the author of TZP (work in progress) and am a core contributor / member at tor project - mainly working with apps team on Tor Browser itself, specializing in fingerprinting

OS: same story - I use the presence of specific chrome:// files to detect OS - see here - again, I would be pushing for apps team to not block these if they do, Tor Browser is not trying to hide the OS - but do note that this is only for gecko, so your logic would be if not TB then warn to use desktop TB, else if mobile warn use desktop TB

For the slider (standard vs safer) it's pretty simple - several window properties, and some webgl errors. I'm in the process of adding a better slider health check to TZP, but it's not high priority right now. But I could work on it sooner if you want it - the basis of it if what would be your slider check, which I have not looked at, or what you're trying to do with it - it told me to use Safest, i.e. no JS - so it seems like if JS is enabled it just returns a default message. But if JS is disabled, do you check if it's a known Tor exit node? No need to answer, but suffice to say, my slider code checks safer vs standard, so maybe you don't need any of that

Thorin-Oakenpants commented 1 year ago

PS: I can even get you the TB version (i.e based on ESR102, ESR115, etc) and warn if you are using an out-of-date Tor Browser

SaptakS commented 1 year ago

I have left some of my thoughts regarding this https://github.com/freedomofpress/securedrop.org/issues/1034#issuecomment-1651187641. My thought about the slider settings is (and probably others can disagree with me) since we do want them to always use the safest setting, showing the message if JS is enabled should suffice?

eloquence commented 1 year ago

This should now be fixed on securedrop.org, thanks again for your help @Thorin-Oakenpants and thanks to @SaptakS and @chigby for implementation and review.

I would suggest as a next step on this issue, to bring the logic in SecureDrop itself in line with the changes in https://github.com/freedomofpress/securedrop.org/pull/1045, specifically to perform the resource:// URL loading check in SecureDrop's Tor Browser detection alongside the existing user-agent logic, so that if either check succeeds, we assume it's Tor Browser.

Unlike securedrop.org was, the SecureDrop logic is not currently broken, but that additional measure seems like it would make it more reliable with little downside.

Thorin-Oakenpants commented 1 year ago

so the merge here is going to fail with TB13

first you need to check if it is gecko, then add a version 115 check and change the resource path - then we're good for all except TB13 on Android (and the android detection is listed upstream but not high priority)

It's OK though, we have a month or more until TB13 lands in release

SaptakS commented 1 year ago

@Thorin-Oakenpants Yes. We decided to not wait till TB13 and fix till the current TB. It's on my todo to check this issue with TB13 and make a separate PR for the fix once it is released.

Thorin-Oakenpants commented 1 year ago

is on my ToDo as well - wasn't ever going to leave you in a broken state

Thorin-Oakenpants commented 11 months ago

So TB13 is finally out .. 291 lines of changelog (phew)

so

css.href = "resource://torbutton-assets/aboutTor.css"

this is going to fail in TB13 - we need to check the release and change the path if the gecko version is 115 or higher - this will fix it for TB13 desktop. Android is a work in progress

    let source = "resource://torbutton-assets/aboutTor.css"
    // FF115+ change source: ToDo: TB13+: does not work on android
    if (CanvasRenderingContext2D.prototype.hasOwnProperty("letterSpacing")) {
        source = "chrome://browser/content/abouttor/aboutTor.css"
    }
    let css = document.createElement("link")
    css.href = source

    // ...  etc

that's it, the change is now stable after the final changes to migrate the tor-button code

android we have a plan to address for 13.5, because ultimately we want a 100% foolproof way to know isTB in advance for tests - rather than use tests to determine isTB and end up in circuitous logic