news 2026/10/23 7:58:37

Bisq 1.10.3 安全加固解析:过滤器信任边界、交易绑定与消息认证的全面收紧

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Bisq 1.10.3 安全加固解析:过滤器信任边界、交易绑定与消息认证的全面收紧
  • 区块链
  • DeFi
  • 金融科技

【免费下载链接】bisq

A decentralized bitcoin exchange network

项目地址:https://gitcode.com/gh_mirrors/bi/bisq
点击查看免费下载

导读

Bisq 1.10.3 是一个以安全加固为核心的发布版本,重点围绕过滤器(Filter)信任边界、交易状态机防护、存款/延迟赔付交易绑定以及支持与争议消息认证四条主线收紧安全策略。本文以 release-notes/1.10.3/notable-changes.md 为主体,结合仓库源码逐项还原每项变更的实现细节与影响面。读完本文,你将掌握:未签名过滤器字段为何被禁用、Core API 如何阻止失败交易被推进、存款与延迟赔付交易的绑定校验如何防止伪造交易注入,以及支持/争议消息如何校验发送者身份,并了解对应的回归测试覆盖。


一、版本概览与兼容性说明

1.10.3 全量提交范围从358b546526到292f438112,共 10 个提交(7 个普通提交、3 个合并提交,涉及 27 个文件)。官方完整记录见 release-notes/1.10.3/full-release-notes.md。

对用户与运营方(operator)而言,本版本的兼容性要点集中在以下几条:

  • 应用与打包版本号提升为1.10.3,最终 tagv1.10.3内含后续的安全加固提交(见 release-notes/1.10.3/notable-changes.md 的 Release Version 一节)。
  • 过滤器提供的 BTC 节点与种子节点字段被禁用(后续章节详述)。
  • Core API 拒绝为已失败交易确认"已开始支付"。
  • 存款交易与延迟赔付交易在处理前执行更严格的绑定校验。
  • 交易聊天、ACK、争议开启、对端开启争议与争议结果消息,在发送者签名公钥不匹配期望的交易对手或争议代理时被直接忽略。

由于这是一次安全加固发布,官方建议依赖过滤器、API 交易控制或争议消息处理路径的节点运营方及时升级。


二、未签名过滤器字段禁用:filterProvidedBtcNodes与filterProvidedSeedNodes

2.1 背景:过滤器签名覆盖范围

Bisq 的网络过滤器(Filter)由受信任开发者私钥签名后经 P2P 网络分发,客户端通过校验签名来决定是否应用。问题在于:Filter数据模型中addedBtcNodes与addedSeedNodes两个字段并未被当前过滤器签名所覆盖(参见 core/src/main/java/bisq/core/filter/Filter.java 中addedBtcNodes、addedSeedNodes字段定义及其序列化/反序列化逻辑)。这意味着攻击者一旦能伪造一份不带这些字段签名的过滤器载荷,理论上可诱导客户端把任意的 BTC 节点或种子节点当作"受信任"节点接入,从而发起中间人(MITM)等攻击。

2.2 实现变更

1.10.3 的处理策略是双管齐下:

  1. 不再持久化/应用:FilterManager收到来自网络的新过滤器时,不再将getAddedBtcNodes()/getAddedSeedNodes()写回配置文件(saveBannedNodes调用链见 core/src/main/java/bisq/core/filter/FilterManager.java)。同时节点选择逻辑中,这部分来源被置空。
  2. 启动时忽略历史残留:此前版本可能已把这两个值持久化到配置文件中,1.10.3 的Config解析层直接忽略filterProvidedBtcNodes/filterProvidedSeedNodes两个命令行选项的取值(选项定义见 common/src/main/java/bisq/common/config/Config.java),防止陈旧残留值在启动时被重新应用。

2.3 源码验证

在 core/src/main/java/bisq/core/btc/nodes/BtcNodesSetupPreferences.java 的selectPreferredNodes方法中,PROVIDED模式下构造候选 BTC 节点流时,filterProvidedBtcNodes来源仅在--ignoreNetworkFilter未开启时才被读取:

Stream<String> filterProvidedBtcNodes = config.ignoreNetworkFilter ? Stream.empty() : config.filterProvidedBtcNodes.stream();

最终由FederatedBtcNodeProvider.getNodes(...)将硬编码节点与过滤来源合并(见 core/src/main/java/bisq/core/btc/nodes/FederatedBtcNodeProvider.java)。种子节点侧同理,core/src/main/java/bisq/core/network/p2p/seed/DefaultSeedNodeRepository.java 只在非ignoreNetworkFilter时才把config.filterProvidedSeedNodes加入种子节点缓存。

回归测试 core/src/test/java/bisq/core/filter/FilterManagerInitializationTests.java 验证了启动时配置文件中残留的filterProvidedBtcNodes、filterProvidedSeedNodes会被清理,而无关的otherOption=keep得以保留。

2.4 对运营方的影响

  • 若你的配置文件或启动参数中显式设置了--filterProvidedBtcNodes/--filterProvidedSeedNodes,1.10.3 将忽略这些值——这是预期行为,并非配置错误。
  • 官方说明该处理是临时性的:在新的过滤器实现(覆盖这些字段签名)可用之前,一律按不安全处理,相关值作为空值写入/应用。

三、BTC 费用接收地址过滤器条目临时禁用

3.1 变更内容

过滤器字段btcFeeReceiverAddresses提供的地址被临时从 mempool 服务的 BTC 费用接收地址列表中排除。该路径当前并未被积极使用,预计将由新的过滤器实现接管。DAO 捐赠地址与 Burning Man(焚烧人)接收地址不受影响,继续留在列表中。

3.2 源码现状

Mempool 服务在构造全部 BTC 费用接收者列表时(见 core/src/main/java/bisq/core/provider/mempool/MempoolService.java 的getAllBtcFeeReceivers()),列表来源包括:

  1. daoFacade.getAllDonationAddresses()—— DAO 补偿请求等捐赠地址;
  2. Burning Man 地址列表的 legacy 地址;
  3. 过滤器提供的btcFeeReceiverAddresses(BtcFeeReceiverService.getConfiguredReceiverAddresses(...),见 core/src/main/java/bisq/core/dao/burningman/BtcFeeReceiverService.java);
  4. 历史上曾销毁 BSQ 的 Burning Man 候选人的所有地址。

也就是说,过滤器条目在代码路径上依然被读取解析(parseBtcFeeReceiverAddresses对非法配置会回退到仅 Burning Man 配置FeeReceiverConfig.forBurningManOnly()),但 1.10.3 官方说明强调其"临时排除",意图是等待新过滤器实现重新接管该路径。阅读此部分源码时,应以本版本发布说明为准理解该字段的实际生效状态。

3.3 相关测试

  • core/src/test/java/bisq/core/provider/mempool/MempoolServiceTest.java 覆盖费用接收地址列表构造行为;
  • core/src/test/java/bisq/core/dao/burningman/BtcFeeReceiverServiceTest.java 覆盖接收地址解析与合法校验。

四、失败交易 API 防护(Failed Trade API Guard)

4.1 问题场景

Core API 允许客户端(如bisq-cli)通过confirmPaymentStarted方法确认买家已开始支付,从而驱动交易沿买家协议路径前进。若交易已失败(failed),仍允许推进该状态机不仅违反协议语义,还可能导致资金路径异常。

4.2 实现

在 core/src/main/java/bisq/core/api/CoreTradesService.java 的confirmPaymentStarted(String tradeId, ...)方法中,首先检查是否按买家协议跟进(isFollowingBuyerProtocol),随后:

if (trade.hasFailed()) { throw new FailedPreconditionException("Cannot confirm payment started for a failed trade."); }

同时该方法还保留了两道前置约束:

  • 交易存款交易必须已确认(trade.isDepositConfirmed()),否则报错提示"需等 deposit tx 确认";
  • 合约与卖方支付账户载荷(sellerPaymentAccountPayload)必须已收到,否则报错提示"未收到卖方支付账户详情"——桌面客户端禁用确认按钮采用同一条件。

这样,即使 API 客户端误调或恶意调用,失败交易也无法再沿买家协议路径前进。


五、存款与延迟赔付交易绑定加固

这一节对应提交7e7e4ed905(Harden deposit transaction and delayed payout transaction binding),是 1.10.3 最核心的协议层加固之一。

5.1 买家侧校验:对方存款交易必须与本地一致

买家处理DepositTxAndDelayedPayoutTxMessage时(见 core/src/main/java/bisq/core/trade/protocol/bisq_v1/tasks/buyer/BuyerProcessDepositTxAndDelayedPayoutTxMessage.java),执行以下绑定检查后再触碰钱包或交易状态:

  1. 本地存款交易获取:作为 taker 时直接使用已设置的processModel.getDepositTx();作为BuyerAsMakerTrade时,因为 maker 尚未设置存款交易,使用processModel.getPreparedDepositTx()(预构建的存款交易)。
  2. 延迟赔付交易字节一致性:要求对方发来的 DPT 序列化字节与本地trade.getDelayedPayoutTxBytes()完全一致,否则checkArgument直接失败。
  3. 规范字段校验:对对方存款交易调用checkCanonicalDepositTxFields(见 core/src/main/java/bisq/core/trade/validation/DepositTxValidation.java)。
  4. DPT 输入绑定:调用DelayedPayoutTxValidation.checkDelayedPayoutTxInput(...)验证 DPT 的输入确实指向该存款交易。
  5. 本地比对:通过checkDepositTxMatchesIgnoringWitnessesAndScriptSigs忽略 witness 与 scriptSig 后比对对方存款交易与本地存款交易,防止收到一份序列化合法但绑定到不同交易的存款。

5.2 DPT 输入必须花费存款交易 output 0

core/src/main/java/bisq/core/trade/validation/DelayedPayoutTxValidation.java 的checkDelayedPayoutTxInput严格校验:

  • DPT 输入数量必须为 1;
  • 该输入的outpoint.getHash()必须等于存款交易的txId,且outpoint.getIndex() == 0;
  • 校验失败时抛出:"Input of delayed payout transaction does not point to output 0 of deposit tx"。

这防止了攻击者提交一份"序列化正确但绑定到另一笔存款交易"的 DPT。同一文件中的checkLegacyDelayedPayoutTxOutput还校验 DPT 输出数量为 1、金额等于买家保证金 + 卖家保证金 + 交易金额之和。

5.3 过期存款确认回调不再推进交易

1.10.3 将存款确认回调绑定到其注册时的交易 ID:如果一笔过期的回调(stale callback)在交易当前存款交易已变化后触发,该回调会被忽略,而不是把交易误标记为"存款已确认"。这一改动堵住了状态机在交易迁移期间被旧回调提前推进的窗口。

5.4 存款交易监听器:要求独立的 maker-fee 与 taker-fee 输入

旧实现只统计"输入父交易 ID 命中两个费用交易 ID 的数量"(count == 2),存在一个攻击面:恶意 seller-as-maker 可以用自己 maker 费用交易的不同输出(费用输出、reserved-for-trade 输出、找零输出)构造两笔输入,从而在计数检查中"伪造"一笔从未被 taker 共同注资的假存款交易。

加固后的isConfTxDepositTx(见 core/src/main/java/bisq/core/trade/protocol/bisq_v1/tasks/buyer/BuyerSetupDepositTxListener.java)改为:

  • 遍历输入,分别标记hasMakerFeeInput与hasTakerFeeInput;
  • 当takerFeeTxId已知(taker 角色)时,要求两个标志同时为 true——必须各有一个独立的 maker-fee 输入和一个独立的 taker-fee 输入;
  • 当takerFeeTxId为 null(buyer-as-maker 角色)时,仅要求 maker-fee 输入存在;
  • 同时校验存款地址depositTxAddress作为该交易的输出出现(而非仅作为输入),避免历史交易因多签地址复用被误判为当前存款交易。

六、支持与争议消息认证加固

对应提交292f438112(Harden support and dispute message sender authentication)。

6.1 基础机制:发送者签名公钥比对

SupportManager(core/src/main/java/bisq/core/support/SupportManager.java)是所有支持/争议消息处理的基类。核心校验方法isSenderSignaturePubKeyExpected(...)将解密后的发送者签名公钥与期望的PubKeyRing签名公钥逐字节比对,不匹配则记Ignoring ... because sender signature pubKey does not match the expected peer并返回 false。PubKeyRing为 null 时(本地交易记录缺失期望密钥)同样拒绝处理。

6.2 交易聊天与 ACK 消息

  • 交易聊天消息(onChatMessage)必须来自期望的交易对手:发送者签名公钥需匹配本地交易记录中对应角色的PubKeyRing。
  • ACK 消息(onAckMessage)同样比对发送者;若 ACK 所引用的源消息在本地找不到,则直接忽略,而不是从未经信任的消息数据中解析对端密钥,避免"凭不可信数据推断信任"。

6.3 争议开启:必须匹配合约声明的交易者

DisputeManager(core/src/main/java/bisq/core/support/dispute/DisputeManager.java)中的isDisputeOpenerSignaturePubKeyValid校验:

  • 从争议中取出合约(Contract),缺失则拒绝;
  • 依据dispute.isDisputeOpenerIsBuyer()取合约中的买家或卖家PubKeyRing作为期望开启者;
  • 发送者签名公钥必须匹配该期望开启者——即争议开启者必须与合约中声明的交易者一致,拒绝"冒名开启争议"。

6.4 对端开启的争议与争议结果:必须匹配本地期望的代理

isDisputeAgentSignaturePubKeyValid校验:

  • 本地必须存在对应交易的交易记录,否则拒绝(无法认证争议代理);
  • getExpectedAgentPubKeyRing(trade)得到的期望代理密钥必须与发送者签名公钥匹配;
  • 载荷中的代理密钥(dispute.getAgentPubKeyRing())必须等于交易记录的期望代理,防止攻击者在消息载荷里塞入自己声明的代理密钥。

这一校验同时适用于本地期望的调解代理(mediation)、退款代理(refund)与仲裁代理(arbitration);仲裁侧见 core/src/main/java/bisq/core/support/dispute/arbitration/ArbitrationManager.java,调解侧见 core/src/main/java/bisq/core/support/dispute/mediation/MediationManager.java。

6.5 关键原则:认证失败先于状态变更

所有无效或未认证的消息都在争议列表、聊天状态或持久化被修改之前被忽略。换言之,非法消息不会污染争议列表、不会进入聊天历史、也不会触发磁盘写入——这与"先认证、后变更"的安全顺序一致。


七、回归测试覆盖

1.10.3 为上述加固补齐了聚焦的回归测试,对应源码位置的测试文件包括:

测试主题对应源码相关测试
存款/DPT 绑定、DPT 输入校验BuyerProcessDepositTxAndDelayedPayoutTxMessage、DelayedPayoutTxValidationBuyerProcessDepositTxAndDelayedPayoutTxMessageTest.java、DelayedPayoutTxValidationTest.java
buyer-as-maker 存款处理BuyerSetupDepositTxListener覆盖于上述 buyer 测试族
过滤器/配置路径清理FilterManager、ConfigFilterManagerInitializationTests.java
费用接收地址列表MempoolService、BtcFeeReceiverServiceMempoolServiceTest.java、BtcFeeReceiverServiceTest.java

官方说明还提到新增了对支持 ACK 认证、争议开启者认证、争议代理认证、争议认证期间的失败交易查找、调解争议结果发送者认证的回归覆盖,以及过期存款确认回调与不匹配存款交易被拒绝的用例。


八、发布版本与升级建议

8.1 版本与提交

应用与打包版本号提升为1.10.3(提交7a441aa6fc,Bump version number forv1.10.3),最终 tagv1.10.3包含版本提升提交及后续的存款/DPT 绑定加固与争议消息认证加固提交。

8.2 发布门禁(Release Gate)

作为安全加固发布,官方建议在发布验证中包含以下聚焦测试路径:

  1. 过滤器/配置路径:确认filterProvidedBtcNodes、filterProvidedSeedNodes不再被持久化或应用,历史配置残留被忽略/清理;
  2. Core API 失败交易防护:确认confirmPaymentStarted对hasFailed()交易抛出FailedPreconditionException;
  3. 存款/DPT 绑定:确认对方存款交易、DPT 输入(output 0)、费用输入(独立 maker/taker fee 输入)、过期回调等路径的校验生效;
  4. 支持/争议消息认证:确认交易聊天、ACK、争议开启、对端开启争议、争议结果消息在发送者签名公钥不匹配时被忽略且不触发状态变更。

8.3 对运营方与开发者的实践建议

  • 节点运营方:升级后检查配置文件,若存在filterProvidedBtcNodes/filterProvidedSeedNodes项,可手动清理或交给 1.10.3 启动逻辑自动处理;依赖过滤器推送 BTC/种子节点的部署需等待新过滤器实现。
  • API 集成方:调用confirmPaymentStarted前需自行检查交易状态(isFailed),避免在失败交易上收到FailedPreconditionException并导致集成流程中断。
  • 阅读源码者:如需深入理解过滤器签名与字段覆盖问题,可结合 docs/filter-and-deny-list.md(过滤器与拒绝列表机制文档)与 core/src/main/java/bisq/core/filter/Filter.java(过滤器数据模型)交叉阅读;Burning Man 接收地址机制可参考 docs/burningman/filter-controlled-btc-fee-receiver-routing.md。

结语

1.10.3 没有引入新功能,却是一版对信任边界要求极高的安全修复:它把"未经签名覆盖的过滤器字段"挡在信任圈之外,用FailedPreconditionException阻断失败交易的异常推进,以"字节级一致 + 输入指向 output 0 + 独立费用输入 + 回调绑定交易 ID"四道防线锁定存款与延迟赔付交易的绑定关系,并在支持/争议消息处理的最前端完成发送者身份认证。对于依赖过滤器、API 交易控制或争议处理路径的部署,本版本值得优先升级;而其沉淀的回归测试,也为后续过滤器实现的替换(新签名方案)提供了可验证的基线。

  • 区块链
  • DeFi
  • 金融科技

【免费下载链接】bisq

A decentralized bitcoin exchange network

项目地址:https://gitcode.com/gh_mirrors/bi/bisq
点击查看免费下载

相关推荐

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/21 7:24:47

彩票源码系统解析:从PHP部署到开奖赔率与并发处理

简介&#xff1a;众神彩票源码是一套面向彩票行业运营者与开发者的完整彩票系统框架&#xff0c;基于2018年可用版本整理&#xff0c;覆盖前端交互、后端业务、数据库与支付对接等核心环节&#xff0c;可用于二次开发或业务改造。压缩包共7919个文件&#xff0c;大小约217.92MB…

作者头像 李华
网站建设 2026/10/19 11:54:45

Android SDK 26离线安装指南:从zip解压到环境变量配置

简介&#xff1a;这份压缩包提供Android SDK Tools 26.1.1完整更新&#xff0c;面向Android原生开发及Unity导出安卓项目的人员&#xff0c;解决25.2.5及以下版本的稳定性与兼容性问题&#xff1b;升级后可获得模拟器性能优化、新版API支持、Gradle插件兼容性增强及AndroidX工具…

作者头像 李华
网站建设 2026/10/23 13:16:12

Android后台拍照实现与避坑:从Camera2到前台服务与画中画

简介&#xff1a;针对Android平台在应用后台执行拍照的需求&#xff0c;这份资源面向移动端开发者和系统集成人员&#xff0c;覆盖服务&#xff08;Service&#xff09;、权限动态申请、Camera与Camera2 API调用、图片压缩存储、WakeLock防休眠及通知反馈等关键环节&#xff0c…

作者头像 李华
网站建设 2026/10/22 21:20:05

Python模拟登陆学信网查询四六级成绩,告别准考证号丢失

简介&#xff1a;这份Android示例项目实现了模拟登录学信网并查询四六级成绩&#xff0c;适合正在学习网络编程与数据解析的Android开发者。项目完整展示了从构造登录请求、携带Cookie维持会话&#xff0c;到解析返回HTML并提取成绩信息的全过程&#xff0c;涉及HttpURLConnect…

作者头像 李华
网站建设 2026/10/22 22:49:33

桌面宠物游戏开发全流程:从技术选型到发售的实战拆解

1. 一款桌面宠物游戏从立项到发售的全流程拆解《Pixel Kitten Desktop》这个名字第一次出现在我视野里的时候&#xff0c;我正蹲在一个独立游戏开发群里看人聊天。有人甩了张截图&#xff0c;一只像素风的小猫趴在任务栏上打哈欠&#xff0c;底下配文“正式发售”。说实话&…

作者头像 李华