nips icon indicating copy to clipboard operation
nips copied to clipboard

nip57: add lnurl tag to prevent custodial replay attacks

Open jb55 opened this issue 2 years ago • 23 comments

Add a new condition to zap requests:

  • SHOULD contain a lnurl tag, which is the resolved lnurl for the target user. The resolved lnurl is either the lud06 field or the lud16 field converted to an lnurl: [email protected] => bech32("lnurl", "https://zaps.com/.well-known/lnurlp/alice"). The purpose of this is to prevent an attack where a user replays their zap request note to another user that shares the same nostrPubkey. This tricks the zapper to send a zap note to another pubkey even if the invoice being paid is to someone else on the same server. Clients MUST match the lnurl field against the zap request p-tag user's resolved lnurl to prevent these kinds of attacks.

jb55 avatar Feb 19 '23 21:02 jb55

This doesnt prevent me zapping myself and having e/p tags for different people.

I can zap myself and then tag jb55's pubkey in the zap request, LNURL service is none the wiser as to if im really zapping jb55's LNURLP

Edit: this can be checked on client side

This wont work for LUD06 as there is no username

v0l avatar Feb 19 '23 21:02 v0l

This doesnt prevent me zapping myself and having e/p tags for different people.

I can zap myself and then tag jb55's pubkey in the zap request, LNURL service is none the wiser as to if im really zapping jb55's LNURLP

Edit: this can be checked on client side

This wont work for LUD06 as there is no username

Yes was going to point out similar sentiment. Wouldn't work in all cases

andrerfneves avatar Feb 19 '23 22:02 andrerfneves

If zappers would require users to specify their pubkey when creating an account with the provider, they could verify that the p-Tag in the note matches. This would require more implementation (and also frontend work) from lnurl providers, but would work for lud06 and 16.

Egge21M avatar Feb 19 '23 22:02 Egge21M

I will update to lnurl instead of user, this should work? For users with lnaddress these can just be converted to lnurls trivially

jb55 avatar Feb 19 '23 22:02 jb55

Clients would then check the target p tag in the zap request and make sure it matches their resolved lnurl for the target user

jb55 avatar Feb 19 '23 22:02 jb55

just updated, does this fix all of the issues?

jb55 avatar Feb 19 '23 22:02 jb55

@jb55 At this point I don't think zaps counter can be made reliable, even with extra validations. @callebtc and me just had fun on Snort and uncovered this edge case that allows infinite zapping of notes:

image (post is on: https://snort.social/e/note1tt0gpvhf3mfygwyyw4cwhyxjt4ffd044rja9dyf2m6est4r46d7sfsxx6q)

I've setup @callebtc's lightning address in my account and now he can zap my notes non-stop while counter goes up. Anyone can do this even without cooperation of another person.

This is likely outside of context of this PR, but wanted to give you a heads up, as you and @v0l continue working on NIP57.

rockstardev avatar Feb 20 '23 00:02 rockstardev

I've setup @callebtc's lightning address in my account and now he can zap my notes non-stop while counter goes up. Anyone can do this even without cooperation of another person.

Could you elaborate how can this be done without cooperation? Can you zap me infinitely if I don't put your address in my account?

fabianfabian avatar Feb 20 '23 06:02 fabianfabian

Could you elaborate how can this be done without cooperation? Can you zap me infinitely if I don't put your address in my account?

No, because this only works if the sats end up in a wallet that you control.

This still is highly problematic though. As long as a zap's "integrity" is questionable, they are nothing more than noise.

I guess this always has been the case though. Even if we would solve these issues, a single entity could operate two accounts and spam Zaps all day long...

Egge21M avatar Feb 20 '23 06:02 Egge21M

Even if we would solve these issues, a single entity could operate two accounts and spam Zaps all day long...

For a future iteration of zaps:

Zaps can be paid-for note PoW. NIP-13^1 supports PoW delegation, so you can pay for someone else to mine it, yet still sign it yourself.

In this sense, a zap is not "sats sent to the receiver", but "sats paid for this (reaction's) PoW". The zap counter could mean "total PoW of reactions to this note".

Upside is zaps cannot be faked. Whoever receives these zaps knows for sure this is signal, not noise.

Downside is sats don't go to the zapped profile or note, but to whoever mined the PoW. However, note author can still separately receive (un-fakeable) sats via normal LNURL or LN Address.

ok300 avatar Feb 20 '23 09:02 ok300

As long as a zap's "integrity" is questionable, they are nothing more than noise.

I think there is no way to ensure that a zap isn't a "wash zap". Even if you provide preimages etc. Therefore, I don't think we need a perfect solution now, an incremental improvement like the one proposed in this PR makes a lot of sense.

callebtc avatar Feb 21 '23 15:02 callebtc

The solution proposed here still allows people to spam invalid zaps and puts all the burden on the client to verify every single one of them.

Are clients even verifying the zap provider public key currently?

fiatjaf avatar Feb 21 '23 17:02 fiatjaf

If zappers would require users to specify their pubkey when creating an account with the provider, they could verify that the p-Tag in the note matches. This would require more implementation (and also frontend work) from lnurl providers, but would work for lud06 and 16.

@Egge7 Yes, but it's not enough. You have to prove you own the nostr pubkey somehow. Otherwise I can just put someone else's nostr pubkey in there and still do the zap request forgery. Potentially can re-use the lud-16 metadata where you already put the Lightning Address, as that information was signed by the pubkey.

Furthermore, I believe nostr clients also have to cross-check this.

hsjoberg avatar Feb 21 '23 23:02 hsjoberg

I think there is no way to ensure that a zap isn't a "wash zap". Even if you provide preimages etc.

Wash zaps are fine. We just can't have fake zaps, otherwise zaps will always just be some cosmetic tipping thing. Instead they are supposed to be much more than that and power real actually useful use cases.

fiatjaf avatar Feb 21 '23 23:02 fiatjaf

Allowing wash-zaps poisons the concept.

For every one honest provider that uses actual zaps to build use case X on top, there can be limitless scammers who use wash-zaps to pump their zap tally and re-create a fake use case X on top, in order to attract actual zaps from unknowing users.

Both honest and dishonest providers use the same protocol, same name, same apps.

No user will be able to tell which are real and which are not, so anything built on top will be a Russian-roulette.

ok300 avatar Feb 22 '23 10:02 ok300

Actually this solution is not bad. Is it ready to merge?

fiatjaf avatar Feb 22 '23 15:02 fiatjaf

Zaps are lost if lud16/06 metadata change. Also, as you noted, zappers being blind means that they can burst out a lot of faked zap notes. Though they can always do that as it's not possible to enforce verification.

But yes, the solution appears to work.

hsjoberg avatar Feb 22 '23 15:02 hsjoberg

The solution proposed here still allows people to spam invalid zaps and puts all the burden on the client to verify every single one of them.

Are clients even verifying the zap provider public key currently?

yes, damus does. if it didn't then anyone could forge zaps. these types of attacks don't work on my node for example because it's non-custodial and single-user.

jb55 avatar Feb 22 '23 16:02 jb55

What if we specify that zap providers must query relays, find users' metadata events and check their lud06/lud16 properties before they issue zap events?

fiatjaf avatar Feb 22 '23 17:02 fiatjaf

What if we specify that zap providers must query relays, find users' metadata events and check their lud06/lud16 properties before they issue zap events?

My suggestion was to just include the receiving users kind0 event in the zap request, but maybe this was too much

v0l avatar Feb 22 '23 21:02 v0l

just include the receiving users kind0 event in the zap request

This is probably the best solution. It places no extra burden on the server nor on the clients.

Maybe do this in a separate parameter, outside of the zap request, i.e. ?nostr=<kind9734>&metadata=<kind0>. The provider checks that and discards it, no need to include it in the actual zap event.

fiatjaf avatar Feb 22 '23 23:02 fiatjaf

My suggestion was to just include the receiving users kind0 event in the zap request, but maybe this was too much

That is pretty neat.

no need to include it in the actual zap event.

I disagree. Clients could then also check that, it makes sure the validity of old zaps is preserved.

hsjoberg avatar Feb 23 '23 00:02 hsjoberg

Clients could then also check that, it makes sure the validity of old zaps is preserved.

If services are checking clients will just trust the validity of the zaps, no need to check anything. Clients are already trusting providers today, if we include the metadata that will just allow providers to not be fooled so we can trust them more.

fiatjaf avatar Feb 23 '23 00:02 fiatjaf