As above, I’m self-hosting Ghost, but I can’t for the life of me find where I can customise, edit the html of the sign-in page so that I can integrate it with Cloudflare Turnstile.
Any ideas? I can’t edit the ember.js stuff
I know this is an old thread but it’s the top search result when looking for this: I tried all kinds of injections for Ghost’s portal, and didn’t get anywhere.
But since this is about Cloudflare Turnstile specifically, here’s an alternative for those that need the protection (this works for signing into Ghost).
I started getting a lot of bounces/email complaints from bots — yes, bots can and will mark your welcome emails as spam while still joining your website. Because Ghost is unprotected by default, having a high percentage of bounces & complaints through services like AWS SES will be negative for your account and sender reputation. And of course affects your server’s IP reputation if that’s how you’re sending.
As an alternative to installing the Cloudflare Turnstile script (or in conjunction with, you can use both, but this is essentially using the same Turnstile technology in the background):
Go into Cloudflare Dashboard → Security → Create rule:
Rule name (required): Protect Ghost CMS Signup Endpoints
When incoming requests match…
Field: Operator: Value
Request method: equals: POST
AND
URI Path: contains: /members/api/send-magic-link/ OR
URI Path: contains: /members/api/signup/ OR
URI Path: contains: /members/api/signin/ OR
URI Path: contains: /members/api/create/ OR
URI Path: contains: /members/api/subscribe/
Expression preview: (this will automatically build based off what you’re doing above)
(http.request.method eq "POST" and http.request.uri.path contains "/members/api/send-magic-link/") or (http.request.uri.path contains "/members/api/signup/") or (http.request.uri.path contains "/members/api/signin/") or (http.request.uri.path contains "/members/api/create/") or (http.request.uri.path contains "/members/api/subscribe/")
Then take action…
Managed Challenge
Then of course hit save. This will protect Ghost CMS endpoints from bots the same way invisible Cloudflare Turnstile does, and if the user is suspicious they’ll be presented a challenge. You can use a different action, but this is probably “safest” for false-positives, so you don’t block legitimate people maybe using VPN, proxies, etc.
Bonus: go to Security → Settings
Turn on “Block AI bots” if you don’t want AI to be scraping your website for training.
Turn on “Bot fight mode” to detect JS and challenge bots — keep it off if you’re serving API and doing a lot of data exchanging on-server that’s legitimate, it might challenge your own processes.
Hope that helps! I think trying to mess with the portal or even having to manually edit and keep track of forms is too much busywork when Cloudflare offers these security rules even for free accounts.
So… I’m confused. Your list of endpoints are just that. They’re endpoints. They’re not webpages. They receive javascript requests from the browser, invisibly to the user. So, while I’m sure you can block access to them, I’m not sure how Cloudflare would serve a challenge for the user to respond to.
As far as I understand the idea here is, when a bot make those api requests for signup, Cloudflare will block that request and respond with a captcha challenge instead of delivering that request.
But, in case of false positives, for a real user, if Cloudflare blocks a legit XHR request and returns a challenge, Ghost’s portal JS will not understand that response and simply fail. That will cost losing that signup.
I’m not sure this can be handled with a regular “form post” if we use custom member signup page. If so, if Cloudflare decides to challenge post request, a human can pass the challenge.
Yeah, you can’t put challenges on API endpoints, but you can put challenges on the forms to initiate on POST requests, but only for regular forms. I don’t think this is possible unless the client side code itself is modified to integrate with captcha. I tried htmlrewriter before but as mentioned the site is client side generated. And i’ve since moved on from Ghost and went full SSG with Astro