getsentry / sentry-javascript

Official Sentry SDKs for JavaScript
https://sentry.io
MIT License
7.97k stars 1.57k forks source link

uBlock Origin blocks requests to sentry.io #2916

Closed piotr-cz closed 4 years ago

piotr-cz commented 4 years ago

Package + Version

Version:

5.23.0

Description

The uBlock Origin (probably most popular adblocking extension, installed by default on Raspberry PI Chromium) recently added sentry.io to it's uBlock filters - privacy list on 28/08/2020.

As a result, Sentry events are not being sent to server.

Log from from Chrome DevTools console:

https://xxx.ingest.sentry.io/api/xxx/store/?sentry_key=xxx&sentry_version=7
net::ERR_BLOCKED_BY_CLIENT

The sentry.io entry might have been added to the list as a result of grofers.com (mis)using it to track user behaviour, unfortunately affecting web apps on all domains.

Reference to commit: https://github.com/uBlockOrigin/uAssets/commit/6489ab5eaf2a838bcdf2ae74ec8542ebb897d16d

piotr-cz commented 4 years ago

Related PR in uBlock/uAssets repo: https://github.com/uBlockOrigin/uAssets/pull/7924

lobsterkatie commented 4 years ago

Hey, @piotr-cz, thanks for reporting this. We’re aware of it, and don't yet have a solution, but we'll update here once we do.

piotr-cz commented 4 years ago

This issue causes using Sentry's javascript platform useless in our product, as our web app is currently being deployed only to machines with uBlock Origin extension enabled (Raspberry PI).

Are there any special directions for setting up a forward proxy for @sentry/browser package?

jan-auer commented 4 years ago

@piotr-cz We have something in our works for this. Would you be comfortable with running a small service on your domain that redirects events to Sentry? If so, please reach out to me via jan.auer@sentry.io. Thanks!

piotr-cz commented 4 years ago

This seems to be resolved by https://github.com/uBlockOrigin/uAssets/commit/9ab563e5fb6c2c8be78aa1ac47e429e057a0ead0, at least for now.

Thank you for everyone involved.

hyperknot commented 3 years ago

Now Easyprivacy is doing it, I've opened an issue here: https://github.com/easylist/easylist/issues/6963

piotr-cz commented 3 years ago

Oh no, not again

hyperknot commented 3 years ago

Easylist's official reply: "Happy to keep it. We block event, error trackers."

I guess this means all uBlock Origin users (where Easylist privacy is default) are not working with Sentry. I don't know if the same list is used by any other blocker, but this means the Sentry team needs to look for a proxy solution.

brpaz commented 3 years ago

@hyperknot Can confirm, that sentry is not working for me with ublock installed as today.

piotr-cz commented 3 years ago

@hyperknot I suggest you open new Issue concerning https://github.com/easylist/easylist/issues/6963. This issue is closed as it's been resolved in uBlock Origin repo and in effect problem you describe may not get enough attention here.

leocharrua commented 3 years ago

Hello, I have the same issue with uBlock Origin ... Blocks sentry:

o265477.ingest.sentry.io/api/5459967/envelope/?sentry_key=XXXXXX&sentry_version=7:1 Failed to load resource: net::ERR_BLOCKED_BY_CLIENT

I don't wanna tell to my clients that uninstall uBlock Origin.

Can you help me?

Thanks

kamilogorek commented 3 years ago

@leocharrua https://docs.sentry.io/platforms/javascript/troubleshooting/#dealing-with-ad-blockers

hyperknot commented 3 years ago

This page doesn't provide information about how to avoid blocking the "ingest" part. For that you need an external service in Docker for example.

leocharrua commented 3 years ago

Hello. I am using the the SDK package directly through the npm:

 "@sentry/angular": "^5.28.0",
"@sentry/tracing": "^5.28.0",

In main.ts (ionic/angular):

import * as Sentry from '@sentry/angular'; import { Integrations } from '@sentry/tracing';

Sentry.init({ dsn: 'https://ea5c59cca30945xxxxxxxxxxx@o26xxxx.ingest.sentry.io/545xxxx', integrations: [ new Integrations.BrowserTracing({ routingInstrumentation: Sentry.routingInstrumentation, }), ],

tracesSampleRate: 1.0, });

This is the "ingest" part I suppose.

We don't use Docker ... any other ideas? The uBlock Origin team can do anything?

Thanks

lobsterkatie commented 3 years ago

@leocharrua There is discussion of proxying in this issue, which helps with the outbound (ingest) blocking. Also, please feel free to add your voice to https://github.com/easylist/easylist/issues/6963, or, as @piotr-cz says, open a new issue there. This has come up before with them and other ad blockers, and has been eventually resolved each time, but more support in favor of fixing it this time certainly can't hurt.

ffxsam commented 3 years ago

Really annoying. Error trackers should never be blocked.

Does anyone know if there's a way, using the Sentry JS SDK, to attempt to ping sentry.io, and catch an exception if it fails? So we could do something like:

try {
  Sentry.pingTheServer();
} catch (e) {
  // alert user to please disable any privacy blockers
}
razor-x commented 2 years ago

For anyone trying to work around this, I am now successfully using AWS CloudFront and Lambda@Edge to tunnel the requests though the same domain. This is pretty straight forward in hindsight, but getting everything working took a bit more work than expected.

Hopefully sharing my setup can save people some time: https://gist.github.com/razor-x/44c1c572a8c9e4cb723b1945a4d75bdb

I don't have the time right now to open a PR, but if anyone wants to take this work and incorporate it into the examples, go for it!

benswinburne commented 2 years ago

I have gotten around this using Cloudfront as a reverse proxy for Sentry which allows me to use a custom DSN with my own domain name as opposed to using the tunnel option which uses the same domain as the application.

Below is a basic Cloudformation template to get it working. You'll need to create an ACM certificate and the Route53 record manually (or add them to this template)

---
AWSTemplateFormatVersion: "2010-09-09"
Description: ""
Parameters:
  SentryIngestURL:
    Type: String
    Default: xxxxxxxx.ingest.sentry.io
    Description: Enter the ingest hostname for Sentry.
  ReverseProxyDomain:
    Type: String
    Default: sentry.yourdomain.com
    Description: Enter the hostname which will be proxied to Sentry ingest.
  AcmCertificateArn:
    Type: String
    Default: arn:aws:acm:us-east-1:xxxxxxxx:certificate/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
    Description: Certificate ARN for the Cloudfront Distribution

Resources:
  CloudFrontDistribution:
    Type: "AWS::CloudFront::Distribution"
    Properties:
      DistributionConfig:
        Aliases:
          - !Ref ReverseProxyDomain
        Origins:
          - ConnectionAttempts: 3
            ConnectionTimeout: 10
            CustomOriginConfig:
              HTTPPort: 80
              HTTPSPort: 443
              OriginKeepaliveTimeout: 5
              OriginProtocolPolicy: "https-only"
              OriginReadTimeout: 30
              OriginSSLProtocols:
                - "TLSv1.2"
            DomainName: !Ref SentryIngestURL
            Id: !Ref SentryIngestURL
            OriginPath: ""
        OriginGroups:
          Quantity: 0
        DefaultCacheBehavior:
          AllowedMethods:
            - "HEAD"
            - "DELETE"
            - "POST"
            - "GET"
            - "OPTIONS"
            - "PUT"
            - "PATCH"
          CachedMethods:
            - "HEAD"
            - "GET"
          Compress: false
          CachePolicyId:
            Ref: CloudFrontCachePolicy
          OriginRequestPolicyId:
            Ref: CloudFrontOriginRequestPolicy
          SmoothStreaming: false
          TargetOriginId:
            Ref: SentryIngestURL
          ViewerProtocolPolicy: "https-only"
        Comment: |
          Reverse proxy for calls to Sentry through a first party TLD.

        PriceClass: "PriceClass_100"
        Enabled: true
        ViewerCertificate:
          AcmCertificateArn: !Ref AcmCertificateArn
          MinimumProtocolVersion: "TLSv1.2_2021"
          SslSupportMethod: "sni-only"
        Restrictions:
          GeoRestriction:
            RestrictionType: "none"
        HttpVersion: "http2"
        DefaultRootObject: ""
        IPV6Enabled: true

  CloudFrontCachePolicy:
    Type: "AWS::CloudFront::CachePolicy"
    Properties:
      CachePolicyConfig:
        Name: !Sub ${AWS::StackName}-CachePolicy
        Comment: ""
        DefaultTTL: 0
        MaxTTL: 1
        MinTTL: 0
        ParametersInCacheKeyAndForwardedToOrigin:
          EnableAcceptEncodingGzip: false
          EnableAcceptEncodingBrotli: false
          HeadersConfig:
            HeaderBehavior: "whitelist"
            Headers:
              - "Origin"
              - "Authorization"
              - "X-Sentry-Auth"
              - "X-Sentry-Token"
          CookiesConfig:
            CookieBehavior: "none"
          QueryStringsConfig:
            QueryStringBehavior: "all"

  CloudFrontOriginRequestPolicy:
    Type: "AWS::CloudFront::OriginRequestPolicy"
    Properties:
      OriginRequestPolicyConfig:
        Name: !Sub ${AWS::StackName}-OriginRequestPolicy
        Comment: ""
        HeadersConfig:
          HeaderBehavior: "whitelist"
          Headers:
            - "Origin"
            - "Access-Control-Request-Method"
            - "Access-Control-Request-Headers"
            - "Referer"
            - "X-Sentry-Token"
            - "X-Sentry-Auth"
        CookiesConfig:
          CookieBehavior: "none"
        QueryStringsConfig:
          QueryStringBehavior: "all"

IIRC Cloudformation must use certificates in us-east-1 (might be wrong) but as a result, deploy the template in us-east-1.

          aws cloudformation deploy \
            --region us-east-1 \
            --template-file stack.yml \
            --stack-name SentryReverseProxy

Then you can set up the client like so

Sentry.init({
  dsn: 'https://xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx@sentry.yourdomain.com/xxxxxxx',
});
carchrae commented 2 years ago

if you are using netlify, it is really easy to make the tunnel using their _redirects proxy feature https://docs.netlify.com/routing/redirects/rewrites-proxies/

you will need to extract XXX YYY and ZZZ from your dsn https://XXX@YYY.ingest.sentry.io/ZZZ

_redirects (or you could use the netlify.toml format see link above for difference)

/unblocksentry      https://XXX@YYY.ingest.sentry.io/api/ZZZ/envelope/ 200

and in sentry add the tunnel you used (i used unblocksentry)

client-app.js

Sentry.init({
  dsn: 'https://XXX@YYY.ingest.sentry.io/ZZZ',
  tunnel: '/unblocksentry'
});

caveat : it may be possible that a malicious person could send /unblocksentry some garbage data and netlify will pass it over to your sentry ingest point. however, i'm not sure this is a concern - and moreover, what stops someone from doing that directly given the DSN is published/deployed anyway.

ps, kudos to @benswinburne for posting his solution too. there is a similar deployed proxy solution here as well https://github.com/getsentry/examples/blob/master/tunneling/nextjs/pages/api/tunnel.js

gudlyf commented 1 year ago

I tried @benswinburne solution and uBlock still blocks calls. It must know something more about the payload to know to block it, unfortunately.

ffxsam commented 1 year ago

@gudlyf Did you try this? https://docs.sentry.io/platforms/javascript/troubleshooting/#dealing-with-ad-blockers

I'm going to be implementing that soon. Privacy blockers be damned! 😁

gudlyf commented 1 year ago

@ffxsam I got the tunnel working with a simple configuration to my CloudFront using CF functions!

Just use a CloudFront function like this and attach it to your Viewer Request. Works like a charm -- not blocked!

function handler(event) {
  var request = event.request;
  var projectId = '123455';

  request.uri = `/api/${projectId}/envelope/`;

  return request;
}
gudlyf commented 1 year ago

Some info on how to achieve this with CloudFront functions. Hope it helps! https://rawdatum.com/posts/8th-piece/

igorsantos07 commented 1 year ago

2023 and Sentry is still blocked by uBlock Origin. I'm going to open yet-another-issue at easylist, but their current issue template states that

If a site implements any tracking or monitoring, UA/IP/Geo checks, browser detection, analytics, telemetry, linking to third-partys, pixels, referrers, fingerprinting, event/perf logging etc. Regardless how helpful or needed the script(s) are, it will be blocked in Easyprivacy. Privacy comes first and the block on these scripts will remain in place.

Effectively, for them, bug reporting == lack of privacy. Awesomely stupid developers :man_facepalming: All forms of extremism are wrong.

I guess the only way indeed is to tunnel the project out, when it's possible.

carchrae commented 1 year ago

@igorsantos07 - given that you can record whatever you like with sentry, i don't think they are wrong to block it. that said, just add your own proxy and it works just fine.

https://github.com/getsentry/sentry-javascript/issues/2916#issuecomment-1036564861

igorsantos07 commented 1 year ago

Proxying is just extra work for something that shouldn't even happen in the first place.

Yep, you can sort of record user information with the reports - what doesn't mean you're really able to track the user down, or cookie them. And then, why not blocking the whole internet, since you can store any information about your users on, surprise surprise, your database as well? Why not block any AWS call, since AWS has databases which potentially could be used to store user information?

As stated in the uBlock issue, Sentry is open about what they do with the user information and move the responsibility about user data to the end developer - and thus, again, no reasons to block Sentry directly.

This is not a decent reason for blocking an error reporting tool which is invaluable for developers. They should at least explain clearly why they think those tools should go, and what to use instead. I asked exactly that on my new issue - https://github.com/easylist/easylist/issues/15806

igorsantos07 commented 1 year ago

I also tried looking around at uBlock docs if there's a way to create a "positive filter" of sorts, so at least Sentry is allowed in any of my dev domains, but it doesn't seem possible - only allow-listing the domains where we use Sentry, one by one. Also found no way to send a Feature Request, except posting something to Reddit or filling it disguised as a bug report instead :man_shrugging:

ffxsam commented 1 year ago

Hot take: The people who maintain EasyList are the same people who always vote to close questions on StackOverflow. 😏

dperetti commented 1 year ago

As of today, Sentry is still blocked by uBlock 🤦‍♂️

justinconnell-vallen commented 1 year ago

Can confirm as well. Calls to sentry.io are blocked unless you pause uBlock Origin on the page.

SmailHammour commented 11 months ago

Still blocked

darkvertex commented 11 months ago

Everyone replying "still blocked" here as if the adblock lists are part of this repo. You are barking at the wrong tree, ya'll.

Wanna make noise? Do it at the maintainers of the adblock lists: https://github.com/easylist/easylist/issues https://github.com/uBlockOrigin/uAssets/issues (They'll probably still say no though. 🤷‍♂️)

And a reminder you can bypass it with the "tunnel" feature, if you host your own endpoint (at least until you are a big company and then the filter people block your domain. 😛) -- Anyway, scroll up in the replies for a few implementation suggestions.

ffxsam commented 11 months ago

It's pointless to complain to the list maintainers.

https://github.com/easylist/easylist/issues/6963

This topic has been beaten to death already, and they haven't shown any signs of budging.

Muetze42 commented 8 months ago

The best thing will probably be to simply send the JavaScript errors to a separate API and then pass the error on to Sentry server-side. Is there a walkthrough for this?

gudlyf commented 8 months ago

The best thing will probably be to simply send the JavaScript errors to a separate API and then pass the error on to Sentry server-side. Is there a walkthrough for this?

I noted one way to do this above (See: https://rawdatum.com/posts/8th-piece/). This has been working great for me.

Muetze42 commented 8 months ago

@gudlyf

I use Laravel and after creating the question I already had the idea. :D

I will just send the Sentry Vue (JS) to an internal API route and from there with the Laravel HTTP client 1:1 to Sentry.

gudlyf commented 8 months ago

@Muetze42 Just make sure you use the tunnel option to the Sentry client library and forward the correct headers, then all should work!

Muetze42 commented 8 months ago

OK. I tested it and it works.

In case anyone needs it.. My Sentry Laravel Tunnel:
(environment and/or url check still needs to be implemented)

<?php

namespace App\Http\Controllers\Api;

use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Http;

class SentryTunnelController extends Controller
{
    /**
     * Handle the incoming request.
     */
    public function __invoke(Request $request)
    {
        $envelope = $request->getContent();
        $headers = array_map(
            fn ($line) => json_decode($line, true),
            preg_split('/\r\n|\r|\n/', $envelope)
        )[0];

        if (empty($headers['dsn']) || $headers['dsn'] != config('sentry.dsn')) {
            return response()->json(null, 401);
        }

        $parsed = parse_url(config('sentry.dsn'));
        $url = sprintf(
            'https://%s.ingest.sentry.io/api/%d/envelope/',
            explode('.', $parsed['host'])[0],
            last(explode('/', $parsed['path']))
        );

        $response = Http::withBody($envelope, 'application/x-sentry-envelope')->post($url);

        return response()->json($response->json(), $response->status());
    }
}