nips icon indicating copy to clipboard operation
nips copied to clipboard

NIP-55: Proxied NIP-05 Authetication

Open benthecarman opened this issue 2 years ago • 20 comments

Nostr has various privacy issues, this is an attempt to be able to solve one of the IP leaks

Made an implementation in rust-nostr: https://github.com/rust-nostr/nostr/pull/58

benthecarman avatar Feb 28 '23 01:02 benthecarman

Yes IP leaking via nip5 is a problem. Tasking a relay to proxy these requests is an intriguing idea.

Pushing these lookups onto the relay seems like a bad deal for the relay operator though. Do you have any thoughts on this?

cmdruid avatar Feb 28 '23 04:02 cmdruid

Pushing these lookups onto the relay seems like a bad deal for the relay operator though. Do you have any thoughts on this?

Yes, in the Expected Behavior section I mention that the relay should do some caching to prevent this

benthecarman avatar Feb 28 '23 04:02 benthecarman

This would put relays in an extremely powerful position similar to DNS, especially when it comes to NIP-05 lookups...

Egge21M avatar Feb 28 '23 07:02 Egge21M

This would put relays in an extremely powerful position similar to DNS, especially when it comes to NIP-05 lookups...

Relays already have all the power when it comes to anything with nostr.

benthecarman avatar Feb 28 '23 07:02 benthecarman

Relays already have all the power when it comes to anything with nostr.

No they don't, especially not when it comes to identity management. Today NIP-05 can be used to lookup someone's private key by remembering their human readable NIP-05 domain and username. You can find my public key on [email protected]...

If you use relays as proxies, they could give back any public key as a result, even if the NIP-05 domain is controlled by you. And the only way for a user to verify the received pubkey is to check the NIP-05 themselves, reintroducing leaks...

Egge21M avatar Feb 28 '23 07:02 Egge21M

You can always just do it yourself, this is completely optional and just a way to help people preserve privacy if they trust relays

benthecarman avatar Feb 28 '23 07:02 benthecarman

You can always just do it yourself, this is completely optional and just a way to help people preserve privacy if they trust relays

If this NIP intends to introduce opt-in privacy that comes at a price of a massive amount of trust (while images and other media still leak the same metadata anyways), then I see absolutely no point in it.

Egge21M avatar Feb 28 '23 08:02 Egge21M

If this NIP intends to introduce opt-in privacy that comes at a price of a massive amount of trust (while images and other media still leak the same metadata anyways), then I see absolutely no point in it.

Other media will be added later.

benthecarman avatar Feb 28 '23 08:02 benthecarman

Some relays already verify the NIP-05 of users. I believe nostr-rs-relay does that. I think this NIP could be replaced with a simpler scheme in which any opt-in relay that does that kind of verification could choose to do it asynchronously at their own time (maybe in a background routine, or whenever they get a new kind:0 event) and append the result to users' kind:0 events when returning them to users:

{
  "id": "...",
  "kind": 0,
  "pubkey": "...",
  "tags": [],
  "content": "{\"name\": \"bob\", \"nip05\": \"[email protected]\"}",
  "sig": "...",
  "nip55": true
}

Then clients could choose to trust that field or not.

fiatjaf avatar Feb 28 '23 11:02 fiatjaf

@fiatjaf I like the idea, but does has some downsides that this otherwise provides

  • Does not allow to lookup by NIP-05 through a relay, this would only allow for verification. If i want to get [email protected]'s pubkey, I will have to make the request myself
  • You don't not get the relays list that the NIP-05 could be providing
  • Invalidating old verification is a little complicated. I guess the best solution would just to be if a new pubkey registered that NIP-05 you have to make the request and if valid, would invalidate the previous key.

I feel this proposal is more inline with the smart-client dumb-relay architecture that nostr tends to have

benthecarman avatar Feb 28 '23 12:02 benthecarman

You make good points, except the last one. I don't favor that architecture. I think smart relays is a good thing and pretty much a necessity for scalability.

In this case, why has the "PROXY" command have to be limited to NIP-05 URLs? Why not make it open to proxying anything? In practice one could host anything at their NIP-05 URL, so this is already allowed.

fiatjaf avatar Feb 28 '23 15:02 fiatjaf

Yeah my intention was to add other types for the second parameter, I guess we could remove that and just have the user send the actual url instead of the user@domain

benthecarman avatar Feb 28 '23 15:02 benthecarman

From the nostr README (emphasis mine):

A relay is very simple and dumb. It does nothing besides accepting posts from some people and forwarding to others. Relays don't have to be trusted. Signatures are verified on the client side.

I do not think it should be the task of relays to do any kind of network proxying or parsing anything other than nostr events and client-to-relay messages. And relays should not have to be trusted with verification.

For web clients, there is some server serving the web client code. Being trusted with hosting this code, it could also be trusted with NIP-05 verification. This would be some custom calls between the client and the host, just like some web apps today use image proxies. No relay involved and no need for a NIP.

If there should be any kind of proxying specified by any NIP, it should be something that retains end-to-end security. Meaning, for NIP-05 and other TLS connections, the full TLS session has to be passed through the proxy.

And if you really want proxying in nostr, I think the proxy should be another client, not a relay. So the architecture would be: Client <-(ephemeral events)-> Relay <-(ephemeral events)-> Proxy <-(TCP)-> Network Server

This has the added benefit of client anonymity as well as being purely a client-to-client standard, any relay can be used, no extra relay complexity needed. It could start off with a single client implementation where the client devs also run a compatible proxy.

shafemtol avatar Feb 28 '23 18:02 shafemtol

I think this NIP could be replaced with a simpler scheme in which any opt-in relay that does that kind of verification could choose to do it asynchronously at their own time (maybe in a background routine, or whenever they get a new kind:0 event) and append the result to users' kind:0 events when returning them to users.

Is this honestly a good practice, though? Relays are introducing new keys to a signed event. Profile events have already morphed into an ambiguous specification. How is a naive client supposed to know which keys are signed and which aren't?

cmdruid avatar Mar 01 '23 08:03 cmdruid

No they don't, especially not when it comes to identity management. Today NIP-05 can be used to lookup someone's private key by remembering their human readable NIP-05 domain and username. You can find my public key on [email protected]...

In fairness, nip05 is not meant to be used as a lookup service (but I agree that is where this train is headed).

cmdruid avatar Mar 01 '23 09:03 cmdruid

In fairness, nip05 is not meant to be used as a lookup service (but I agree that is where this train is headed).

Of course it is. User-Lookup is even one of the possible usecases outlined by the NIP itself.

Egge21M avatar Mar 01 '23 09:03 Egge21M

Yeah my intention was to add other types for the second parameter, I guess we could remove that and just have the user send the actual url instead of the user@domain

This would allow relays to moderate urls on behalf of a client. That sounds really useful actually. It could be an elegant way for relays to offer content moderation (in addition to privacy).

cmdruid avatar Mar 01 '23 09:03 cmdruid

Of course it is. User-Lookup is even one of the possible usecases outlined by the NIP itself.

Yes but that scenario is then contradicted by the rule: "Clients must always follow public keys, not NIP-05 addresses." which means an unsolicited domain lookup is inherently untrustworthy.

cmdruid avatar Mar 01 '23 09:03 cmdruid

Yes but that scenario is then contradicted by the rule: "Clients must always follow public keys, not NIP-05 addresses." which means an unsolicited domain lookup is inherently untrustworthy.

You are mixing up things here. The flow is:

  1. client looks up my public key using my nip-05
  2. clients extracts the public key and adds it to its following-list

This is how nip-05 can be used to find users, while sticking to the "only follow pubkeys" rule.

But this discussion is off-topic for this PR I guess.

Egge21M avatar Mar 01 '23 10:03 Egge21M

But this discussion is off-topic for this PR I guess.

You are right. In this proxy scenario the pubkeys are used to initiate the lookup anyway.

cmdruid avatar Mar 01 '23 20:03 cmdruid

I don't like the idea of creating a new command that returns non-event json and expects the relay to be an open proxy. What if a client floods the relay with PROXY requests?

My relay stores the NIP-05 verification status as an event, which can be queried. It already periodically rechecks verification status and refreshes the event. For instance, here's what mine looks like:

{
    "id": "a27811e365e484d5ef378d66ead0fbe3296e70f7dc933592d8e894d7bc321d17",
    "pubkey": "e023394c864594c1ffe81219227d27f5deadca2f193a42a383ba2a9219abbb8b",
    "created_at": 1677875643,
    "kind": 31494,
    "tags": [
        [
            "t",
            "verification"
        ],
        [
            "d",
            "verify:c7da62153485ecfb1b65792c79ce3fe6fce6ed7d8ef536cb121d7a0c732e92df"
        ],
        [
            "n",
            "[email protected]"
        ],
        [
            "expiration",
            "1680294843"
        ]
    ],
    "content": "[email protected]",
    "sig": "d559a853a766973d3507073ea13853620f9d26f36c4430094517c1980920fa82397598d46c7e32e3dfc9145d7ee65daf3ca081be8398d8e566541b33711cc815"
}

This is used to simplify the implementation, but there's no reason why a client couldn't query for {"kinds": [31494], "#n": ["[email protected]"]}, if they wanted to avoid hitting "bar.com" directly.

davestgermain avatar Mar 03 '23 20:03 davestgermain