ueberauth_google icon indicating copy to clipboard operation
ueberauth_google copied to clipboard

Getting csrf_attack exception in callback but only on Safari and Safari Mobile

Open nicolasblanco opened this issue 2 years ago • 12 comments

Hello folks.

Right now I'm getting:

%Ueberauth.Failure.Error{
      message: "Cross-Site Request Forgery attack",
      message_key: :csrf_attack
    }

but only on Safari and Safari Mobile.

Everything is working fine on Chrome and Firefox. I'm trying to inspect what is done differently in this browser...

nicolasblanco avatar Oct 22 '21 17:10 nicolasblanco

I tried to debug the issue and basically it looks like the strategy is writing the ueberauth.state cookie but after the Google redirection, the private function get_state_cookie(conn) in Ueberauth.Strategy is returning nil.

It looks like the server is not getting everything for some reasons.

The weird thing is that it's only happening on my side with latest Safari and Safari Mobile.

nicolasblanco avatar Oct 22 '21 18:10 nicolasblanco

I am seeing the same problem sporadically but I can't pinpoint it to a specific browser/os. @nicolasblanco were you able to find the exact cause of the issue?

fedme avatar Oct 27 '21 11:10 fedme

I faced similar issue in chrome today, the code was working fine last month.

Then I tried using https in my dev environment and makes the GOOGLE_REDIRECT_URI to point to https and it worked again.

kayuapi avatar Nov 09 '21 05:11 kayuapi

I faced similar issue in chrome today, the code was working fine last month.

Then I tried using https in my dev environment and makes the GOOGLE_REDIRECT_URI to point to https and it worked again.

On my side I was getting this exception both on local dev and on production where all my servers and redirect links are on HTTPS, so it's not only related to HTTPS in my opinion.

Also, I'm getting this exception all times and not sporadically on Safari and Safari Mobile.

nicolasblanco avatar Nov 14 '21 11:11 nicolasblanco

If anyone is still experiencing this issue, I would be curious to know whether the browser is sending the ueberauth.state_param cookie. Specifically, is the SameSite behavior of the cookie preventing it from being sent during the callback? This could explain the differences across browsers and when, for example, redirects are involved.

aj-foster avatar Sep 23 '22 17:09 aj-foster

still have this issue, tried changing samesite to none; strict but still had the same issues, fails in all browsers, the default on most browsers changed from none to lax by default so im thinking the problem has something to do with that samesite=Lax is appended to the set-cookie header

mithereal avatar Sep 26 '22 08:09 mithereal

If you have the opportunity, can you open the network inspector (in the settings, "preserve logs"), and copy the Set-Cookie response header here? That would help us diagnose this.

Changing SameSite to None may not work if your endpoint thinks it is operating over http instead of https. Plug will automatically set the "Secure" attribute on the cookie accordingly. This can happen, for example, if you terminate SSL and do not have a header informing Plug of the original protocol.

aj-foster avatar Sep 26 '22 12:09 aj-foster

heres the entire auth flow GET /auth/github HTTP/2 Host: localhost:4000 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:105.0) Gecko/20100101 Firefox/105.0 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,/;q=0.8 Accept-Language: en-US,en;q=0.5 Accept-Encoding: gzip, deflate, br Connection: keep-alive Cookie: __session_key=SFMyNTY.g3QAAAABbQAAAAtfY3NyZl90b2tlbm0AAAAYTWkwTmZFblZjY1RxUUZteG5zM0hBT0M2.SzEZMNeVO2tZ_mbesbYqxo-6Fj7a7lkvmotEt2-YH2s Upgrade-Insecure-Requests: 1 Sec-Fetch-Dest: document Sec-Fetch-Mode: navigate Sec-Fetch-Site: none Sec-Fetch-User: ?1 TE: trailers

HTTP/2 302 Found cache-control: max-age=0, private, must-revalidate content-length: 201 date: Tue, 27 Sep 2022 02:08:41 GMT location: https://github.com/login/oauth/authorize?client_id=Iv1.2f81a316e8262411&redirect_uri=&response_type=code&scope=user%3Aemail server: Cowboy x-request-id: FxiVkzxMn5QMd6IAADKB X-Firefox-Spdy: h2

GET /login/oauth/authorize?client_id=Iv1.2f81a316e8262411&redirect_uri=&response_type=code&scope=user%3Aemail HTTP/2 Host: github.com User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:105.0) Gecko/20100101 Firefox/105.0 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,/;q=0.8 Accept-Language: en-US,en;q=0.5 Accept-Encoding: gzip, deflate, br Connection: keep-alive Cookie: logged_in=yes; _device_id=5fbf2f360cab16a32d6a8f8417b44291; _octo=GH1.1.1513978513.1647913957; _gh_sess=%2FjlXawGKZuualvO4NI4LyeRgOjm7wtoSoHUxiqhAAAhAUPz4NHxhFFvp5VQvc5hZ9pU73uJgh7xgphi9lKXbba%2BtzesBHPgNnzku5XF3OlLFHVdNpoyHNB4W08L2Un9DmIQOnd2o7frou5lu1TnlOPMvFaST10kRahBigF1SBARisKtTnt04HtKbuR0in0f9eLHI8BUPLyDoXa%2FVUZvHbP0%2Fbt3QaM3qpynk1Mmr4UvmoMdDV4S1BgwJvi0UX7jFOSsDPtxVuqxrMZHNYgqQLWtgQQAmk1Hf9rueeLr7LuCICjpZPfijfQIDDxni930cz49C%2BOXAh4ExxoV7%2BGIphjaKCCKj7zXN5ar9oyMEj%2FMupETTlo9VtOoRuZnitBevIExYAE%2BCog9TFXL825aVWpcdrGUUvOtdP2No19%2FEvhTN0O7aD5NIiVsdFwkEW3coVuDtOsXaJoSjJjzW%2FoWgH2AJY00KirMCdkGHkoHGo%2FOsRaqC7zVCqGu5vZUF%2Ba1Gtq3ua4qpOQhO9EZjO2Uv2Ey0V2GaA4ihURZmUw8zfvQ7eLhvlBmL3o%2BEO6hU1m0dr0NCp7Rp3sDBUHV9tIdO8uW1q75ko3RnPsowdyu4N%2BFNAliZD2MRzwlaqMgmJw3CHQTWPdtkL8B08XsnHdeGX2GofffAShfxRGI3TzQmDmPCrl30fISNKYbArfvduIHp%2Byr6BUninrAwbTA7MatrA%2FfcFc6UkgROIke4nE1QbY0TXo4rmDE%2Bxoj%2BN%2F%2FjkIUj2yzqFw%3D%3D--sy1j6t86FZihZ579--RB9MLS28G1QEPFbXrriIFg%3D%3D; preferred_color_mode=dark; tz=America%2FPhoenix; user_session=nW1v9Ibh_RL3-OPoW5NBb42bbgBKSELFrsXT-rNaEICs0MtG; tz=America%2FPhoenix; color_mode=%7B%22color_mode%22%3A%22dark%22%2C%22light_theme%22%3A%7B%22name%22%3A%22light%22%2C%22color_mode%22%3A%22light%22%7D%2C%22dark_theme%22%3A%7B%22name%22%3A%22dark%22%2C%22color_mode%22%3A%22dark%22%7D%7D; dotcom_user=xxxx; has_recent_activity=1 Upgrade-Insecure-Requests: 1 Sec-Fetch-Dest: document Sec-Fetch-Mode: navigate Sec-Fetch-Site: none Sec-Fetch-User: ?1 TE: trailers

HTTP/2 302 Found server: GitHub.com date: Tue, 27 Sep 2022 02:08:42 GMT content-type: text/html; charset=utf-8 location: https://localhost:4000/auth/github/callback?code=9898f57bd64bc1506454 cache-control: no-cache set-cookie: has_recent_activity=1; path=/; expires=Tue, 27 Sep 2022 03:08:41 GMT; secure; HttpOnly; SameSite=Lax _gh_sess=hfYl0QqOWujjGQFARv9%2B63S1vJUH7MyyQD9s0yMq6gy9006E274XaADc2us052bDa6sl3qFNpoSo8T0XvmXPiNnfrcpDCoggLHbzIwA4kApC4T%2FLBNAVMBzC40pXYa1fcXZKiBxFXi%2FyCT60eNeux2uDUWMWf%2BX3uMOLwoJ9zgZZp%2F%2BpiGD7SZsqMVajqeYf7bcoD6iVN0TQgyhvv%2FfBdPiUgVcMo%2FYMZsn7rPj6%2FoC0wbUgFiLrHSc9OAZtDYrXS%2BO3pySZWRkXB4bT3hhIIqPHg7Q7tdEtncTyHzw6GBWcwbg4Rf6FstEoMvYNejbBMc%2FP7R49vovIV8lwOoEg2HPNTdYd2jw8D%2BoxMjHxrUkJ0q6GLFrKKcUCSwtosxjEUhru2%2BKIyuAAx9KklBcaMiyA%2F929rwQy4XUO8cT7cpJfZbuaMcpaGUBZ4K6Aplsqm1nYDFPeod3k48EgMLC9se0ROtmkwwgXLRq6tHKMvRea%2BAGkghBZ4LKb0OAl9jw4%2BF%2F3lnKqQqJsijBlPPcgEXbISVr7GdDE6eOdOPMsgpVpetAo6UiIN%2Bk9nnfvHaPAX8v2GizRW3ddrFVPIhqLALkjYEJ63NQQwdhgYkf9qJG4KphLNo1wNedRRm7asYtzZHLkEKdJH3pYnqvbKg1OQk%2FCbB%2BLLrFi9grjjSSlU56Pgsr6sBxEPCdRaRJ%2FV6LdkjQ1HtSS%2Btne0Px53bHJ%2Ftsi09%2FPcQgTzVgEpjqBdO7fgk%2BO2ZapSUGziY0Kt9yazTyAjw%3D%3D--nhCYGi5RFwDxND%2FK--YikD4xFKOjC%2BPu2BBw3elQ%3D%3D; path=/; secure; HttpOnly; SameSite=Lax strict-transport-security: max-age=31536000; includeSubdomains; preload x-frame-options: sameorigin x-content-type-options: nosniff x-xss-protection: 0 referrer-policy: origin-when-cross-origin, strict-origin-when-cross-origin expect-ct: max-age=2592000, report-uri="https://api.github.com/_private/browser/errors" content-security-policy: default-src 'none'; base-uri 'self'; block-all-mixed-content; child-src github.com/assets-cdn/worker/ gist.github.com/assets-cdn/worker/; connect-src 'self' uploads.github.com objects-origin.githubusercontent.com www.githubstatus.com collector.github.com raw.githubusercontent.com api.github.com github-cloud.s3.amazonaws.com github-production-repository-file-5c1aeb.s3.amazonaws.com github-production-upload-manifest-file-7fdce7.s3.amazonaws.com github-production-user-asset-6210df.s3.amazonaws.com cdn.optimizely.com logx.optimizely.com/v1/events .actions.githubusercontent.com wss://.actions.githubusercontent.com online.visualstudio.com/api/v1/locations github-production-repository-image-32fea6.s3.amazonaws.com github-production-release-asset-2e65be.s3.amazonaws.com insights.github.com wss://alive.github.com; font-src github.githubassets.com; form-action 'self' github.com gist.github.com objects-origin.githubusercontent.com; frame-ancestors 'self'; frame-src render.githubusercontent.com viewscreen.githubusercontent.com notebooks.githubusercontent.com; img-src 'self' data: github.githubassets.com identicons.github.com github-cloud.s3.amazonaws.com secured-user-images.githubusercontent.com/ github-production-user-asset-6210df.s3.amazonaws.com customer-stories-feed.github.com spotlights-feed.github.com *.githubusercontent.com; manifest-src 'self'; media-src github.com user-images.githubusercontent.com/ secured-user-images.githubusercontent.com/; script-src github.githubassets.com; style-src 'unsafe-inline' github.githubassets.com; worker-src github.com/assets-cdn/worker/ gist.github.com/assets-cdn/worker/ vary: X-PJAX, X-PJAX-Container, Turbo-Visit, Turbo-Frame, Accept-Encoding, Accept, X-Requested-With x-github-request-id: B9EC:7635:128D3B7:1B88D70:63325AA6 X-Firefox-Spdy: h2

GET /auth/github/callback?code=9898f57bd64bc1506454 HTTP/2 Host: localhost:4000 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:105.0) Gecko/20100101 Firefox/105.0 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,/;q=0.8 Accept-Language: en-US,en;q=0.5 Accept-Encoding: gzip, deflate, br Connection: keep-alive Cookie: __session_key=SFMyNTY.g3QAAAABbQAAAAtfY3NyZl90b2tlbm0AAAAYTwTmZFblZjY1RxUUZteG5zM0hBT0M2.SzEZMNeVO2tZ_mbesbYqxo-6Fj7a7lkvmotEt2-YH2s Upgrade-Insecure-Requests: 1 Sec-Fetch-Dest: document Sec-Fetch-Mode: navigate Sec-Fetch-Site: none Sec-Fetch-User: ?1 TE: trailers

HTTP/2 302 Found cache-control: max-age=0, private, must-revalidate content-length: 145 content-type: text/html; charset=utf-8 cross-origin-window-policy: deny date: Tue, 27 Sep 2022 02:08:42 GMT location: / server: Cowboy x-content-type-options: nosniff x-download-options: noopen x-frame-options: SAMEORIGIN x-permitted-cross-domain-policies: none x-request-id: FxiVk1HsPB-s0ZQAABmJ x-xss-protection: 1; mode=block set-cookie: __session_key=SFMyNTY.g3QAAAACbQAAAAtfY3NyZl90b2tlbm0AAAAYTWkwTmZFblZjY1RxUUZteG5zM0hBT0M2bQAAAA1waG9lbml4X2ZsYXNodAAAAAFtAAAABWVycm9ybQAAAEBGYWlsZWQgdG8gYXV0aGVudGljYXRlLiBUaGUgY29kZSBwYXNzZWQgaXMgaW5jb3JyZWN0IG9yIGV4cGlyZWQu.2Orzj45gMW4Gikb8W--pPL0LLNAxI3i7BuOED9-zhA0; path=/; secure; HttpOnly ueberauth.state_param=; path=/; expires=Thu, 01 Jan 1970 00:00:00 GMT; max-age=0; secure; HttpOnly X-Firefox-Spdy: h2

mithereal avatar Sep 27 '22 02:09 mithereal

(Note: the above requests show a request for GitHub OAuth, not Google. Still going to look through it.)

Looking at the above, and searching specifically for ueberauth.state_param, I see the following in the last request:

ueberauth.state_param=; path=/; expires=Thu, 01 Jan 1970 00:00:00 GMT; max-age=0; secure; HttpOnly

This is where Ueberauth clears the state cookie after the callback is complete (regardless of success or failure). I don't see where this state cookie is being set during the request phase. If you go to the network tab and look at the original request to /auth/github, under the Cookies tab, the browser will likely show you the ueberauth.state_param cookie with a warning about why it isn't being set. You may need to check a box to display rejected cookies.

Sidenote: for safety, I recommend logging out of the GitHub session you used to generate the above trace, just in case someone tries to use your session cookies for something nefarious.

aj-foster avatar Sep 27 '22 02:09 aj-foster

the only warning i see is Cookie “__session_key” does not have a proper “SameSite” attribute value. Soon, cookies without the “SameSite” attribute or with an invalid value will be treated as “Lax”. This means that the cookie will no longer be sent in third-party contexts. If your application depends on this cookie being available in such contexts, please add the “SameSite=None“ attribute to it. To know more about the “SameSite“ attribute, read https://developer.mozilla.org/docs/Web/HTTP/Headers/Set-Cookie/SameSite so im assuming this is the error but where do i add the samesite attribute, ive tried in the config to no avail, thanx for looking at this even tho its across application bounds, it seems as multiple ueberauth plugins are having the same issue and this had the most traction

mithereal avatar Sep 27 '22 04:09 mithereal

Just sharing based on my past experience, first some general things to check (for anyone reading) and then some specific thoughts for the above conversation.

General Notes:

  • Check that you are using ueberauth version 0.7.0 or above. This is when CSRF checks were added, so if you're seeing a CSRF related error, you're here.

  • If you're using an OAuth strategy that requires POST callbacks (for example, ueberauth_apple), then ensure the strategy is using the state_param_cookie_same_site option in its code. POST requests require SameSite=None to work properly. (Sidenote: the "official" ueberauth_apple strategy doesn't do this yet, but I maintain a fork that does.)

  • If you require SameSite=None because of the above, you must also trick Plug into setting the secure attribute on the cookie as well.

    Plug manages this behaviour based on the incoming request conn. If the original request was for an http address, Plug will not set the secure attribute, and SameSite=None will not be accepted by the browser. If the original request used https but you're terminating TLS at a load balancer (for example), you must inform plug about the correct protocol by using an X-Forwarded-Proto header or something similar.

  • Related to proxies and headers, make sure you don't have a layer of infrastructure that is stripping out the set-cookie header in responses or cookies in requests.

  • Make sure the scheme matches between your original request to /auth/:provider and the callback request. If one is made with http and the other https, or vice-versa, the browser may decline to send the state cookie during the callback.

Specifics:

  • It's odd that there is no set-cookie header listed in the first response at all. Maybe that's just an artifact of the way the browser exported the request log (it automatically removes cookies that were rejected?). But it makes me wonder if Ueberauth isn't even trying. A quick version check of all the libraries involved wouldn't hurt. You almost certainly have ueberauth version 0.7.0 or higher because of the set-cookie in the last response, but maybe you have an old version of the GitHub strategy that doesn't yet call the internal function for setting the state cookie during the request phase.

  • GitHub and Google use GET requests during the callback phase, which means SameSite shouldn't matter (as far as I understand). So as long as the browser isn't completely blocking the cookie, it should be fine. Furthermore, localhost is a secure context, so the whole secure attribute discussion above shouldn't matter.

  • As a final check, make sure the scheme matches between your original request to /auth/:provider and the callback request. If one is made with http and the other https, or vice-versa, the browser may decline to send the state cookie during the callback.

aj-foster avatar Sep 28 '22 03:09 aj-foster

i fixed this by noticing my callback was running 2x, this was due to a failure in the callback of the controller i was running returning an unexpected response so wasnt technically failing but ueberauth wasnt setting the cookie

mithereal avatar Sep 30 '22 19:09 mithereal