본문 바로가기
Blockchain/Ethereum

[Ethereum] - metamask 메시지 서명과 검증

by 기저귀찬개발자 2021. 1. 7.

메타마스크를 활용하면 특정 메시지에 서명한 값을 가지고 서버에서 메시지를 검증하여 사용자가 맞는지 확인하여 로그인, 사용자 검증 등에 사용할 수 있다.

 

아래는 메타마스크의 인스톨 여부와 권한을 요청하는 구문이다.

<script>
	window.addEventListener('load',async function() {
      if (window.ethereum) {
        try {
          // Request account access if needed
          await ethereum.enable();
        } catch (error) {
          console.log(error)
          // User denied account access...
        }
      }
      // Legacy dapp browsers...
      else if (window.web3) {
          window.web3 = new Web3(web3.currentProvider);
          // Acccounts always exposed
          web3.eth.sendTransaction({/* ... */});
      }
      // Non-dapp browsers...
      else {
          console.log('Non-Ethereum browser detected. You should consider trying MetaMask!');
      }
    });
</script>

 

아래와 같이 2단계에 걸쳐 연결을 설정한다.

 

서명 inject된 metamask web3를 가지고 서명 요청을 보내는 기본적인 스크립트이다.

method의 경우 personal_sign 말고도 구조화된 메시지를 보내는 여러 함수들이 있다.

(* 참고 docs.metamask.io/guide/signing-data.html)

<script>
  function sign(){
	var from = ethereum.selectedAddress;
      var params = ['test',from];
      var method = 'personal_sign';

      web3.currentProvider.sendAsync(
      {
        method,
        params,
        from,
      },
      function (err, result) {
        
        $.get( 'http://localhost:3000/sign/'+JSON.stringify(result.result) );

      });
   }
</script>

 

 

 

서명을 하게 되면 아래와 같은 결과 값을 받게 되는데 result에 해당 하는 값이 서명된 메시지이다.

 

sign 함수를 보면 nodejs로 구성된 localhost 서버로 보내게 된다. 

아래의 코드에서 최종적으로 나타나는 toAddress가 사용자 주소가 되고 다른 인자로 클라이언트의 주소를 받아와서 비교하여 실제 사용자가 맞는지 확인해보면 된다.

exports.sign = async function (req, res, next) {
  try {
    var hash = req.params.hash;

    const msgBuffer = ethjs.toBuffer(msg);

    const msgHash = ethjs.hashPersonalMessage(msgBuffer);

    hash = hash.replace(/['"]+/g, '');

    const signatureBuffer = ethjs.toBuffer(hash);

    const signatureParams = ethjs.fromRpcSig(signatureBuffer);

    const publicKey = ethjs.ecrecover(

      msgHash,

      signatureParams.v,

      signatureParams.r,

      signatureParams.s

    );

    const addressBuffer = ethjs.publicToAddress(publicKey);

    const address = ethjs.bufferToHex(addressBuffer);
    const toAddress = getContractByCate(cate);

    return res.status(200).json({ toAddress });
  } catch (e) {
    console.log('err',e)
    return next(e);
  }
}

댓글