Open darioAnongba opened 4 weeks ago
For reference, NIP-05 redirects because of this discussion https://github.com/nostr-protocol/nips/issues/127 and this PR https://github.com/nostr-protocol/nips/pull/128
Thanks for the reference, I see that the rationale leading to the decision is not very solid. It is somehow trying to prevent DDoS by forbidding redirects, but:
You can redirect with reverse proxy to an external server:
server {
listen 80;
server_name mydomain.com;
location = /.well-known/nostr.json {
proxy_pass https://mydifferentdomain.com;
proxy_set_header Host mydifferentdomain.com;
}
}
To prevent a high amount of requests to a server, you usually implement a caching mechanism, respected by most CDNs. The nostr.json
is not supposed to change often so just cache for some time. The requests won't even hit your server:
'Cache-Control', 's-maxage={seconds}, stale-while-revalidate={seconds}, stale-if-error={seconds}'
Allowing redirects to same subdomain should at least be allowed since I am not targeting domain that I do not control. But again, reverse proxy redirects break this argument.
It is not a security issue as there is no security involved in NIP-05. There is no risk of hacking, nor funds are risk and the data is public by definition.
It is a subjective matter. Some servers might actually like being pointed to and provide the NIP-05 service to others.
Notably, most wallets that implement Lightning Addresses—such as Wallet of Satoshi, Alby, Breez, Blink, Phoenix, and others—allow HTTP redirects, despite the protocol having arguably higher security risks due to its transactional nature.
Lightning Address initially didn't support redirects because redirects are dangerous and insane, but people started implementing redirect support and the protocol had to bend. Arguably UX was greatly favored there because Lightning Address URLs are inherently dynamic -- i.e. you had to have a server there on your /.well-known
path generating invoices, and that made things difficult for most people who were self-hosting their Lightning Address on their own personal domain, so it made sense for them to redirect to another place. NIP-05 has no such problem since it's super static and you just need a file or a very simple handler to return your pubkey.
What is your goal here? Why do you need redirects? Why can't you just return your desired response from a Next.js API handler? If you don't have the user information in there you can fetch it from the other place that has the information at runtime and return it in any way you want, you can probably even just do something in a single line, like return await fetch(...)
, effectively proxying the request but without requiring nginx or anything.
It is somehow trying to prevent DDoS by forbidding redirects, but: You can redirect with reverse proxy to an external server
Proxying a request is different than returning redirect responses. In the redirect case the target server will be hit by multiple HTTP requests from many different clients. In the proxy case all requests will be coming from your IP.
Hi @fiatjaf, happy to see you joining the conversation
Lightning Address initially didn't support redirects because redirects are dangerous and insane
This is subjective and not an argument for protocol specification as it doesn't explain why it would be dangerous or insane in the context of NIP-05.
Lightning Address URLs are inherently dynamic -- i.e. you had to have a server there on your /.well-known path generating invoices
The redirect of the .well-known for LN addresses is mainly for aesthetic reasons as the response of the well-known endpoint includes a callback
field that is the one pointing (maybe) to an outside domain for invoice generation. Thus, LN addresses are as static as NIP-05 and there is actually no redirection involved for invoice generation as that is performed on the second call. The data returned by the .well-known on LN addresses can be cached and reused.
NIP-05 has no such problem since it's super static and you just need a file or a very simple handler to return your pubkey.
I would argue that the vast majority of Nostr users use a service for NIP-05, among my contacts, I see countless nostrplebs
, primal.net
, getalby.com
, etc. Only few own a domain name that they use to return a static nostr.json
file for their own identifier.
What is your goal here? Why do you need redirects? Why can't you just return your desired response from a Next.js API handler?
My goal is to redirect the calls from mydomain.com/.well-known/nostr.json
to api.mydomain.com/...
. "Redirection" is the correct term. What you are suggesting is intercepting the request, fetching the data and returning it with or without alteration. This is what I implemented as a workaround but it's not a redirection and it's now part of the source code of the NextJS app. Whether it is possible to implement this workaround with a handler in my specific case for NextJS is not part of this conversation.
Proxying a request is different than returning redirect responses. In the redirect case the target server will be hit by multiple HTTP requests from many different clients. In the proxy case all requests will be coming from your IP.
The specification defines how the server behaves when receiving a request and how the client does when sending one. The specification is agnostic to the number of requests or the number of different clients the server allows. You could add a recommendation like "Servers SHOULD return a Cache-Control
header ...`.
My point is that, similarly to firewalls, it's good to start by closing the doors and slowly open them if there is a clear use case or advantage. Like to LN Addresses, nothing inherent with redirects increases the attack surface and allowing them increases UX and ease of development.
It looks like you don't really have a justification for this change since you are already doing what the NIP specifies and proxying requests in your server (with no harm to yourself or anyone) and you have cited no other use cases that would need the client-side redirects.
I think I gave some justifications:
What I want to do by simply setting a redirect in the config of NextJS, outside of the src
:
redirects: async () => {
return [
{
source: '/.well-known/nostr.json',
destination: 'https://api.numeraire.tech/.well-known/nostr.json',
permanent: true,
},
];
},
What I have to do (implement a manual interceptor that could very well not behave as expected in the api
directory) and an additional rewrite policy in config:
import type { NextApiRequest, NextApiResponse } from 'next';
export default async (req: NextApiRequest, res: NextApiResponse) => {
const { method, query } = req;
const backendUrl = new URL('https://api.numeraire.tech/.well-known/nostr.json');
for (const key in query) {
const value = query[key];
if (Array.isArray(value)) {
value.forEach(val => {
backendUrl.searchParams.append(key, val);
});
} else if (typeof value === 'string') {
backendUrl.searchParams.append(key, value);
}
}
try {
const response = await fetch(backendUrl.toString(), {
method,
headers: {
'Content-Type': 'application/json',
},
});
const data = await response.json();
res.setHeader('Cache-Control', 's-maxage=60, stale-while-revalidate=30, stale-if-error=600');
res.status(response.status).json(data);
} catch (error) {
console.error('Error fetching from backend:', error);
res.status(500).json({ error: 'Internal server error' });
}
}
and
rewrites: async () => {
return [
{
source: '/.well-known/nostr.json',
destination: '/api/nostr',
},
];
},
The handler is a manual implementation that differs in each framework.
Given that you personally don't like redirects, maybe @dennisreimann from BTCPayServer having written the tutorial about redirects for LN addresses will have some insights.
Sorry, but points 1, 2 and 3 are not justifications for adding a new breaking change to the protocol, they are just arguments about why past decisions might have not been based on the most solid arguments. We can argue that all day, but even if we conclude you are right these things will not justify making a change now. To justify making a change we would need an actual positive justification, like a real world valuable use case that isn't possible today.
Point 4 is just telling me that it took you extra code to implement the handler in Next.js? That is already built already though, and changing it now would be extra work for you. Also, if it's just a static set of pubkeys that you have there wouldn't it make more sense to serve them directly from the Next.js app?
I would argue that the vast majority of Nostr users use a service for NIP-05, among my contacts, I see countless
nostrplebs
,primal.net
,getalby.com
, etc. Only few own a domain name that they use to return a staticnostr.json
file for their own identifier.
I don't get this point. Why do these users have care about your suggested change?
If you allow redirects now, most clients will not follow them so they will be useless. This ship has already sailed.
It is not a breaking change to the protocol. In the same way as you should not forbid redirections (a specific aspect of the HTTP protocol) on the Nostr protocol, you should not enforce redirections neither. Clients should be free to follow redirects if they want to. Removing the section about "security constraints" (that has nothing to do with security) will not break consensus.
The use case is clear. I want to specify that a specific queried resource is permanently (301) or temporarily (302) available at a different location. Here a subdomain. That is what HTTP redirects are for and Nostr has no business in that context.
We are not serving a static file. We are building the Numeraire SwissKnife, a lightning wallet similar to Alby Hub allowing creating LN and Nostr addresses, we propose it as a service through a dashboard. You can see the docs at docs.numeraire.tech and reach the API at api.numeraire.tech. the nextJS website at the root domain (numeraire.tech) should not be aware of Nostr.
We are talking about protocol design here. Whether or not clients have already blocked redirections by following the NIP is irrelevant to the NIP itself, it will simply become an opinionated choice for clients.
In definitive, I'm just trying to point out a flaw in the NIP design, if you don't want to change it because you don't like redirects, do as you please.
Hi @fiatjaf,
The NIP-05 specification contains the following security constraint:
I would like to discuss why this constraint may not be appropriate in the context of NIP-05 and propose allowing redirections. Additionally, I will explain how preventing redirections diminishes the ease of implementation.
The problem
NIP-05 prohibits HTTP redirections by specifying that clients must not follow 301/302 redirects from the
/.well-known/nostr.json
endpoint, citing security concerns.The security rationale
The NIP does not explain the specific security risks associated with allowing redirects. Generally, preventing clients from following redirects is intended to mitigate risks such as users being redirected to unexpected or unsafe locations if a domain is compromised.
However, in the context of NIP-05, clients trust the domain owner to provide the mapping from the Nostr identifier to the public key. The goal of NIP-05 is to facilitate this lookup, not to verify the authenticity of the information provided. Therefore, if a domain is compromised, disallowing redirects does not enhance security, as the trust has already been broken. A malicious domain could provide incorrect mappings regardless, and since there is no central authority to verify the information, the client’s trust in the domain is fundamental.
Reverse proxy VS HTTP redirection
In the context of NIP-05, HTTP redirects are functionally equivalent to reverse proxy configurations. The primary difference is that with reverse proxies, the user is unaware of the redirection and remains on the same domain, whereas with HTTP redirects, the client is informed to fetch the resource from a different location. Disallowing HTTP redirects while permitting reverse proxies seems unjustified, as both achieve the same result.
A reverse proxy configuration might look like this, effectively allowing redirects for Nostr addresses:
However, many modern deployment platforms like Vercel or DigitalOcean App Platform do not allow configuring reverse proxies directly. Developers using these platforms find it easier to implement an HTTP redirect, such as in Next.js:
Preventing HTTP redirects forces developers to implement workarounds to intercept and forward the request to the backend, which is essentially the purpose of HTTP redirects.
Comparing with Lightning Address
Notably, most wallets that implement Lightning Addresses—such as Wallet of Satoshi, Alby, Breez, Blink, Phoenix, and others—allow HTTP redirects, despite the protocol having arguably higher security risks due to its transactional nature.
In practice, Lightning Address servers are often deployed on subdomains different from the root domain. For example, BTCPayServer instances are frequently hosted at
pay.mydomain.com
, and companies like Numeraire or Alby expose their APIs atapi.numeraire.tech
orapi.getalby.com
. There's even a tutorial in the BTCPayServer documentation recommending developers implement a redirect for LN Addresses here.Proposed Change
NIP-05 should permit HTTP redirects, especially redirects to subdomains. Allowing HTTP redirects would simplify implementation for developers using platforms that do not provide access to reverse proxy configurations. Permitting redirects in this context would not increase the attack surface for NIP-05, as clients already trust the domain to provide accurate mappings.