See https://blog.healthchecks.io/2019/12/preventing-office-365-a... for someone who did have this experience.
People don't tend to report problems like "my account was activated sooner than I expected"
The verification process serves only you, the administrator. To everyone else it's a tedious obstacle.
Nobody will reach out to you to say "I made it through the registration process just fine but it was slightly less burdensome than I expected, is everything OK?"
If you want to know if Google is hitting your activation URLs, check your access logs. Your users will almost certainly not realize it happened. Even if they do notice it, there is no impact on them and no motivation to inform you. You would have to be extremely lucky to hear about it from a user.
And I'll instead refrain from using sites that inappropriately provide bare get URLs that are really state-mutating booby traps in disguise.
If everything send to gmail is opened upon arrival and cached, you know nothing about when or if the recipient actually opened the email.
What is being described here is likely being done for some other purpose.
> Instead of serving images directly from their original external host servers, Gmail will now serve all images through Google’s own secure proxy servers.
Https://gmail.googleblog.com/2013/12/images-now-showing.html
This is not just a Gmail thing. Most corporate mail filters visit a link and scan for malware as a feature.
Why not send a short random code by email for the user to then copy into the sign-up form they were in the process of filling in?
What I do think would be reasonable is having a well-labeled link which takes you to a confirmation form: someone can follow it easily and choose to submit it with far less friction and it leaves standard web semantics intact.
All of that may affect the sign-up rate.
Switching to no confirm obviously changed this to 0% drop off of people who clicked the link, but the number of people who clicked was the same.
It was curious to me why people wouldn’t go through with the confirmation step, but never learned why. We just learned that for some reason more people click once instead of twice.
So it doesn’t matter to me if they were bots or not.
For example, 100 users clicked on the first link, 80 completed, and had normal account activity (clicking on stuff, uploading and downloading things, etc).
100 users clicked on the second link and then had normal account activity.
Maybe they were all bots, but they seemed human based on the “normal activity.”
Ragequitting is one way to exit a process, but just not going to the next step from distraction is surely more common.
The original discussion was about clicking links vs reading and entering the code in sign-up confirmations. The former takes less steps and is easier to complete. Power users with unusual habits might disagree. But if they complete the sign-up anyway, it makes more sense to focus on regular users.
Extra steps are hard and boring and people don’t want to do them.
I consider myself a savvy user and I want to click a link. Not click a link, then look up a code from the email, then paste, then click submit.
I’d live with having to manually click “I’m sure I want to unsubscribe” or something.
This is most annoying when the site wants me to type in my email address to unsubscribe. I have lots and lots of different email addresses that funnel into a single one. When the site doesn’t put my address in the “To” field, I dont know who they sent to.
Services should be respectful of users time.
I've become increasingly suspicious of this practice
if my email address is in the URL, why don't you autofill that email box for me? if it's not in the URL, why aren't you fetching it from your database using my unique hash in the URL? do you even keep any records of email subscription preferences? am I just signing up for more shitty spam by giving you my email, again? am I just being marked as 'active' i.e. fresh meat, somewhere in the spammiverse?
these questions become more poignant and the suspicion more fiery when, low and behold, it turns out you are still subscribed
I don't fill them in any more, I just block the sender
don't get me started on the "it may take up to 28 days for our systems to register your desertion" bollocks -- I'm not working a contractual notice period, or running a lap of dishonour. it's a bitflip to 'false' in the 'is_pesterable' column, else a respectful deletion. it takes microseconds, not weeks!
I typically never type in any information because I assume the site doesn’t know and wants to know.
I’d rather just set up a kill rule on my end than risk getting my email on one more list.
One of them mentioned that you can continue keeping things as a 1 click solution with the token in the URL, but instead of doing the destructive action upon visiting the link -- instead you would get sent to a page with a form where the token is put into a hidden field that gets auto-submit as a POST request with Javascript.
This way from your POV it's a 1 click solution. You only waste a second waiting for the redirect and if the user doesn't have Javascript enabled you can <noscript> the field as being an input field which is pre-filled out based on the value from the URL (this can be done server side).
Now everyone is happy, unless gmail is going to go as far as auto-following redirects with JS enabled.
- You GET /reset/abc123
- Your server responds back with a page that has a form
- There's a hidden field with the token
- Javascript kicks in and on page load executes the form as a POST request
- Your server responds to that POST request and does whatever it needs to do
All of that is kicked off by gmail visiting /reset/abc123, and now it comes down to whether or not gmail's pre-visiting code will run the JS on the page. If not, then the above workflow fixes this issue, if it does then you're in the same position as avoiding all of this and having a GET /reset/abc123 perform the destructive action.Entering emailed or texted codes is becoming more common with 2FA for banking, PayPal etc. anyway so I think most people are going to broadly manage.
UX is important, and I think saying “suck it users, I’m going to use GET the way I think is write” is not a positive way of thinking about it.
I think the problem is just the mechanics of POST not being allowed in an email, so if there’s a way to POST from just clicking on a link I think we should use it. But there’s not, so having a GET that triggers something is the least bad thing. I like it better than javascript and forms in email. And better than autosubmitting, hidden forms on load.
A malicious page that knows the url used in the email could open the url from the email in a popup. The js will execute in the popup, and do the POST request. It doesn't matter how much csrf protection you have on the POST step, if anyone can trigger it with no user interaction just by opening some page with a GET request.
Sorry but this whole scenario is just ridiculous. If somebody can access your email it is already game over. It doesn't matter what web technology you are using at the that point, user interaction or not.
If a "malicious page" knows the URL it doesn't matter at all because it means it is capable of arbitrary code execution and that point it could just exfiltrate the URL to somebody or a Chromium instance to perform the user interaction. Actually if the page can open a popup I think it could also execute JavaScript within the context of the page and perform the user interaction right there.
Scenario a) No authentication-y bits in the url. User goes to the url, site checks if the user is already logged in via a cookie. If so, does the POST request.
Typically in this case the urls are easily guessable, so that's an easy CSRF. In principle they could be made per-user (some sort of HMAC on a user+timestamp). In practise, I think its fairly common for websites not to do that in this sort of situation.
scenario b) The url contains some sort of nonce, or signed assertion that automatically logs the user in. I think this is fairly common in email urls, because web developers want people to be able to take an action just from clicking the link in the email, even if the device they read email on is not the same as the device they normally use to interact with the application. I also think this is the scenario that applies to this discussion, since it was started around talking about the issues caused by google auto following links, and in scenario A, google auto-following links would not be an issue.
Of course, in principle, its possible that the authentication bits in the url, just authenticate that action, and don't generally log the user in. In practise I think its really common to just generally log the user in, since most sites want people to stay on the site once the user does anything, and not just immediately exit after the email action is completed.
These urls are typically not guessable. A small percentage of users do tend to smatter these across the internet (e.g. https://urlscan.io/), but ignoring that, this is a login-CSRF. That is, an attacker can generate their own such url, and force their victim to log into the attacker's account.
The impact of a login-csrf tend to be very application specific. Sometimes its kind of minor, but I have definitely seen cases in major websites where a login-csrf can lead to a full account take-over of the victim's account.
> Actually if the page can open a popup I think it could also execute JavaScript within the context of the page and perform the user interaction right there.
This is only true if the pop-up has the same origin as the site that opened it. Otherwise there is just a very limited API (Basically, postMessage(). Also both sides can change the current url of the other side, which is a bit nuts). Also there is now a new http header, Cross-Origin-Opener-Policy that affects this.
Kinda hard to pre-scan a URL if you can’t provide the password for it.
We solved it by having a screen with a confirmation button , then later we added javascript to show a loader page over the button and click the button automatically.
https://www.w3.org/TR/capability-urls/
It is also a good way to communicate between two parties that don't want to have user account in any service, we constantly request input from B2B customers by providing forms with a capability URLs. An no, we don't want to use an identity provider. Maybe good ones like auth0. Amazon Cognito is pretty decent in my opinion, but Amazon is also big tech. Industrial espionage is something real for that matter.
We have mail providers that respect privacy, just saying... I don't understand the love for Gmail at all, especially when you use a mail client, which I would heavily recommend to everyone.
Ironically a lot of security scanner also do follow links. Understandable, but I just hope they don't plaster the logs too much...
https://example/com/token?forBots
https://example.com/token
https://example.com/token?forBots
Hopefully any automated systems will open the first or last link first, so that you can save the request info and filter based on that. In case requests come out of order, you can always add a small delay to the "human" link before responding.I haven't yet gotten to implementing any of the authentication on my current project, so I might be missing something really basic.
The next best thing is to set a cookie when requesting the magic link, but the downside (or upside?) is that it will be valid only for the browser it was requested with.
But in those cases there may be an automatic POST after you travel to the link, so it wouldn't be triggered by gmail looking up the url.
For this use-case, it seems like even an automated link click would be a good signal of a deliverable email address.
- `sec-fetch-dest` header is present (HUMAN)
- `accept` header is present (HUMAN)
- `from` header is bingbot(at)microsoft.com (AUTOMATED)
- `user-agent` header includes BingPreview (AUTOMATED)
HTH
I have my browser configured to retrieve the page only and no additional requests for CSS, images, or javascript.
Make the emailed verification/reset link (GET request) idempotent (1 and >1 request has the same effect).
Have the link just present an interface for the user to take the next step. In the next step make a POST request that actually commences your verification/reset process.
In all likelihood you'll want expiry logic (let's say it's 30 minutes) - if you store the token with a created_at timestamp on the server you can have your verification/reset process check that now < (created_at + 30 minutes)
If expired, provide a UI for the user to request a fresh verification/reset email.
<link rel="prefetch" href="/actual_validate/email/1d00a5c2648c211befd33f5a8a7cbfab?prefetch=1">
<script>
location.href = "/actual_validate/email/1d00a5c2648c211befd33f5a8a7cbfab?js=1";
</script>
<noscript>
<a href="/actual_validate/email/1d00a5c2648c211befd33f5a8a7cbfab?js=0" rel="nofollow" class="btn btn-primary" role="button">Click to confirm your account</a>
</noscript>I assume so, because of an old trick where query strings are used for ad-hoc cache control as in /style.css?1629472765
On the other hand. It validates the email address more quickly, so you could even refresh/poll when it's verified automatically
A better solution is to assume that some middleman (email server or client) will always try to access links in the email. Instead send the user a code and have them manually enter it on the linked page.
I'm not a web developer. Out of curiosity, why is that?
These assumptions are so baked into web software that while assuming a GET request won't do anything zany or overly stateful is probably fine, assuming the same for a POST request should probably be considered negligent.
74.51.221.37 - - [19/Aug/2021:22:05:16 +0000] "GET /validate/email/1d00a5c2648c211befd33f5a8a7cbfab HTTP/1.1" 404 0 "" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.107 Safari/537.36"
$ dig -x 74.51.221.37 +short
cache.google.com.
I sent a link to a large file over Viber and immediately some ip connected and started downloading. Stopped at 350mb of around 3.5gb. I get that they want to show thumbnails or whatnot, but they just don't discriminate between content types.
I'd be fine if the fine print in the EULA provides a guarantee that the feature scans content solely for generating previews, and that M$ keeps no copy of it, etc....But, I'm sure I'd go blind looking for such text in the EULA.
If you're building your web app in development, chances are your links will have localhost as their hostname which wouldn't trigger a visit from Google. You may also end up having an in memory fake email server to not even send the email in dev too (lots of web frameworks have solutions for this).
Checking the user-agent might work but I'm not a fan of this method because now it sets you up with having to keep a list of all known agents for every email client / service that might pre-visit URLs.
(Because waiting for Gmail to load on a laptop is painful, whereas on my phone is shows up as a push notification within seconds)
74.51.221.37 - - [19/Aug/2021:22:05:16 +0000] "GET /validate/email/1d00a5c2648c211befd33f5a8a7cbfab HTTP/1.1" 404 0 "" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.107 Safari/537.36"
I suppose you could somehow block cache.google.com but I suspect Microsoft and others do similar things.
So a link that is only valid once would be affected. Restricting the validity by time is a good way to solve this while still maintaining decent security.
/validate/email/1d00a5c2648c211befd33f5a8a7cbfab
The token is cryptographically strong and disappears after access. It can't be guessed and no one but the email account holder should click it, but I am seeing the URL accessed multiple times from multiple IPs, so I investigated.
Turns out, if the user provides a Gmail or Gsuite email account during registration, Google clicks the link. I was curious if others on HN had encountered this and how they dealt with it.