Closed Bug 1507055 Opened 6 years ago Closed 4 years ago

Login with Stackdriver is still broken after bug 1505212

Categories

(Core :: Privacy: Anti-Tracking, defect, P1)

65 Branch
defect

Tracking

()

VERIFIED FIXED
Future
Tracking Status
firefox74 --- verified
firefox75 --- verified

People

(Reporter: ehsan.akhgari, Assigned: baku)

References

(Blocks 1 open bug)

Details

(Whiteboard: [privacy65][anti-tracking])

Attachments

(2 files, 3 obsolete files)

This requires a Google Cloud account (you can get one for free).

STR:

1. Go to Google Cloud Console: https://console.cloud.google.com
2. From the menu on the left hand side, under Stackdriver, click on Monitoring.
3. You'll get redirected to your Google Account login page, select an account there.
4. You'll be redirected to <https://app.google.stackdriver.com/account/login2/?next=https%3A%2F%2Fapp.google.stackdriver.com%2Fsocial%2Fcomplete%2Fgoogle-oauth2%2F>.
5. Press Log in with Google.
6. Back to step 4.

Now the user enters a never ending loop.

Andrea, any chance you could take a look please?  Thanks!
Flags: needinfo?(amarchesini)
> 3. You'll get redirected to your Google Account login page, select an
> account there.

This doesn't happen to me. I see a new window appearing, with the monitoring page. No authentication prompt. This with and without my latest patches. And I'm using a normal google account, should I use a different one?
Flags: needinfo?(amarchesini) → needinfo?(ehsan)
(In reply to Andrea Marchesini [:baku] from comment #1)
> > 3. You'll get redirected to your Google Account login page, select an
> > account there.
> 
> This doesn't happen to me. I see a new window appearing, with the monitoring
> page. No authentication prompt. This with and without my latest patches. And
> I'm using a normal google account, should I use a different one?

Hmm, in my profile I have signed in to the MoCo gmail account as well as my personal gmail account, so in the account login dialog I see them both selected (perhaps because I have the cookies for both logins).  Can you try logging in to both accounts before step 1 perhaps?
Flags: needinfo?(ehsan) → needinfo?(amarchesini)
Assignee: nobody → amarchesini
> Hmm, in my profile I have signed in to the MoCo gmail account as well as my
> personal gmail account, so in the account login dialog I see them both
> selected (perhaps because I have the cookies for both logins).  Can you try
> logging in to both accounts before step 1 perhaps?

I have done the same thing now: I am logged in with 2 accounts. same steps, I see the monitoring page asking me to create a project. what else could it be? I don't have any tacking-related patches in my tree, normal m-c.
Flags: needinfo?(amarchesini)
Do you have a cloud project before you start step 1?  (I do, maybe that is a difference)
Status: NEW → ASSIGNED
Priority: -- → P1
Whiteboard: [privacy65]
I finally managed to reproduce this bug. Here what happens:

1. StackDriver.com creates iframe(accounts.google.com) - 3rd party tracking origin.
2. the user clicks login.
3. here we don't see a window.open(), but, instead, a navigation to accounts.google.com as first party.
4. the authentication is done. After that, accounts.google.com redirects to stackDriver.com again.
5. StackDriver.com loads iframe(accounts.google.com) which checks if document.cookies has some value.
6. We don't allow the tracker to have access to its cookies. The website asks the user to authenticate again.
Some additional details:

*If I am logged in on google*

1. The user clicks on a link. This generates a mouse event

2. subjectPrincipal=https://app.google.stackdriver.com/account/login2/[...] execs window.location.assign(https://accounts.google.com/o/oauth2/auth?[...])

2. https://accounts.google.com/o/oauth2/auth redirects to https://app.google.stackdriver.com/social/complete/google-oauth2

3. The new page opens an iframe(https://accounts.google.com/o/oauth2/iframe)

4. We have a navigation via location.href=https://app.google.stackdriver.com/account/login done by subjectPrincipal=https://app.google.stackdriver.com/social/complete/google-oauth2

5. The new page creates an iframe(https://accounts.google.com/o/oauth2/iframe)

6. The iframe checks document.cookies <- here we show the login link again.

*If I am not logged in on google*
I didn't finish the previous comment:

*If I am not logged in on google*

1. The user clicks on a link. This generates a mouse event

2. subjectPrincipal=https://app.google.stackdriver.com/account/login2/[...] execs window.location.assign(https://accounts.google.com/o/oauth2/auth?[...])

3. https://accounts.google.com/o/oauth2/auth redirects to https://app.google.stackdriver.com/social/complete/google-oauth2

4. the page opens an iframe(https://accounts.google.com/o/oauth2/iframe)

5. We have a navigation via location.href=https://accounts.google.com/o/oauth2/auth?

6. Login form appears

7. in the meantime there is an iframe loading https://accounts.youtube.com/accounts.. let's ignore it.

8. after the login and several redirects, we are redirected to https://app.google.stackdriver.com/social/complete/google-oauth2

9. the page creates an iframe(https://accounts.google.com/o/oauth2/iframe)

10. the iframe checks the cookie (document.cookie), it doesn't find any, and it does: parent.postMessage(something) which triggers a location.href = https://app.google.stackdriver.com/account/login2
Now, after this, I would suggest a new heuristic that works in this way:

If we load a tracker as a first-party with a non-tracker referrer, and its loading has started from a user-interaction, let's store a permission to the tracker origin called: "possible-sso-" + its referrer - expiring in 1 hour (or less).
When a first-party loads an tracker iframe, which has a permission called "possible-sso" + first-party's origin (not expired), and the first-party has the same 3rd party tracker as referrer, we grant the storage access permission to that iframe.

In comment 6 and 7, that means:

when we load  https://accounts.google.com/o/oauth2/auth, with referrer https://app.google.stackdriver.com/account/login2/ (point 2 and 3), we store a permission called "possible-sso-https://app.google.stackdriver.com" granted for origin "https://accounts.google.com"

When we go back to https://app.google.stackdriver.com/social/complete/google-oauth2, (point 5 and 9) at the creation of iframe(https://accounts.google.com/o/oauth2/iframe), we grant the permission to https://accounts.google.com because it has the permission "possible-sso-https://app.google.stackdriver.com" and the first-party (https://app.google.stackdriver.com) has referrer https://accounts.google.com.

This should not be complex to do it. I can prototype it for tomorrow if we all agree with this approach.
Flags: needinfo?(ehsan)
(In reply to Andrea Marchesini [:baku] from comment #8)
> Now, after this, I would suggest a new heuristic that works in this way:

Nice investigative work!  I really like your suggestion.  I have a few suggestions.

> If we load a tracker as a first-party with a non-tracker referrer, and its
> loading has started from a user-interaction, let's store a permission to the
> tracker origin called: "possible-sso-" + its referrer - expiring in 1 hour
> (or less).

Let's make sure the permission is assigned to the referrer not the tracker so that you can assign it to the exact principal (including the OAs).  We can call this one "3rdPartySSO^https://tracker.example" to make it quite similar to ANTITRACKING_PERM_KEY.  :-)

Also, under what circumstances would a login process take an *hour* to finish?!  This heuristic is super prone to abuse, so I think we should not even be that lenient.  If you have a slow 2G connection you probably give up on one page load after 10-15 minutes?  I'd like to propose 15 minutes, and if we ever get a bug report that shows we undershot, we can increase (let's use a pref obviously.)

> When a first-party loads an tracker iframe, which has a permission called
> "possible-sso" + first-party's origin (not expired), and the first-party has
> the same 3rd party tracker as referrer, we grant the storage access
> permission to that iframe.
> 
> In comment 6 and 7, that means:
> 
> when we load  https://accounts.google.com/o/oauth2/auth, with referrer
> https://app.google.stackdriver.com/account/login2/ (point 2 and 3), we store
> a permission called "possible-sso-https://app.google.stackdriver.com"
> granted for origin "https://accounts.google.com"
> 
> When we go back to
> https://app.google.stackdriver.com/social/complete/google-oauth2, (point 5
> and 9) at the creation of
> iframe(https://accounts.google.com/o/oauth2/iframe), we grant the permission
> to https://accounts.google.com because it has the permission
> "possible-sso-https://app.google.stackdriver.com" and the first-party
> (https://app.google.stackdriver.com) has referrer
> https://accounts.google.com.
> 
> This should not be complex to do it. I can prototype it for tomorrow if we
> all agree with this approach.

Yeah, sounds great!  Let's do it.  Thanks for thinking this through.
Flags: needinfo?(ehsan)
Using Safari v12.0, I remove cookies from google.com and stackdriver.com.  I have the preference set to Allow cookies from the current website only.  I visit https://app.google.stackdriver.com/account/login2/?next=https%3A%2F%2Fapp.google.stackdriver.com%2Fsocial%2Fcomplete%2Fgoogle-oauth2%2F directly (step 4 in comment 0) and I am able to login.  I do get a red message saying "Unable to load the workspace list, reload and try again." but that is probably because there is no workspace set up for the account.

I sign out and quit the browser.  Open the browser and turn on ITP debug mode. Restarted the browser. I clear cookies for google and stackdriver again.  Set accounts.google.com to a tracking domain:
MacBook-Pro:~ tvyas$ defaults write com.apple.SafariTechnologyPreview ResourceLoadStatisticsManualPrevalentResource accounts.google.com
MacBook-Pro:~ tvyas$ defaults read com.apple.SafariTechnologyPreview ResourceLoadStatisticsManualPrevalentResource
accounts.google.com
MacBook-Pro:~ tvyas$ 

I opened the browser and went through the steps again.  I was still able to login.
Version: unspecified → 65 Branch
I can somewhat reproduce this on Safari Technology preview 71. I had a lot of trouble getting the login loop to trigger. My most successful approach was to:
1. clear state
2. login with a single account on https://console.cloud.google.com
3. in a new tab, go to sso.mozilla.com
4. login and open Mozilla's gmail, thus having two active accounts
5. From the menu on the left hand side, under Stackdriver, click on Monitoring.

The ability to reproduce also seemed to depend on the default projects I had set in each account (i.e., I couldn't reproduce on a test account until I created a project)

After this I was taken to the account chooser page. After choosing an account I would then loop similar to steps 4 - 6 as described in Comment 0. However, after a small number of loops (2 - 6), I would end up on the project page. After that point, I could no longer trigger the loop and had to clear storage to see it again.
I see the following logs repeated with each pageload.

2018-12-19 13:22:33.019721-0800 0xb269a7   Info        0x0                  19641  Safari Technology Preview: (WebKit) [com.apple.WebKit:ResourceLoadStatisticsDebug] About to block cookies in third-party contexts for: accounts.google.com, 3rdpartytestwebkit.org.
2018-12-19 13:22:33.020039-0800 0xb269a7   Info        0x0                  19641  Safari Technology Preview: (WebKit) [com.apple.WebKit:ResourceLoadStatisticsDebug] Done updating cookie blocking.

I haven't been able to reproduce looping through more than two "Continue with Google" screens. The non-determinism in triggering this has made it difficult to determine the cause.
Attached patch part 3 - heuristic (obsolete) — Splinter Review
This patch should store the permission on the parent process.
These is what I wrote so far but:

1. this issue is not reproducible in nightly anymore. And with bug 1515693 uplifted, also beta is fine. This happens because google passes allow-storage-with-user-interaction sandbox flags.

2. my patches are still too fragile because it's not always true that we go from a non-tracking page to a tracking page, and from the same tracking page to the same non-tracking page. We could have redirects to other non-tracking pages which will break my current patches.

Would be great if somebody can test this issue again in nightly and beta, after bug 1515693.

Hello,

We have tried to reproduce this issue and have the following findings:

  • This issue still occurs with the same repro steps on the latest Nightly build 66.0a1(2019-01-08) with the loop remaining stuck on https://tinyurl.com/y8dzegdf

  • This issue is not present on the latest Beta build (65.0b9).

We have modified on the latest nightly "network.cookie.cookieBehavior" from 4 to 0 and it had the desired behavior, thus, this may very well be the culprit for this.

Flags: needinfo?(amarchesini)
Version: 65 Branch → unspecified
Target Milestone: --- → Future
Version: unspecified → 65 Branch
Component: Tracking Protection → Privacy: Anti-Tracking
Flags: needinfo?(amarchesini)
Product: Firefox → Core
Flags: needinfo?(amarchesini)
Whiteboard: [privacy65] → [privacy65][anti-tracking]

This still reproduces for me on trunk. Andrea, are you planning to clean up your patches for review?

Ehsan and I discussed this issue on IRC. We are going to have a meeting this week to find a better strategy/solution to fix this issue. We can give an update after the meeting.

Flags: needinfo?(amarchesini)

The heuristic that we are going to implement is the following:

  1. When a first-party document A is created by a redirect from B
  2. and if the B's origin is included in a pref-based list,
  3. the B's origin will have storage-access permission granted, when loaded as 3rd party in A.
  4. the storage-access permission will have a short expiration time.

This is partially implemented. I hope to finish the implementation (tests included) for the next week.

Assignee: amarchesini → ehsan
Assignee: ehsan → amarchesini
Attachment #9033033 - Attachment is obsolete: true
Attachment #9033035 - Attachment is obsolete: true
Attachment #9033034 - Attachment is obsolete: true

I've submitted a patch. This is a first starting point which is not optimal, but good enough to be reviewed.

This patch gives storage access to 3rd party trackers after a top-level tracker to non-tracker HTTP redirect. The storage access permission is granted only if the user has interacted with the tracker before the redirect.

Good news, this patch allows the user to complete the authentication on stackdriver. Bad news, it works only after the second try.

At the first try, my patch doesn't work because we have a sequence of redirects like this:

  1. google.com authentication form redirects to youtube.com (tracker to non-tracker)
  2. youtube.com redirects to google.co.uk (non-tracker to non-tracker)
  3. google.co.uk redirects to stackdriver.com (non-tracker to non-tracker)

But from the second try, the sequence is different:

  1. google.com to stackdriver.com (tracker to non-tracker)

Because of this, my patch is able to grant permission to google's 3rd-party resources when loaded on stackdriver.com.

Thanks Andrea! I unfortunately didn't get a chance to look at your patch today, will do that next week.

Pushed by amarchesini@mozilla.com:
https://hg.mozilla.org/integration/autoland/rev/4639d83e5871
Implement Anti-tracking heuristic for redirects, r=Ehsan
Status: ASSIGNED → RESOLVED
Closed: 4 years ago
Resolution: --- → FIXED
Regressions: 1610485
Status: RESOLVED → REOPENED
Resolution: FIXED → ---
Pushed by amarchesini@mozilla.com:
https://hg.mozilla.org/integration/autoland/rev/678dd02cf719
Implement Anti-tracking heuristic for redirects, r=Ehsan
https://hg.mozilla.org/integration/autoland/rev/be170480919d
AntiTrackingCommon::RedirectHeuristic must check the number of redirect entries, r=Ehsan
Flags: needinfo?(amarchesini)
Pushed by amarchesini@mozilla.com:
https://hg.mozilla.org/integration/autoland/rev/6f83de2c474a
Implement Anti-tracking heuristic for redirects, r=Ehsan
https://hg.mozilla.org/integration/autoland/rev/3ea18bc6dc4a
AntiTrackingCommon::RedirectHeuristic must check the number of redirect entries, r=Ehsan
Status: REOPENED → RESOLVED
Closed: 4 years ago4 years ago
Resolution: --- → FIXED
Flags: qe-verify+
QA Contact: ciprian.georgiu

I've managed to reproduce this issue on Firefox 74.0a1 (2020-01-10) using Windows 10x64 by following the STR from comment 0.
This issue is verified fixed on Firefox 74.0b6 and Firefox 75.0a1 (2020-02-21) on the following OSes: Windows 10x64, Windows 7x64, macOS 10.15 and Ubuntu 18.04x64.

Status: RESOLVED → VERIFIED
Flags: qe-verify+
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Created:
Updated:
Size: