-
Notifications
You must be signed in to change notification settings - Fork 577
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
NIP-43 - Fast Authentication #571
Conversation
1a15349
to
e8caf81
Compare
I understand the difference between this and NIP-42 and the advantage of checking Auth at connection rather than at write. However I think NIP-42 can be changed to check Auth at the time of connection. I was setting up a relay for secure DMs and need a way to Auth at connection and only allow kind 4 query for the Authed pubkey. I was able to modify nostream relay to Auth at connect and restrict query. Find a working code here. It supports NIP-42 Auth at connection. https://gist.github.com/starbackr-dev/558c30c126bcb2e10d39e1dc9c58d8a6 I still feel NIP-42 is better because you exchange challenge String. You can also auth multiple times adhoc when the user is trying to do something. If this solution was presented before NIP-42 merge then I would have picked this. But now, NIP-42 is already supported by relays and clients (Amethyst) and nostr-tools. The cost of change outweighs the benefit we get with this NIP. Unless I am missing something. |
I agree, what problem is this solving? I will agree that AUTH is currently a pain to implement (you have to queue up pending messages until the AUTH handshake is done), but it covers all use cases in a way that this doesn't. |
@starbackr-dev Thanks for the gist although no matter what code you write, NIP-42 can't really do auth on connection. Problems: Relays aren't required to send NOTICE/OK messages so you can't even really wait for a successful authentication. With NIP-43, the server is expected to authenticate the user before the user receives the 'open' event. |
@staab with NIP-42 you can't even be sure the AUTH handshake is done. You just know you already sent the 'AUTH' response, but doesn't know the relay finished processing it. The NIP-42 challenge requirement was a mistake. Either way, the client you are using can read everything you send and receive to/from relays. Even your encrypted DMs will be visible to the client after for example the NIP-07 extension decrypts it. At the end of the day, you are trusting the client wether you are using NIP-42 or 43. |
Of course you're trusting the client, I don't see how that's relevant. You're right that the flow is awkward, maybe that could be fixed by requiring the OK response instead of introducing a different, less flexible flow. |
thanks @arthurfranca for the clarification. Since I am using 1 relay I resolved the promise at AUTH. The correct way to do this is to read the NIP-11 relay document that has this flag "auth_required": true, which will indicate if I expect to Auth or not. I think we all agree that there are problems in NIP-42 auth flow. Is it fixable or do we need to rip it off and replace is the question.
Also, can you expand more on this statement? ? |
@starbackr-dev The challenge requirement is used to prevent the user A's malicious client from forwarding the user A's AUTH event to an user B. So user B wouldn't be able to start a new websocket connection and authenticate as A on same relay using the forwarded AUTH event because the challenge would be different at each new connection. But 1) this attack doesn't make much sense because the user A's client, after AUTH, can already act as A without waiting for user clicking any button. The client can already send 2) With NIP-43 the relay mitigates this forwarding auth events problem here by storing the auth event id for a while. 3) For So the challenge requirement is a mistake because it brings nothing to the table while being the reason why the authentication flow needs extra round trips, which is really bad for websockets, cause it is not request/response based like regular http requests, so can't guarantee order of messages. |
Imo NIP-42 should be deprecated (just like NIP-08 was too).
NIP-43 is the right fix. No need to check NIP-11 relay document, nor wait for NOTICE/OK responses that may never come, nor think of when to expect to receive or send auth messages. |
Here are the things that might be lost if NIP 42 were deprecated:
I am overstating my case here, I don't know how important all these things are, just listing them to be clear about potential trade offs. |
Yes but is revealing the pubkey really a big problem? It has its benefits though like the relay can rate limit per pubkey. For being easier to implement, more relays may require auth for viewing DMs. And I think most NIP-42 enabled relays will send "auth" message from the start (see how @starbackr-dev gist expects this to be the case). Also, for NIP-42 support, clients will most likely be automatically configured to send "auth" replies as soon as it receives "auth" request. It would be difficult to imagine an UI showing popups for the user to manually accept replying to relay auth requests. Do you do this with coracle?
Not a problem. The client could always send "authorization" query parameter no matter if relay requires authentication or not. edit: I agree that one may want to lazily authenticate (although not me). See comment below
Kind of false. The user is authenticated from the start, but authorization to use a specifc resource is another topic.
I can't comment on that. Care to show us a draft?
NIP-42 doesn't officially support this. It was suggested but rejected. To switch accounts one has to reconnect, both for NIP-42 and NIP-43. |
I would add that, for NIP-43, nothing stops relay from requiring auth at a later moment. And clients can try connecting without "authorization" query parameter first. The difference is that it would require a reconnect. But it is better than the NIP-42 back and forth. |
Hello @fiatjaf could you say something? I know you dislike challenge in NIP-42 and NIP-98 HTTP Auth security is very similat to NIP-43. What about instead of deprecating NIP-42 we just add NIP-43 and see which one wins? |
Even though I don't like the challenge I think it is not that hard to do, and we should stick to having a single way of doing things. Adding another one just because we can is not a good idea from the protocol point of view. Also, about your comment:
I suggested the same thing when I was trying to get NIP-42 to not require any challenges, but @cameri replied that was a bad idea because something about distributed computing or something like that made it very hard. I also remember being convinced by @cameri that the challenge was important, and the argument wasn't that a client was malicious (I had already dismissed that argument myself). So there must be another argument, I just can't remember what it was or find it in that thread. Maybe I made a mistake and shouldn't have been convinced, but requiring the challenge is not that bad. |
@fiatjaf you know what is funny? NIP-42 isn't even implemented at nostream yet. I re-read NIP-42 PR discussion and he did had an argument of nostream being multi-process and that according to him it would be hard to store the event id for the time window duration because he would have to use locks. Seriously, this is a weak argument. Nostream has Redis which is perfect for this cause it is single-threaded, executes commands sequentially and has expiration feature. |
I agree with you. |
If we decide the challenge is not important and @cameri doesn't show up here to convince us of the contrary, can we modify NIP-42 in a backwards-compatible way? I think it is not even being used anywhere. |
I'm in the process of adding AUTH support to Nostream |
I have an working version of nostream relay that accepts NIP-42 AUTH on connect. I will stand in for @cameri to support that challenge AUTH is better than one time auth header. The below working version uses nostr-tools for AUTH and it works with Nostream relay. Also Amethyst client has implemented NIP-42 as well. https://gist.github.com/starbackr-dev/558c30c126bcb2e10d39e1dc9c58d8a6 @staab had some good points on why we need AUTH challenge I like @arthurfranca enthusiasm and passion on this. But I will repeat what I said earlier. The cost of change outweighs the benefit we get with this NIP. |
Not using a per-connection challenge and depending on storing/looking up the signed AUTH event makes authentication stateful and bakes the requirement that relays must effectively process each authentication attempt serially to avoid replay scenarios. I have various instances of Nostream around the globe, all with their own Redis instance for increased performance. None here should care or know about how that works. With NIP-43 support, there has to be a single shared Redis instance for all distributed forms of Nostr relays just to avoid replay scenarios. It's like NIP-43 makes assumptions about the kind of architecture relays can have if they decide to support it. I'd be fine with NIP-43 if we make the check for used signed auth events optional and not mandatory. That way people will know what they are getting into by using NIP-43. This is all about trade-offs of each solution, not about whether @cameri added NIP-42 support to Nostream or not. |
I'm not sure if I follow. If it is one Redis instance per deployed relay, I give you 2 options to store the auth event ids (Note: I will consider it NIP-42 for key name below cause fiatjaf wants this PR to be an edit to NIP-42 instead of a new NIP):
It is all atomic, no race conditions. There are other ways too. If not using redis, a DB unique constraint is enough. If single-process, it could be stored in memory.
"The authorization event |
I will change the PR to make it an edit to 42.md but I think I won't have time to do this today. |
@fiatjaf done. ready for review/merge |
you know, it is possible to include an authentication tag on every message, if you want to avoid the queueing problem for both the client and the server
advantage:
disadvantage:
maybe this is better than NIP-42? need to ask server authors |
8b784ad
to
9bab3e6
Compare
Just git rebased |
Still NACK, for two reasons.
|
@staab if we consider the client is supposed to decide when to authenticate instead of asking the user, will it blindly authenticate when receiving a NIP-42 relay AUTH message? Probably yes. Is eager authentication vastly different or worse than blindly authenticating when relays ask it? |
No, but clients shouldn't blindly authenticate either Edit: to elaborate, I've recently realized relays built into bech32 entities pose a (minor?) security/privacy vulnerability, since user-generated-content can make a user's client connect to a specific server. Clients should maintain a list of user preferences for given relays, asking permission to connect in less-certain cases (like when no one you follow lists that relay). |
I don't see connecting to a random relay as a threat or else nostr has a big problem specially considering NIP-65. Sincerely I don't see clients asking for auth permission as a good user experience. Though NIP-07 extensions/signer apps may warn users when asking to sign authentication events. |
That is a lot of extra fiddling just to avoid a slightly different set of assumptions.
NIP-42 incentivizes this. Bad clients get an easy antipattern either way: blind authentication or eager authentication.
If I read it correctly in this NIP the client still must sign the authorization event, so that should not be possible, but I see your concern. Since the privacy issue stems from the eager auth antipattern, maybe we can work around that by making it immediately clear to user/client which relays are authenticated or not. One way to do this would be to require a username in the URI. Like with git hosts you can read/clone via the public HTTPS endpoint, or you can get full access via the git/ssh server where you authenticate with your pubkey but you login with some designated username like |
I was going to (and probably still will) speak to this at Nostrasia, but I'll just say it here too. I think @jb55 makes an excellent point about not connecting to random relays. When I visit a website, and it tells my browser to go to google fonts, that bothers me, that is not good. I want to control that, so I install uBlock Origin and restrict where the browser is allowed to go. NIP-65 is a protocol-level thing, and clients are still free to refuse to go to relays that are not whitelisted. I intend to put whitelists and blacklists (default deny or default allow) into gossip eventually. NIP-65 doesn't force a client to do anything, it is just informational. I hope this isn't too much off topic. I'm holding my tongue as to the actual topic for the moment. |
@badonyx if I got ir right, your idea is to use
You think clients should only connect to unknown relays if not authenticating, by connecting to the relay without adding "nostr@" to the relay url. Wouldn't this part be the same as not adding |
@mikedilger good insights. A relay deny list seems useful when relays start getting evil. Though I'm yet to find out exactly what harm they can cause aside from linking pubkeys to IP addressess and sending invalid nostr events. @staab I dislike NIP-42 flow. The relay AUTH message comes by surprise at any moment and most likely will make the first client REQ/EVENT message fail. REQ is the major problem because the relay will probably just return an EOSE without events which is hard to detect as a failure. NIP-43 tries to fix this by authenticating from the start. Don't you think privacy focused clients can deal with that by using random keypairs to sign NIP-43 events when it thinks it won't access restricted content (it won't fetch DMs, for example)? It is the same approach of NIP-96 file upload using NIP-98 login where you can use random keypair to be anonymous but yet the flow is kept simple by always requiring the client to sign an authentication event. |
I just want to keep the spec simple if we can ("one way of doing things"). If clients want to eagerly authenticate, why can't they send auth right away? Right now coracle handles some of this by buffering commands to be sent if negotiating auth so they don't get lost. I imagine relays could do the same thing by hanging on to client requests until auth is negotiated and retroactively fulfilling them. I'd far rather have a marginally more complex implementation than a marginally more complex spec. Edit: so,
It seems to me that there's not enough creative discussion going into making what we already have work better, and too much eagerness to add a new spec. Implementations come and go, specs are forever. |
Your message exchange example is perfect but I'm afraid of some relays failing to implement it right and some clients postponing implementation due to complexity.
Great! Right now the spec forbids it but this would help a lot and I guess with that in place we could close NIP-43 PR. A minor inconvenience is one must always check NIP-11 or else the client started AUTH message would get no response when talking to a relay with no NIP-42 support. While with NIP-43 a client could try to eager authenticate without checking NIP-11. |
Ah yeah, good point. The challenge is there to prevent replay attacks, but I guess we could change the spec to allow the client to provide its own time-based challenge. |
I thought it would be a client AUTH message with no event just to tell relay to send it back an AUTH carrying the challenge right away. But if it were like you said it would be better, similar to NIP-43 if I got it right. |
Co-authored-by: Semisol <45574030+Semisol@users.noreply.github.com>
A signature is at most valid for 5m and the worst that can happen is not much. And how would it even get leaked? |
#902 made NIP-42 great again. If someone was using NIP-43 I can re-open it. |
Non-interactive client to relay authentication.
Meaning it authenticates on connection request and uses same event kind from NIP-42 but no challenge, similar to NIP-98 HTTP auth.
Updated NIP Text here