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

Solidity中如何向智能合约函数传递经可信源验证的参数?

Solidity 验证链下传入参数可信来源的可行方案

Solidity 运行在链上沙盒环境,本身无法主动发起链下HTTP请求,也无法直接识别参数是从哪个服务端API获取的,要验证用户传入的claimDate确实来自你的可信后端,有三类成熟落地方案,可按安全需求选择:

  • 服务端签名+链上验签(通用场景首选,成本最低)
    实现逻辑非常直接:你的可信服务端持有一把独立保管的签名私钥,当接口返回claimDate给调用方时,同时返回私钥对(链ID, 合约地址, 用户id, claimDate, 防重放标识)的签名值。用户调用合约testFunction时,需要把id、claimDate、对应签名一同作为入参传入。合约内提前硬编码签名私钥对应的公钥地址,函数入口先做ECDSA签名校验,只有签名验证通过,才说明传入的claimDate是你的可信服务端签发的原始值,没有被调用方篡改。
    参考实现代码:
    contract TestSmartContract {
        // 提前写入可信服务端签名对应的公钥地址
        address public immutable TRUSTED_SIGNER;
    
        constructor(address _trustedSigner) {
            TRUSTED_SIGNER = _trustedSigner;
        }
    
        function testFunction(uint256 id, uint256 claimDate, bytes calldata signature) public payable returns (uint) {
            // 构造和服务端签名规则完全一致的消息哈希
            bytes32 msgHash = keccak256(abi.encodePacked(
                block.chainid,
                address(this),
                id,
                claimDate,
                msg.sender
            ));
            // 适配以太坊签名规则做验签
            bytes32 ethSignedHash = keccak256(abi.encodePacked(
                "\x19Ethereum Signed Message:\n32",
                msgHash
            ));
            (bytes32 r, bytes32 s, uint8 v) = splitSignature(signature);
            address recoveredSigner = ecrecover(ethSignedHash, v, r, s);
            require(recoveredSigner == TRUSTED_SIGNER, "claimDate source invalid");
    
            // 以下编写业务逻辑
            return 1;
        }
    
        // 签名拆分工具函数
        function splitSignature(bytes calldata sig) internal pure returns (bytes32 r, bytes32 s, uint8 v) {
            require(sig.length == 65, "invalid signature length");
            assembly {
                r := calldataload(sig.offset)
                s := calldataload(add(sig.offset, 32))
                v := byte(0, calldataload(add(sig.offset, 64)))
            }
        }
    }
    
    注意签名规则一定要加链ID、合约地址、调用者地址,避免攻击者把其他链、其他合约的有效签名拿过来做重放攻击。
  • 去中心化预言机写入(高安全场景可选)
    如果不想依赖用户传参,可以直接通过去中心化预言机网络,把后端生成的claimDate经过多节点共识后直接写入合约存储,业务函数直接读取合约内存储的、经预言机认证的参数值即可,完全不需要接收用户传入的claimDate。这个方案安全性更高,但接入复杂度和Gas成本也更高。
  • TLS原生证明(极端高安全需求可选)
    如果需要完全去掉对服务端私钥保管的信任,可以用TLS证明类方案,要求调用方提供从你的官方API获取claimDate时的TLS会话证明,合约验证证明是和你服务端域名建立合法TLS连接拿到的原始返回值,全程不需要服务端额外做签名逻辑,但技术复杂度极高,普通业务场景不需要用到。

不要踩一个常见误区:不要试图靠校验msg.sender做参数来源校验,用户完全可以在本地把从API拿到的claimDate改成任意值再签名发交易,链上只能看到发交易的地址,根本无法识别参数本身是不是从你API拿到的原始值。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 17:06:27