Most active commenters
  • mtlynch(7)
  • brunoTbear(3)

←back to thread

1134 points mtlynch | 25 comments | | HN request time: 1.283s | source | bottom
1. mtlynch ◴[] No.22936825[source]
Author here. Happy to answer any questions or hear feedback about this post.
replies(4): >>22937478 #>>22937646 #>>22937672 #>>22938279 #
2. swyx ◴[] No.22937478[source]
title is a little sensationalist, i find that a little hard to forgive :) it is well understood any anti fraud system records movement. how does your analysis fare on Google's reCAPTCHA v3?

or rather the actual issue, the x00,000's of sites that actually record movement for product research and, yes, marketing? sensationalizing this issue on stripe, which is a probable good actor, doesn't help the sites and web users deal with the real bad actors.

but its a well written article with solid recommendations so kudos for that.

replies(4): >>22937556 #>>22937570 #>>22937649 #>>22937950 #
3. mtlynch ◴[] No.22937556[source]
> it is well understood any anti fraud system records movement.

I don't think that's true of every anti-fraud system. I've integrated PayPal checkouts by pasting some HTML on a single page and that works fine. I'm sure it works better if you can record movement, but that doesn't necessarily mean I'm okay with handing over so much data to achieve those gains.

> how does your analysis fare on Google's reCAPTCHA v3?

I haven't looked too carefully at it, but my understanding is that reCAPTCHA 3 works if you place it on a single page. If reCAPTCHA is directing users to place it on every page of their app and not making it clear that Google's tracking it, I'd have a problem with that as well. From a cursory look at Google's documentation, they don't seem to be doing that.

4. falcolas ◴[] No.22937570[source]
No, it’s not well understood. Perhaps you, and people in your direct field understand this, but does an average web developer who is reading Stripe’s documentation? Does a consumer?

Silent, given the lack of documentation or notification, is 100% appropriate here.

replies(1): >>22942189 #
5. TAForObvReasons ◴[] No.22937646[source]
Have you tried sequestering the payment logistics to a separate domain or subdomain? If you had a pay._____.com that processed payments using Stripe.js, and that redirected back to app._____.com (which would not be using stripe.js), would tracking continue into your app pages?

EDIT: didn't expect this to be so controversial (6 downvotes!)

replies(1): >>22937768 #
6. ◴[] No.22937649[source]
7. tomashertus ◴[] No.22937672[source]
This is a common practice for anti-fraud detection systems. The whole article is sensationalistic. You will see similar techniques used all over the web (your bank website, Ticketmaster, airlines websites, etc.).
replies(1): >>22937868 #
8. mtlynch ◴[] No.22937768[source]
That was one of the solutions I considered. I believe that would successfully limit Stripe's tracking, but it's just logistically complicated to stand up a whole second app just to serve one page and manage state between the payment app and my main app.
replies(1): >>22940721 #
9. mtlynch ◴[] No.22937868[source]
Thanks for reading!

> This is a common practice for anti-fraud detection systems... You will see similar techniques used all over the web (your bank website, Ticketmaster, airlines websites, etc.).

I respectfully disagree.

My bank tracks my movement on their own website. They don't track movement on other businesses' websites.

I believe many developers integrate with Stripe expecting that their JS library executes and shares data only on the pages where Stripe UI elements appear on the page. The fact that JS library runs on every page and sends data back to Stripe, even before the app calls the API, is unexpected. I believe that Stripe should, at the very least, make this more obvious to integrators and, ideally, give site owners the ability to limit what data Stripe collects.

replies(3): >>22938098 #>>22938101 #>>22939474 #
10. dang ◴[] No.22937950[source]
We've changed the title - see https://news.ycombinator.com/item?id=22937739
replies(1): >>22938437 #
11. brunoTbear ◴[] No.22938098{3}[source]
You may not be aware of how many banks/airlines/ticket websites have outsourced their fraud fighting to solutions like Shape Security, or Sift (Science). Web-wide tracking via cookies is a reasonable and widespread technique for fighting fraud.

Given your background I'd imagine you'd be aware of this.

replies(3): >>22938330 #>>22938364 #>>22938781 #
12. huhtenberg ◴[] No.22938101{3}[source]
> I believe many developers integrate with Stripe expecting that their JS library executes and shares data only on the pages where Stripe UI elements appear on the page.

What makes you believe that exactly?

If you include stripe.js on your About page, all bets are off for that page. You can believe all you want here, but you have explicitly included some 3rd js code, so feigning surprise that it gets executed is shallow.

replies(1): >>22938240 #
13. mtlynch ◴[] No.22938240{4}[source]
>> I believe many developers integrate with Stripe expecting that their JS library executes and shares data only on the pages where Stripe UI elements appear on the page.

> What makes you believe that exactly?

I've read all the StackOverflow and Github issue posts I can find related to this issue.[0,1,2,3,4] The overall sentiment from developers is that they're surprised and don't want Stripe to send this information. That said, there's obviously a selection bias because the ones who consider it expected behavior don't post.

> If you include stripe.js on your About page, all bets are off for that page. You can believe all you want here, but you have explicitly included some 3rd js code, so feigning surprise that it gets executed is shallow.

Sure, I'm ultimately responsibility for what runs on my site. I believe Stripe is also responsible for clearly disclosing the behavior of their library, and I feel like open critique is an appropriate way to encourage that.

[0] https://github.com/stripe/react-stripe-elements/issues/257

[1] https://github.com/stripe/react-stripe-elements/issues/99

[2] https://stackoverflow.com/questions/45718026/stripe-js-makin...

[3] https://stackoverflow.com/questions/56481458/why-does-stripe...

[4] https://stackoverflow.com/questions/55904278/reduce-network-...

14. brunoTbear ◴[] No.22938279[source]
It's not super clear to me what harms you've identified here. Tracking mouse movements is a very common way to separate human users from automated fraud, and tracking page views is a relatively common way of identifying normal navigation of a website (homepage-->click on link to search-->click on search results-->click on product reviews-->click on buy) vs fraud navigation (open product page directly-->click on buy). This kind of anti-fraud has existed since the Silvertail days.

Additionally, the Stripe cookie can reasonably be read as a way to reduce false positives: if you've purchased from a dozen stripe merchants with no chargebacks and they see you in the same browser with the same payment method, you're probably good to go. The user benefits from having fewer charges declined, and from their goods being less expensive (due to lower shrink for their merchant).

One great thing about Stripe is their extraordinary transparency. The fact that the stripe.js payload is sent in ~cleartext is either a sign that their eng team was unwilling to roll their own encryption, didn't feel it was necessary, or consciously chose to make it visible so curious users can understand what's going on. I suspect their fraud solution doesn't rely on these being unobserved by bad guys. I am surprised that it's not necessary to include some tamper-evident field though.

For what it's worth, a post to login to aa.com includes this spectacularly obscured blob of who knows what. Would be interesting to know how much of my personal data got hoovered up here, but you won't get clickbait upvotes on HN by going after someone _less_ reputable than Stripe.

  X-6LdxA4pr-a: 6eta-yIqpITGjyIefMI7BLhyY6Km5cM_Y7j0t6yyo4MA4ih7jsy8=4-9MsInBvm36VNvPpZQ1AT9BLMCIihQx7-bZONZNCkleLk76Wh9HOkBR5wuPvy1BcKvj8Imtik9BnZQRATho7TXrAgGrGZwcyZZr2TXtqYN5Dk01eoWRC3ZKxLzfpC_iXMvNselNmhvj6Kntco7rXkLMm-8t4AFYmnR5XgZoahho9_F6s-bMLT8NmQuNoYABsM7YnFU1e67YsxaPimKHcMF5Hk8o3Fuf_7NoAh6jCcf5oFxrXClB3zWBX9wBvhXaXt1fiNajnZvNnNSjy=ajQ_wNcFxiphY=Ak6PXQe_4ImRrNnRo5GgZ-pRczZkALsR_jwjX3NaXyCoAbFR=9WNsE3toTKo9rZrX_GjskvGMIPrZNNYsr6PXyhYQ_9t_ZmaMIGo2Im_s8PBZkul9k9RZAtPsMutcK1GoSWtrFCtHbbj8-S=HyhMs54R8Fl=2-WYSY9wcoZHLTak9_zfoku_5h2BFhzVgGhOgy9j4F9PVh6YhFFwobuh6tC6cM0Gs22Rg-P5Gt6oHBF=Ana6OQ1BQ8bf7y0rX2x1ACqg46Gbl6V5pK8rX=2=96Hrs6_TGQZBl-lrVhujp20=JGZPXTbYmrZBXMmGXI2NN5NPXY5BNmStph9M4PK4e-zqX_CGrh6iMMl32tCYL-2BcgYr4KFjmLWbZMK6OR1RqQ76mh1Bzt25X-9B_yaicyvbAMur9Y4c6B7rGqZBXMvcyIv6AqYbXjGOOhhr=tmtpC7RMIh=3FvRgk7repW5XIMhzoPBXEYBxMh54MxioTGMs3K-ZqPB4I6qkmWoAkXrUAmqQM2rcoFPsMVhsuZjyIFYskzRckQ6WhmSszZNaFP6QFCBXIk397PT4yF=4Izfuknf5NGMghGRAkz-gQl1xy8B4tC=QrZBsPwrWKhrLg3oA-lV7YZBnFqB36Z-pNG1qq7Rc_vBXkFtzFlBpN4YyosHNw9tQVWEsyU=3t9oJQf54GPjiy91x7ZtM==_xnZjyYatAhKiVKD-QgJbQIvPx8FHQ3FjQh86HmFr2IFSnmPRZT964Y7r2=PaLCvfoMs1XF_tph0-5Fn6c2Fwsy9HsMzBvNGo3mZPmRm5A6aNQ2XjnYN-X5KP7AWBnF1pAyCjnZNBA-wBsMlSQBFRX54tsF28zhvRDSWtfYNPeZ2j--2rQyaBsyeNeTnn02L6Cjaq437Ph-vM68sPWCWr4MuPXK8Rg-aYLkl_4ZvtiYZ6AOg6ahoNNIuBLMyjMTxtMCagHYNtVhCVQIojjkwjmlMqzya-HjuT4QLpzRwtphLxQjFPNkoBzTbrPbPvl-lSVhlRlhC=Akofr77Bs0C57N_r422gAqhON3PrXGsico7=AhlcL-6PLk26x3WPy8htgIvt5mF57Q_5esF6imK5gQZBXM8_vh1rXqLrcyCtOkPt83KfgxGo7kujOhkNLnWPNNwcmYZo2rYPZbh1xILrcx7HsM0N6katLTm6c9atX29fMrAYOLuxut8RGUWtikC9cy8o=hLPqta6vyahVICSo-eBQMkMNyarWhQtMChig-SKOh9p4MPHmn7YsCuTAgZ9VEZtM54YmkYBLkuqikzjQoZ-syFnHTmbXYKM3FKUcy7Hskm9vhGSoMbsekHYLocm7QZ1zN7MLZTgZtLR8ZNaQ0Ctc9ZBEuSrAO0NyMaKWFyPph8_4MvBzy9jNwwjLbSRokmYObPNLm7gEk_WZThhNAFjLTuqvsDrHN61eTFjyr1jLklG8-vb0-aybYPYOt5L465GXt2acM0jNNQOy=7=97V=skvtX-yHLTG6vhF59oP=s2viMIlQncWNpK9tXCCjsICr2r=YQM0ffkQ5gT9iiSWBsxGRiQhBQAXfrY=TonV66FhNs-9-ckC6sMCBN53suhqH62s6xIghsMWj7R_6cCRteTvn45aBcI9=43WT4F8RxtlbekQYs6ZRenFjskeNsyzYYNNjLMMPcIla-PZHmb7g9-0R9g_iQ-vrC8PBWhvB=UPBMrQr4klRrMCR5rRKnFCGsy91zFvOyhaPXqVo9oTrHLVpoMF6OY766kPtC=_tMhWHsn7BqyuB4IyPik9tMtpwcy8GXcW6vR_jL6AGCIuYVhajLhCbvk9imglHVVJjsM0547V5sbW=6G7PhMGBG6Zfc-lBO_gRrklRMIFRZTmB3FvRckw-LN7qoXWtqkCBVNZrx-gcV=QGo59PgK_T9BZ6x67NsxZj6_yoJYhfcM0HsKCtXgZ-omzYNN1PLkuB9_br4MGg96ZHm77BVZ_5qL76eMaioyFYmToiCIlo9y9RfkFrCC4MqNIH86ZPX-8GeZ6TcIVrXbNfjYvtikGhQMCo9KGHVPNGvQZRgjhHSbL-LyVjNjur4nstoYVjsML-mga69gaiMMa=sjWfMk7-LTGtrPw5ETYjo6ZaXokiiN7BAFa=aHWjOmZic-JhX=GR2Izhlt4jnGGPL-05J2FtVha-4-FRAm7rehFRq-ABS2PNsqWPeQgcAkb5ojo59MGccM1ruVN-x_hsLk7ez6mVeTxNcLLBQK4=7YVMsGoHszFPsGhjyIPTrmPc8FUBzQ2Ys2hGehxroonf7jCfXFCYssUYsgNRfkltimVo4=7c5gBtoha-WmZNc2zTOhuQsMCrvb-6qb7OIzLbFNZtQI9TcTltZU7eg3B-mkh6sM554MChNpWtsR9LjFCjWh1o4MMYyIyjpVWtsIRPWxQ1lFC=aNaMJh8YmywVeo7YQ7Po2ZlRAkFm4MuhmzatgM6SsCq5X-lYNh9HObWBsoFrXENNXyV6lhh6ATu6sWWR3WW6g=6oJhwqzY1r6CwtXoZHQCm58-aGyIoo9-7QLkCRfkCMs=Z68-2PlnVtpN76mkur96ZScC0fc22tMIC37b7BsoVtsQv5Lk2tqgl_Qg5jMICoGhk5GhqqZqgrxMwtXy2pNgZRpkojQGtYLbSB4C8PskCBA5vtMN7rehlBxLJtxMmo9eWB3FKo=YJNL-CreTIjNTCR9I9NSuYGsM9B9hz5GT9RqICBlz7jOhFVlB0-cyG5A-uTiyxI5J1PxeHMsPQnDmDts=nq6jut52MrCgV=7M2gxmyYsgYR51Qg7M6-WNaBs0C6LkaRX5ZTGzPBGmZ-cp5=4G_M49PjxG_=ZTCp6m7tihXfqkXtfOkgXQNBVhaR3z7rc7Wg9j8=s2_T0twtiYkhs-UH--a6sxOfOmVjQMCBcyWTMbktrb3GCkCRphlBzF9RcYQML-9tphyBWhFOXT9PWCC=aK_YsMpELkCjg3PRxMzNAbnOmTwfc3Yr4PZNXCgG8-m6x0_q-kpBsYVHLTvTM=NHnncLsLVqmkGtA-XbWCFjpmhYnmVToTg-LbFR9yltsMFBXF9rA5eqsgPR5LZOpZAtgNUSQ9=-g_GYLk0g967-=ZlaVh0icM2rs_FhG5N1s2-6s0LB43715MyNVxGBc9ZTGFXR7hkr7F9fcIloGh9YnF6Rih960LWYNjp_XIFP6FPjq=_tctL=4MKNOyetekCM3=PBeb7BcKgoah1jMIvjyFFBAT66gklrfk8PXI8o4G4rWEFM6gG5o5AyAZZNsKwYLbWfoYZB991BHymB4MqBLT8oJkOt4yaReFCtoTzMgnZNLNSYLTetAMgtcC-mvhbBsK66X9ZNOy0BS0w6Ow4NLqFtiwK5zNhbaz7o4_aaqj1jLykBeMVRgyxr4FRy7CwB4RhBahgjmklafkkrzbVpLFoM6TqgAMwyXeNBoYStVNZtcTh5XMlr=bPPLTl=4=hRc2xrsA-jX2Wfn-ltOVLrATCo2jijVh9BokuYmMaa4turX6iB6B5o3nPBcyhjsKbAphuYsFuNeqZrLMzTcM9BXTvR4LPTahCjLThfMh8t8CXMsFh=-wqta87BC3Ztcyv=45bSikeBihag92vB8FwfctK54IwPLb7BVBgjsyPYLklSo-x1L5vGBEKxyTw6LylPcIy=HLWj6UDNNhAjyI8b4e71XXsVqyFRXMp=_kaPH_0tSNL6QgEo4MzM4-vRrkKPrFho4kCPQj9NLkacntlBrNRo4wzrA5_6cyaByy9jy-6pAtCqgPwPNUbiLqaB9xDML5Y4sTC-cPvBsPZjsM9PxzZ=4gAY-BPPxM8jLxARGyR=9n7T4xZrXj8-4eKB977bHhopct9PoTaqoTCPX5IBLThNjjxR4_lhs7N
replies(1): >>22941186 #
15. mtlynch ◴[] No.22938330{4}[source]
> You may not be aware of how many banks/airlines/ticket websites have outsourced their fraud fighting to solutions like Shape Security, or Sift (Science). Web-wide tracking via cookies is a reasonable and widespread technique for fighting fraud.

I view that as a different situation. If a bank/airline/ticketer outsources fraud to a third party, there's presumably an informed exchange of "we'll let you run JS on every page on our website and suck up whatever information you want if you help us detect fraud."

In the case of Stripe, I don't believe they're clear with client applications that they're collecting information from every page of an app. I think most developers integrate with Stripe so they can accept payment on one or two pages and probably don't expect Stripe to be collecting the level of data they're reporting back to Stripe servers.

replies(1): >>22938487 #
16. bsamuels ◴[] No.22938364{4}[source]
I honestly cannot fault him. While online fraud prevention is a massive industry that touches almost every major website we use, you don't exactly have people giving talks about how serious the problem is or how advanced the detection tooling is because the nature of the industry requires you to keep your methods secret.

Heck, I have a friend who's working on a non-finance web app with <20k MRR, and even at that size he's starting to encounter fraud problems that require tooling to mitigate.

If your app stores any data that may be sellable on the dark web, you are a target.

17. brunoTbear ◴[] No.22938487{5}[source]
This “level of data” doesn’t strike me as alarming. It’s views and mouse locations. Really no different than any simple analytics solution.

Hypothetically: I tell a dev to drop a piece of JS on every page that seems related to payments. That dev probably isn’t doing their job super well if they don’t ask me why or wonder why and find out.

I think you imagine HN readers to be dumb. Nothing here is surprising.

I know it’s covid era and we felt good as a community wagging our fingers at Zoom’s naughty FB tracking inclusion. Legitimate concerns there given the advertising business model, and no good reason for zoom to be doing it. This is fundamentally different: the data is for a good purpose with a narrow scope to a good company with a user-positive value creation model.

I believe your princess is in another castle.

replies(1): >>22939843 #
18. SahAssar ◴[] No.22938781{4}[source]
> reasonable and widespread

One of those can be factual and the other is clearly subjective.

19. voiper1 ◴[] No.22939474{3}[source]
>I believe many developers integrate with Stripe expecting that their JS library executes and shares data only on the pages where Stripe UI elements appear on the page. The fact that JS library runs on every page and sends data back to Stripe, even before the app calls the API, is unexpected.

It's not unexpected when they tell you to include it on every page:

As was in their docs ages ago and still now: https://stripe.com/docs/js

>Including Stripe.js >Include the Stripe.js script on each page of your site—it should always be loaded directly from https://js.stripe.com, rather than included in a bundle or hosted yourself.

>To best leverage Stripe’s advanced fraud functionality, include this script on every page, not just the checkout page. This allows Stripe to detect anomalous behavior that may be indicative of fraud as customers browse your website.

... they are asking you to enable them to track your user's interaction with your entire website.

20. adambyrtek ◴[] No.22939843{6}[source]
You might have some reasonable arguments, but your condescending tone is completely undermining the conversation.
21. somishere ◴[] No.22940721{3}[source]
Could you simply use an iframe with a sandbox attribute? Idea being you dynamically create an iframe, fill it with content (styles, postmessage scripts, what have you), then dynamically set a semi-restrictive sandbox before loading Stripe's library. When you're done (i.e. have a payment token in the parent) just remove the iframe. This way everything Stripe related is sandboxed and the script is unloaded as soon as you're finished with it.

Good chance I'm missing something, or there's some kind of protections in place around this.

https://developer.mozilla.org/en-US/docs/Web/HTML/Element/if...

replies(1): >>22940823 #
22. mtlynch ◴[] No.22940823{4}[source]
That was another solution I considered. I think that would work, but it seemed expensive to implement. I believe it would still require me to host a separate copy of my app or a standalone app that handles just payments. Stripe also creates its own child iframe for displaying payment UI, so at that point, my app would look like:

  Main app
    My sandboxed iframe
      Stripe's iframe
So managing all the bubbling up and down of messages felt like it was going to be complicated. Limiting Stripe to a single page and forcing the new HTTP requests to unload it is a bit hackier, but is really simple to implement. You can see it in the blog post - I only had to add ~5 lines of extra code to my app to make it work.
replies(1): >>22942923 #
23. Nextgrid ◴[] No.22941186[source]
> The fact that the stripe.js payload is sent in ~cleartext is either a sign that their eng team was unwilling to roll their own encryption, didn't feel it was necessary

It is indeed not necessary when you can just use HTTPS.

24. lowan12 ◴[] No.22942189{3}[source]
I mean, the docs literally spell this out, so I'm not sure how much you or the author of the article wants their hand held:

> To best leverage Stripe’s advanced fraud functionality, include this script on every page, not just the checkout page. This allows Stripe to detect anomalous behavior that may be indicative of fraud as customers browse your website.

https://stripe.com/docs/js

25. somishere ◴[] No.22942923{5}[source]
My problem is primarily that I'm working with SPAs where a refresh really lowers the game.

I put together a proof-of-concept using a 'same-domain frame', no secondary domains or apps. The idea is separation over security, so you can unload without any side hustle. Tho without a second domain you're relying on Stripe being as trustworthy as they are, and not looking to actively undermine your sandboxing attempts [which I think is ok - we embedded their library in the first place].

https://codepen.io/theprojectsomething/full/ExVNEoZ