Hey folks, today I released the new website for my open source push notification tool ntfy.sh. I’d love some feedback and/or criticism. Please don’t be shy.
ntfy is a tool that lets you send push notifications to your phone from any script or server using a simple HTTP PUT/POST requests. It’s 100% open source and self-hostable, and has clients for Android/iOS/web/macOS/Windows/Linux. You can use it like this to send yourself notifications (more in the docs, and then receive them on your phone or desktop:
curl -d "Backup on $(hostname) complete" ntfy.sh/mytopic
It integrates into everything under the sun and is super easy to use.
The ntfy.sh server is free to use for everyone within documented limits (which are enough for 90+% of users). If you need higher rate limits (more daily messages, bigger attachments, …), you can pay for plans in the web app.
I am happy to answer questions, and I’d love feedback to the tool, or to the new website.
UnifiedPush aside: I’m happy this exists as an option to get notifications out of the hands of Google. I don’t use ntfy as I don’t yet have a use to use with scripts, but I do use the protocol via a self-hosted Prosody XMPP server and
mod_unified_push
+ Cheogram (XMPP client & Conversations fork) to handle the incoming notification for Tusky (Mastodon) & Element (Matrix). XMPP is well-suited to as a way to handle this UnifiedPush because it’s push by default and as a bonus I get lightweight decentralized chat. I’d encourage folks to give the UP protocol a shot and maybe add support to your own projects.Certainly! It would be good to see the ntfy client get support for UnifiedPush with other distributors, so it would be possible to gain the app’s functionality without needing a second permanent connection open. Currently there is a fork of gotify (similar app to ntfy) with support for this, but it feels less actively maintained than ntfy.
How do I ensure that only authorized publishers are able to submit notifications to
ntfy.sh/mytopic
?keep
mytopic
a secret and only give it to authorized publishersEven if you do that, can’t any middle-box or intermediating agent see
mytopic
as part of a request URL?Ultimately I think this is fine! It just means that
ntfy.sh
is basically a demo server, that topic names underneath that domain provide no form of access control or delivery guarantees, and that any actual user will need to self-host with appropriate security measures. Which is, I guess, important to make clear in the docs. Specifically, there is no way for users to “choose a unique topic name” in a way that “keeps messages private”.an intermediating agent shouldn’t be able to see anything w/ https
you could think of that URL as being analogous to an API key
It would be incorrect to think of any URL as equivalent (in the security sense) to a secret like an API key.
Discord webhooks work the same way ¯\_(ツ)_/¯
i think any webhook works the same way 😅, as does many cloud file providers that have things like “Anyone with this link” on things like google docs or dropbox… invitations to chats on systems like whatsapp for anyone with the link (or QR code)…
it really all depends on what you do with the URL, and the administrative practices of the people running the site that utilizes this method of security
as long as you don’t misuse it, and it’s using https, and the people running the site do it knowing this is how the security works, it is absolutely secure… and, as long as everyone is aware, as secure as using an unencrypted API key…
The consequence of an unauthorized POST to a Discord webhook is an unauthorized message in an e.g. Discord channel. No downstream consumer would assume that an arbitrary message, whether submitted via webhook or otherwise, is actionable without additional authn/authz. So I don’t think this, or any other kind of webhook, is directly comparable. I could be wrong! If
ntfy.sh
topic notifications are understood by consumers to be un-trusted, then no problem, and mea culpa! But that’s not what I took away from the docs.You seem to be dead set to find a fatal flaw in ntfy, with quite the dedication. :-) I disagree with your assessment that the security of an API key and a secret URL are fundamentally different. And with that fundamental disagreement, our argument comes to an end.
On the wire, a HTTP request with an API key looks like this:
A request against the ntfy API looks like this (excluding the JSON endpoint, which is more like the above):
The only difference is that the secret is in a different spot in the HTTP request.
You made an argument that you cannot rely on TLS: That is completely flawed, because if you cannot trust TLS, then your header-based auth also falls apart.
You also made an argument saying that you cannot rely on people making HTTPS requests. That also applies to the traditional Bearer/Basic/whatever auth.
IMHO, the only valid argument to be made is the one that the HTTP path is cached and prominently displayed by browsers. That’s correct. That makes it less secure.
ntfy is a tool usually used for casual notifications such as “backup done” or “user xyz logged in”. It is geared towards simplicity: simple simple simple. It doesn’t do end-to-end encryption, and the examples are (partially at least) suggesting the use of HTTP over HTTPS (for curl). So yes, it’s not a fort-knox type tool. It’s a handy tool that makes notifying super simple, and if used right, is just as secure as you’d like. But yes, it can also be used in a way that is less secure and that’s okay (for me, and for many users).
I really didn’t want to get into such a (what it feels like) heated discussion. I just wanted to show off a cool thing I did …
Technically, I agree with you that secret links and API keys are the same. I also agree that secret links are a simple, adequate solution for a simple service like ntfy.
When reasoning about the security of secret links, I’d encourage you to also think about the practicalities of how people tend to use links: It’s extremely easy to share them and people see them more as public information. This can be seen in the behavior of some tools that automatically upload and store them elsewhere without encryption, e.g. browser history sync. IIRC this also lead to leaked password reset links when outlook automatically scanned users’ emails for links and added them to the bing index.
Sorry! My intent is definitely not to find some fatal flaw. I’m providing feedback as requested:
Haha. I suppose I got what I asked for :-)
Which can be catastrophic. I’ve heard many stories of crypto scams that were fueled by a hacked “official” project Discord account sending out a scam phishing link or promoting a pump-and-dump scheme.
You can also DELETE a discord webhook
why?
In what way could/would a URL (containing a long random string) not be a secret in that sense?
Or a user is sending notifications like “The dishwasher is done” or “The Mets lost” and there’s no need for security.
Sending notifications to what? If you can
then I can
right?
Sure. But who cares? Then I abandon my channel and switch to a new one. They can’t find it, because I’m using https and they can’t MITM anything useful.
If your use case allows you to abandon one topic and switch to a new topic on an ad-hoc basis, that’s great, but it’s not something that most applications are able to do, or really even reliably detect. This is all fine! It just means that any domain that provides unauthenticated write access to topics is necessarily offering a relatively weak form of access control, and can’t be assumed to be trusted by consumer applications. No problem, as long as it’s documented.
I should really write this up as a FAQ, because it comes up so much. :-) First of, thanks for the vivid discussion on ntfy. I love reading feedback on it. Much appreciated.
The original premise of ntfy is that topics are your secret, so if you pick a dumb secret, you cannot expect it to be or remain private. so
ntfy.sh/mytopic
is obviously just a demo. Most people in real life pick a unique-ish ID, something like a UUID or another password-like string. Assuming your transport is encrypted, This is no less or more secure than using a anAuthorization
header with a bearer token (other than the notable difference that it’s in the server logs and such).If you want your topics to be password-protected in the traditional sense (username/password or a token), you can do so by using the fine grained access control features (assuming a selfhosted instance), or by reserving a topic (screenshots). This can also be on the official instance, assuming you pay for a plan.
It simply is not true that a URL containing a “unique-ish ID” like a UUID is “no more or less secure” than using an authorization header, or any other form of client auth. URLs are not secrets! Even if you ensure they’re only requested over HTTPS – which you can’t actually do, as you can’t prevent clients from making plain HTTP requests – it’s practically impossible to ensure that HTTPS termination occurs within your domain of control – see e.g. Cloudflare – and in any case absolutely impossible to ensure that middleboxes won’t transform those requests – see e.g. Iran. There are use cases that leverage unique URLs, sure, like, login resets or whatever, but they’re always time-bounded.
If you pay to “reserve” a topic foo, does that mean that clients can only send notifications to
ntfy.sh/foo
with specific auth credentials? If so, all good! 👍Well, that’s the clients fault? The client leaking their secrets is just as possible with an authorization header.
It’s trivial to do this. I don’t understand and I don’t see how an authorization header is different.
No they aren’t. Unique URLs are used all the time. Like every time you click “Share” on a document in Paper/Drive and it gives you some really long url.
We’re discussing “Capability URLs” as defined by this W3C doc which says that
and further dictates (among other constraints) that
I don’t really care about that doc tbh
edit: To elaborate slightly, I’m extremely familiar with capabilities
Sure, it’s not the most massively secure thing in the world, but anyone using this service can be confident their client isn’t making plain HTTP requests else they’d pick something normal. I don’t know why my HTTPS termination would be at CloudFlare unless I’d set it up (or ntfy started using it), and even if it were of all people I trust CloudFlare to not-spam me the most. It’s not that big a deal.
Looks like plain HTTP to me.
To clarify, an application developer using this service, being the type of developer to use a service like this, would be able to feel confident an application request to this web service is via HTTPS.
You can either refuse to listen on port 80, or you can detect they’ve transmitted it in the clear and roll that key.
I spent some time over the weekend trying to get self-hosted ntfy.sh going, but ran into an issue with iOS clients not receiving push notifications. I ensured I had followed the docs with an upstream and local base configured properly, but sadly no luck. Since iOS is a requirement for my use, I’ve shelved the effort for now.
Based on this (poorly titled/described) ticket, I’m not the only one. https://github.com/binwiederhier/ntfy/issues/402
Any chance we can get better or more reliable iOS support?
New website looks great and I would love to explore the tool in more depth!
iOS support is quite limited, but the basics should still work. I am more than happy to help troubleshoot, but I suggest looking at the known issues and the troubleshooting page.
Most notable, the most common mistake, if you receive nothing is this (I suggest you read the entire page though, since it’s relevant for iOS):
Sorry that iOS is so limited and buggy. I am just one dude, and I don’t use iOS as my daily driver. I have tried to make the best I could with the time I had. I’ll eventually get around to fixing it, or I’m happy to accept help with the iOS development. The code is also open source if you want to take a look: https://github.com/binwiederhier/ntfy-ios
How quickly we forget @jcs and https://pushover.net/
What do you mean? Pushover is nice, but IIRC it is neither open-source nor self-hostable so there is place for both.
A very happy user of pushover.net here…. it’s cheap, it works fine without having to keep extra connections open and the API is nice to interface with. I have various nagios/icinga instances pushing messages, together with various local apps sending out status messages. Great client-side/mobile app.
For what it’s worth, ntfy doesn’t need any extra connections either in it’s default configuration since it’s using Firebase (like Pushover too). :-)
This is neat, but please don’t use our community for marketing outreach if you have no other engagement here.
That said, slick product.
My apologies. I am an active reader but not a very active poster. But you are correct. Do you want me to delete the post?
No. Why? This is a great open source project and it should be fine to post here about it.
No sweat, just try to engage otherwise–submit neat stories and whatnot. We don’t want to become a dumping ground for growthhackers.
Will do.
I’ve got ntfy wired into a project and I love it!
Thoughts on the website:
I hadn’t thought of that. I’ll check it out.
High-entropy topics are secure, but some people want to reserve a short name (e.g. ntfy.sh/phil) and use a user/pass or tokens to access topics. It’s a matter of preference I suppose. Do you have suggestions for a better phrasing?
Maybe a term roughly like “vanity topics” (akin to vanity license plates) would make the intended use more clear.
On the website, I’d suggest putting reserved topics in a separate paragraph reading something like “The Pro plan lets you have topics with short, convenient names, which are secure without having to be kept secret.”
Nice! I made something similar using a mess of scripts when I was working on a test program that took around 48 hours to run — needed to get to it as soon as it was done to be able to iterate quickly. But not as a finished product!
I’ve been looking for something like this for a while. Using the native Mail client on iOS is nice, but since I’m using Migadu for e-mail hosting, I don’t get push notifications – only poll. This is in contrast to how things like Gmail work, where they incorporate their own push notifications through their developer license.
I could pay $99 for the privilege to do the same, but that’s way too much for what probably only amounts to a few extra seconds to poll for new e-mail. With something like this, I think I can get around all of the above. Only issue might be linking to the actual e-mail in the app.
Love this, absolutely something that could fit in my workflow. One issue I’ve found on an Android Phone (One Plus 7 Pro), is that in notification settings there is nothing for default notifications. I only have Max, High, Low and Minimum. This result in no proper notification (i.e no pop up or vibration) for default notifications. I’m not sure if this is an issue with my phone or the app. I downloaded it from F-Droid.
Edit: Using the Google Play version has solved the issue for me. I know there can be some funk with notifications and apps installed outside of Google Play, so not totally unexpected for the F-Droid version to be a little funky. I’ll stick to this version now.
That’s not something I have heard before, and there is no difference between F-Droid and Play in this regard. Odd. Feel free to file an issue if it’s a big issue.
I was under the impression that for proper push notifications, like your service is offering, that there was a dependency on Google Play Services? I’ve not developed for Android, so apologies if that is not correct. I seem to remember there being issues with Proton Mail on F-Droid that seemed to cite that reason before they fixed their notification issues.
Either way, since using the Google Play version it has all worked flawlessly. I will try the F-Droid version again at some point and just make sure it wasn’t something I’d done to stop it working properly.
I started using this for various notifs on my home server and it works great!
One thing about the “URL is the secret” design that I ran into though was that the URL paths have a fixed max length. I was trying to generate a 512-bit hex-encoded prefix for my topics for security, but that caused HTTP errors (4xx or 5xx, I forget which) when posting to the topics. In the end I went for a 32-bit prefix instead, which is probably fine but feels a little uncomfortable.
Topics can be 64 bytes long, which is more than enough to make them unguessable. Plus, you get rate limited and then banned very quickly if you do that.
I suggest not using just hex characters, but instead use the full set of allowed characters:
-_A-Za-z0-9
64 permitted characters, or 64 bytes?
[-_A-Za-z0-9]{1,64}
I use ntfy to send URLs from Emacs on my text terminal (where I can’t see images) to my phone, where I can. Wrote about a dozen lines of elisp to provide general integration, and also hook into eww and url-at-point.