You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PHP(Laravel)后端如何验证Elrond签名并获取对应钱包地址

PHP(Laravel) 后端 Elrond 钱包签名验证实现方案

依赖安装

直接通过Composer安装验签所需的两个稳定依赖:

composer require tuupola/ed25519
composer require bitwasp/bech32

前后端传参约定

请求payload必须携带以下字段,避免验签逻辑歧义:

  • address:用户提交的Elrond钱包地址,固定为erd1开头格式
  • signature:钱包生成的签名,十六进制编码字符串
  • message:签名对应的原始明文,必须携带一次性随机nonce、过期时间等防重放字段,比如固定格式为Login to [你的dApp名称] nonce:xxx expire:xxx
  • nonce:后端提前下发的一次性随机校验串

注意:禁止使用无任何上下文的固定消息做签名,否则攻击者截获合法签名后可无限重放请求。

核心验签逻辑

直接在控制器中实现即可,核心逻辑包含参数校验、nonce有效性校验、公钥提取、消息补全、ED25519验签、地址二次比对6个环节:

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use Tuupola\Ed25519;
use BitWasp\Bech32\Bech32;

class WalletAuthController extends Controller
{
    const ELROND_SIGN_FIXED_PREFIX = "Elrond Signed Message:\n";
    const ELROND_ADDRESS_PREFIX = "erd";

    public function loginBySignature(Request $request)
    {
        // 基础参数格式校验
        $params = $request->validate([
            'address' => 'required|string|starts_with:erd1',
            'signature' => 'required|string|hex:size:128', // 64字节签名转十六进制固定128位
            'message' => 'required|string',
            'nonce' => 'required|string|size:16'
        ]);

        // 一次性nonce校验:提前在下发nonce时绑定客户端IP、设置2分钟过期,校验通过立刻删除
        if (cache()->pull("elrond_login_nonce:{$params['nonce']}") !== $request->ip()) {
            return response()->json(['error' => '非法请求,nonce已失效'], 403);
        }

        try {
            // 1. 从前端传入地址解码出公钥原始字节
            list($prefix, $groupedPubKey) = Bech32::decode($params['address']);
            if ($prefix !== self::ELROND_ADDRESS_PREFIX) {
                throw new \Exception("地址前缀非法");
            }
            // bech32解码结果为5位分组,转换为8位原始公钥字节
            $rawPubKey = Bech32::convertBits($groupedPubKey, 5, 8, false);
            if (strlen($rawPubKey) !== 32) { // ED25519公钥固定32字节
                throw new \Exception("公钥长度非法");
            }

            // 2. 构造Elrond钱包实际签名的完整消息:固定前缀+消息长度+原始消息
            // 所有官方Elrond钱包签名时都会自动拼接该前缀,漏加会导致验签100%失败
            $fullSignMessage = self::ELROND_SIGN_FIXED_PREFIX . strlen($params['message']) . $params['message'];

            // 3. 十六进制签名转原始二进制
            $rawSignature = hex2bin($params['signature']);
            if (strlen($rawSignature) !== 64) { // ED25519签名固定64字节
                throw new \Exception("签名长度非法");
            }

            // 4. ED25519签名校验
            $ed25519 = new Ed25519();
            if (!$ed25519->verify($fullSignMessage, $rawSignature, $rawPubKey)) {
                throw new \Exception("签名不匹配");
            }

            // 5. 用公钥重新生成钱包地址,和前端传入地址做二次比对,彻底防篡改
            $regeneratedGroupKey = Bech32::convertBits($rawPubKey, 8, 5);
            $realAddress = Bech32::encode(self::ELROND_ADDRESS_PREFIX, $regeneratedGroupKey);
            if ($realAddress !== $params['address']) {
                throw new \Exception("提交地址与签名公钥不匹配");
            }

            // 所有校验通过,$realAddress 就是真实合法的钱包地址,后续写自己的登录逻辑即可
            return response()->json([
                'code' => 0,
                'msg' => '登录成功',
                'wallet_address' => $realAddress
            ]);

        } catch (\Exception $e) {
            return response()->json(['error' => '校验失败:' . $e->getMessage()], 403);
        }
    }
}

高频踩坑点

  • 漏加Elrond固定签名前缀:官方钱包签名时会自动拼接Elrond Signed Message:\n+消息长度的前缀,直接拿前端传的原始消息验签必然失败
  • 未做nonce一次性校验:合法签名被截获后可被攻击者重复使用,必须给每个登录预请求生成唯一nonce,绑定客户端信息、设置短过期时间、用后即删
  • 跳过地址二次比对:若bech32解码逻辑存在兼容问题,可能出现公钥和传入地址不匹配的情况,必须用公钥重新生成地址做全等比对
  • 未做长度校验:非法长度的签名、公钥参数会触发底层依赖报错,提前做格式拦截可降低异常率

内容的提问来源于stack exchange,提问作者GPaul

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.27 17:36:19