5 ms·
Author here. Happy to answer any questions or hear feedback about this post.
by mtlynch 7y ago
Author here. Happy to answer any questions or hear feedback about this post.
- swyx 7y agotitle 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.
- mtlynch 7y ago> 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.
- falcolas 7y agoNo, 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.
- lowan12 7y agoI 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 https://stripe.com/docs/js
- deleted 7y ago[deleted]
- dang 7y agoWe've changed the title - see https://news.ycombinator.com/item?id=22937739 https://news.ycombinator.com/item?id=22937739
- swyx 7y agowe love you dang
- TAForObvReasons 7y agoHave 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!)
- mtlynch 7y agoThat 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.
- somishere 7y agoCould 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/iframe#attr-sandbox https://developer.mozilla.org/en-US/docs/Web/HTML/Element/if...
- mtlynch 7y agoThat 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.
- tomashertus 7y agoThis 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.).
- mtlynch 7y agoThanks 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.
- brunoTbear 7y agoYou 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.
- mtlynch 7y ago> 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.
- brunoTbear 7y agoIt'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