I will refer to this post How to verify MetaMask account holder is the real owner of the address? .
So what devs are suggesting is to create a nonce on server side, get it via public API, sign wallet address with it and return to server for validation. And its assumed to be secure authentication.
Lets demystify this starting with:
The frontend should do a GET request to retrieve the current nonce for the public address that is trying to sign in. If the account doesn't exist yet then create it and return the nonce anyway.
What it means is that there is a public API that takes walletAdress
as parameter and creates a entry in database (not questions asked). This is like leaving a huge backdoor for hackers to bring down your database. Nothing is preventing them to create fake but valid wallet addresses and bombard the server creating millions of fake records until it dies off.
Secondly lets take a a look at this code for signature validation:
nonce = "\x19Ethereum Signed Message:\n" + nonce.length + nonce
nonce = util.keccak(Buffer.from(nonce, "utf-8"))
const { v, r, s } = util.fromRpcSig(signature)
const pubKey = util.ecrecover(util.toBuffer(nonce), v, r, s)
const addrBuf = util.pubToAddress(pubKey)
const addr = util.bufferToHex(addrBuf)
This works completely offline. So who is the stopping the hacker to reverse engineer it? Create a function that takes nonce and some other user wallet address and create a signature? The crypt code is public. And the nonce retrieval is public.
What I tried so far is to replace the database part with user cookie short lived session and a redirect to retrieve the nonce. It would prevent spamming the database, as well generate a private nonce for every nonce request.
Still the whole flow doesn't make sense in terms of security. Any fresh ideas on this?