智能合约里的 “拒绝服务“ 攻击:让你的合约变成 “死机的手机“

你有没有遇到过手机突然卡死,点什么都没反应的情况?在区块链世界里,智能合约也可能遭遇类似的 "罢工"—— 这就是 "拒绝服务攻击"(Denial of Service,简称 DoS)。今天用大白话讲讲合约里的 DoS 攻击是怎么回事,以及如何防范。

先理解:什么是拒绝服务攻击?

简单说,拒绝服务攻击就是通过各种手段,让合约的核心功能彻底失效,谁都用不了

就像:

  • 你经营一家自助餐厅,有人故意把所有座位占满却不消费,真正的顾客进不来
  • 你开了个快递柜,有人把所有格子都塞一些废纸条,导致正常包裹放不下

在合约里,DoS 攻击会让转账、提款、投票等关键功能彻底卡住,严重的甚至会让合约里的资产永远取不出来。

合约里最常见的 3 种 DoS 攻击手法

1. 利用 "必须成功的批量操作"—— 最容易踩的坑

很多合约会设计批量操作功能(比如批量发工资、批量退款),如果代码里用了for循环一次性处理所有用户,就可能被攻击。

漏洞合约示例(批量退款):
contract BatchRefund {address[] public refundees; // 退款名单mapping(address => uint) public amounts; // 每个人该退的钱// 管理员添加退款名单function addRefundee(address who, uint amount) public {refundees.push(who);amounts[who] = amount;}// 批量退款(有漏洞!)function refundAll() public {// 循环给每个人退款for (uint i = 0; i < refundees.length; i++) {address payable who = payable(refundees[i]);// 只要有一次转账失败,整个函数就会卡住(bool success, ) = who.call{value: amounts[who]}("");require(success, "给某个人退款失败了");}}
}
攻击方式:

黑客只需要用一个 "有问题的地址"(比如一个没有receive函数的合约地址)加入退款名单。当refundAll()执行到这个地址时,转账会失败,require会触发revert,整个批量退款就会卡住。

结果就是:所有人都拿不到退款,功能彻底报废

2. 用 "gas 炸弹" 耗尽资源 —— 让交易永远失败

以太坊的每笔交易都有 gas 限制(相当于 "燃料上限"),如果合约里有需要大量计算的功能,黑客可以故意触发这些功能,让 gas 消耗超过上限,导致交易失败。

漏洞合约示例(投票系统):
contract BadVoting {mapping(address => uint) public votes; // 每个人的票数address[] public voters; // 投票人名单// 投票function vote() public {votes[msg.sender]++;voters.push(msg.sender); // 每次投票都记录地址}// 计算总票数(有漏洞!)function countTotalVotes() public view returns (uint) {uint total = 0;// 遍历所有投票人计算总数for (uint i = 0; i < voters.length; i++) {total += votes[voters[i]];}return total;}
}
攻击方式:

黑客可以用大量不同的地址反复调用vote(),让voters数组变得非常长(比如 10 万个地址)。当有人想调用countTotalVotes()时,遍历 10 万个地址需要的 gas 会远远超过区块上限,导致这个函数永远无法执行。

结果就是:投票系统的计票功能彻底瘫痪

3. 控制关键权限 —— 让合约变成 "死账户"

如果合约的核心功能(比如提款、升级)依赖某个单一地址(比如管理员),而这个地址因为私钥丢失、被黑等原因失控,就会导致合约 "永久停机"。这也算一种特殊的 DoS。

漏洞场景:
contract AdminControl {address public admin; // 管理员地址mapping(address => uint) public balances;constructor() {admin = msg.sender; // 部署者成为管理员}// 提款必须由管理员触发function withdraw(address to, uint amount) public {require(msg.sender == admin, "不是管理员");(bool success, ) = payable(to).call{value: amount}("");require(success);}
}
攻击 / 风险方式:

如果管理员的私钥丢了,或者管理员地址是个合约且该合约功能已失效,那么withdraw()函数就永远没人能调用,合约里的资产就成了 "死钱"。

这种情况在实际中很常见,每年都有大量加密资产因为 "管理员私钥丢失" 而永久冻结。

如何防范拒绝服务攻击?

针对不同的 DoS 攻击,有不同的防御方案,但核心原则是:避免单点依赖,控制操作复杂度

1. 解决批量操作问题:化整为零

把一次性的批量操作,拆分成多次小批量操作,即使某一次失败,也不影响整体。

修复批量退款合约:

contract SafeBatchRefund {address[] public refundees;mapping(address => uint) public amounts;uint public nextIndex; // 记录下次开始退款的位置function refundBatch(uint batchSize) public {uint end = nextIndex + batchSize;// 防止数组越界if (end > refundees.length) end = refundees.length;// 本次只退batchSize个人for (uint i = nextIndex; i < end; i++) {address payable who = payable(refundees[i]);(bool success, ) = who.call{value: amounts[who]}("");if (success) {nextIndex++; // 只有成功了才更新索引} else {// 失败了就跳过,下次再试break;}}}
}

这样即使某个人退款失败,也能继续给其他人退款,不会全军覆没。

2. 解决 gas 炸弹:限制计算复杂度

  • 避免在合约里写需要遍历超长数组的函数
  • 提前计算并限制单次操作的复杂度
  • 重要功能尽量设计成 "常量级" 或 "线性级" 复杂度

修复投票系统:

contract GoodVoting {mapping(address => uint) public votes;uint public totalVotes; // 直接记录总票数,不用每次计算function vote() public {votes[msg.sender]++;totalVotes++; // 投票时直接更新总数}// 直接返回已记录的总数,无需遍历function countTotalVotes() public view returns (uint) {return totalVotes;}
}

3. 解决权限问题:去中心化治理

  • 避免单一管理员,改用多签钱包(需要多个管理员同意才能操作)
  • 关键功能设计成 "时间锁"(操作需要等待一段时间才能执行,给社区反应时间)
  • 重要合约可以引入 DAO 治理,让社区共同决定关键操作

示例(多签简化版):

contract MultiSig {address[] public admins; // 多个管理员uint public required; // 需要多少个管理员同意constructor(address[] memory _admins, uint _required) {admins = _admins;required = _required;}// 提款需要足够多管理员同意function withdraw(address to, uint amount) public {// 检查是否有足够多管理员授权(实际实现更复杂)require(isApprovedByEnoughAdmins(), "同意人数不足");// ... 执行提款 ...}
}

总结:拒绝服务攻击的本质是 "卡住关键流程"

DoS 攻击不像重入攻击那样直接偷钱,但它能让你的合约彻底失效,造成的损失可能更大(比如无法提款的资金池)。

防范的核心思路是:

  • 别把所有鸡蛋放在一个篮子里(避免单点依赖)
  • 复杂操作要拆分(避免一次性处理太多任务)
  • 给系统留 "后路"(失败了能重试,权限丢了有备选)

写合约时多问自己:"如果这个功能卡住了,有没有备用方案?" 能帮你避开大多数 DoS 陷阱。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/diannao/96128.shtml
繁体地址,请注明出处:http://hk.pswp.cn/diannao/96128.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

安全设计-防止非法移机

前言我们的设备在实际使用过程中&#xff0c;在我们的巡查机制粒度下&#xff0c;发现依然有设备被非法移动到其他非计划点位。因此&#xff0c;我们需要设计一套及时预警&#xff0c;但是对客户无感&#xff0c;不影响业务办理的防范机制。1.方案设计交互图2.方案说明 2.1方案…

OpenHarmony之三方库适配深度实践:从移植到合规的全链路指南

1. 为什么要做三方库适配?——更深层的价值分析 维度 现状痛点 预期收益 深度价值 生态 成熟开源库无法直接运行 复用 10+ 年开源沉淀,提升功能覆盖率 避免生态碎片化:通过标准化适配流程,确保不同厂商对同一库的实现一致 性能 JS 层重实现耗 CPU 原生 C/C++ 加速 3~10 倍 …

2025年09月计算机二级MySQL选择题每日一练——第一期

计算机二级中选择题是非常重要的&#xff0c;所以开始写一个每日一题的专栏。 答案及解析将在末尾公布&#xff01; 今日主题&#xff1a;MySQL 基础概念 1、以下关于数据库的特点中&#xff0c;描述正确的是&#xff08; &#xff09; A. 数据无冗余 B. 数据不可共享&#xff…

JAVA字符串操作——在蓝桥杯的基本应用

我们来系统地梳理一下 Java 中的字符串操作。Java 的字符串操作非常丰富&#xff0c;主要涉及到 String、StringBuilder 和 StringBuffer 这三个核心类。 目录 一、核心类简介 二、String 类的常用操作 1. 创建字符串 2. 获取基本信息 3. 比较字符串 4. 查找与判断 5. 转…

【深度学习基础】PyTorch Tensor生成方式及复制方法详解

目录PyTorch Tensor生成方式及复制方法详解一、Tensor的生成方式&#xff08;一&#xff09;从Python列表/元组创建&#xff08;二&#xff09;从NumPy数组创建&#xff08;三&#xff09;特殊初始化方法&#xff08;四&#xff09;从现有Tensor创建&#xff08;五&#xff09;…

动态规划:入门思考篇

1. 简单类比 假如我们要求全国人数&#xff0c;那么我们只要知道各个省的人数&#xff0c;然后将各个省的人数相加即可&#xff0c;要想知道各个省的人数&#xff0c;只要将这个省下面所有的市人数相加即可&#xff0c;同样&#xff0c;如果想要知道各个市的人数&#xff0c;只…

小杨的 X 字矩阵(举一反三)-洛谷B3865 [GESP202309 二级]

题目描述 小杨想要构造一个 X 字矩阵&#xff08; 为奇数&#xff09;&#xff0c;这个矩阵的两条对角线都是半角加号 &#xff0c;其余都是半角减号 - 。例如&#xff0c;一个 55 的 X 字矩阵如下&#xff1a; --- --- ---- --- --- 请你帮小杨根据给定的 打印出对应的“X …

数据组合与合并:Pandas 数据整合全指南 +缺失值处理

数据组合与合并&#xff1a;Pandas 数据整合全指南在进行数据分析之前&#xff0c;数据清洗与整合是关键步骤。 遵循“整洁数据”&#xff08;Tidy Data&#xff09;原则&#xff1a; 每个观测值占一行每个变量占一列每种观测单元构成一张独立的表格 整理好数据后&#xff0c;常…

c#联合halcon的基础教程(案例:亮度计算、角度计算和缺陷检测)(含halcon代码)

目录 1.环境配置 2.案例一&#xff1a;亮度计算 halcon代码&#xff1a; 主界面代码&#xff1a; 3.案例二&#xff1a; 角度计算 halcon代码&#xff1a; 主界面代码&#xff1a; 4.案例三&#xff1a;缺陷检测 halcon代码&#xff1a; 主界面代码&#xff1a; 通过…

大数据云原生是什么

"云原生"&#xff08;Cloud Native&#xff09;指的是‌利用云计算原生优势&#xff08;弹性、按需服务、自动化、分布式等&#xff09;来设计、构建、部署和运行大数据应用和工作负载的方法论与技术体系‌。它不是简单地“把大数据平台搬到云上”&#xff0c;而是从…

Pytest项目_day16(yaml和parametrize结合)

查询手机号归属地 我们首先可以在YAML文件中定义测试数据 方式一&#xff0c;使用- 注意&#xff1a;当我们需要一次传入两个参数时&#xff0c;需要定义两层迭代&#xff0c;即两层列表不够直观&#xff0c;容易写错 输出的结果为&#xff1a; 然后我们可以将测试数据传入test…

【Nginx指南】从核心原理到生产实践

目录Nginx指南&#xff1a;从核心原理到生产实践引言&#xff1a;Nginx在现代架构中的核心地位一、Nginx核心能力与应用场景1.1 多场景适配的全能型中间件1.2 技术优势&#xff1a;Nginx成为行业标准的关键二、Nginx安装部署&#xff1a;源码编译与包管理方案2.1 源码编译&…

物体检测

目录 1 目标定位 2 地标检测 3 目标检测 4 在卷积网络上实现滑动窗口 5 边界框预测 6 交并比 7 非极大值抑制 8 锚框 9 YOLO算法 10 用u-net进行语义分割 11 转置卷积 12 u-net 结构灵感 1 目标定位 你已经对图片分类有所了解。例如通过这张图片可以识…

es7.x es的高亮与solr高亮查询的对比对比说明

一 solr&es高亮1.1 solr与es高亮功能解释说明&#xff1a;1)高亮配置&#xff1a;fragmentSize(1000) 设置片段长度numOfFragments(1) 指定返回的片段数量preTags() 和 postTags() 设置高亮标记2)字段处理差异&#xff1a;在 ES 中&#xff0c;使用 matchQuery 而非 termQ…

DSP音频算法工程师技能2

一、核心知识准备1. 算法原理3A算法&#xff08;AGC自动增益控制/AEC回声消除/ANS降噪&#xff09;&#xff1a;掌握AEC的NLMS/双讲检测原理&#xff0c;ANS的谱减法/维纳滤波&#xff0c;AGC的压缩曲线设计。熟悉Speex/WebRTC等开源实现。EQ音效&#xff1a;IIR/FIR滤波器设计…

第4章-04-用WebDriver页面元素操作

🏆作者简介,黑夜开发者,CSDN领军人物,全栈领域优质创作者✌,CSDN博客专家,阿里云社区专家博主,2023年CSDN全站百大博主。 🏆数年电商行业从业经验,历任核心研发工程师,项目技术负责人。 🏆本文已收录于专栏:Web爬虫入门与实战精讲,后续完整更新内容如下。 文章…

【计算机视觉与深度学习实战】04基于K-Means聚类的图像分割系统设计与实现

摘要 图像分割作为计算机视觉领域的基础任务,在目标检测、医学影像分析、自动驾驶等众多应用中发挥着关键作用。本文基于K-Means聚类算法设计并实现了一个完整的图像分割系统,该系统集成了多种颜色空间转换、自定义初始化策略、空间特征融合等先进技术。通过Python和Tkinter…

Android Studio常用知识总结

一、运行方式1.运行 (Run)当您选择“运行”时&#xff0c;Android Studio 会编译您的应用并将其安装到目标设备或模拟器上。这通常用于&#xff1a;快速部署: 您只想看看应用是否能正常启动并运行&#xff0c;或者进行一些基础的用户界面测试。性能测试: 在正常运行模式下测试应…

设计模式笔记_行为型_访问者模式

1. 访问者模式介绍访问者模式&#xff08;Visitor Pattern&#xff09;是一种行为型设计模式&#xff0c;它允许你在不改变对象结构的前提下&#xff0c;定义作用于这些对象的新操作。访问者模式将操作的逻辑从对象结构中分离出来&#xff0c;使得你可以在运行时动态地添加新的…

数学建模 14 中心对数比变换

用途&#xff1a;是处理成分数据的核心预处理方法&#xff0c;核心目标是解决成分数据的和为常数100% &#xff0c; 导致的维度冗余&#xff0c;非线性相关问题。使得数据满足传统的统计/建模方法&#xff1b;举例子&#xff1a;食品比例中 面粉(50%),糖(30%),水(20%)原理&…