{"id":13432613,"url":"https://github.com/slowmist/eos-smart-contract-security-best-practices","last_synced_at":"2026-01-26T20:12:13.580Z","repository":{"id":108008280,"uuid":"149097369","full_name":"slowmist/eos-smart-contract-security-best-practices","owner":"slowmist","description":"A guide to EOS smart contract security best practices","archived":false,"fork":false,"pushed_at":"2025-07-31T09:47:19.000Z","size":51,"stargazers_count":397,"open_issues_count":0,"forks_count":73,"subscribers_count":32,"default_branch":"master","last_synced_at":"2025-07-31T13:17:05.709Z","etag":null,"topics":["blockchain","eosio","security","smart-contracts"],"latest_commit_sha":null,"homepage":"https://slowmist.com","language":null,"has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/slowmist.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null}},"created_at":"2018-09-17T09:00:41.000Z","updated_at":"2025-07-31T09:47:23.000Z","dependencies_parsed_at":"2023-03-10T09:16:00.469Z","dependency_job_id":null,"html_url":"https://github.com/slowmist/eos-smart-contract-security-best-practices","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/slowmist/eos-smart-contract-security-best-practices","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/slowmist%2Feos-smart-contract-security-best-practices","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/slowmist%2Feos-smart-contract-security-best-practices/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/slowmist%2Feos-smart-contract-security-best-practices/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/slowmist%2Feos-smart-contract-security-best-practices/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/slowmist","download_url":"https://codeload.github.com/slowmist/eos-smart-contract-security-best-practices/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/slowmist%2Feos-smart-contract-security-best-practices/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28787174,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-26T13:55:28.044Z","status":"ssl_error","status_checked_at":"2026-01-26T13:55:26.068Z","response_time":59,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["blockchain","eosio","security","smart-contracts"],"created_at":"2024-07-31T02:01:14.206Z","updated_at":"2026-01-26T20:12:08.571Z","avatar_url":"https://github.com/slowmist.png","language":null,"funding_links":[],"categories":["Others"],"sub_categories":[],"readme":"# EOS 智能合约最佳安全开发指南\n\nEnglish Version: [check here](/README_EN.md)\\\n한국어 버전: [여기를 클릭](/README_KR.md)\n\n这篇文档旨在为 EOS 智能合约开发人员提供一些智能合约的**安全准则**及**已知漏洞分析**。我们邀请社区对该文档提出修改或完善建议，欢迎各种合并请求(Pull Request)。若有相关的文章或博客的发表，也请将其加入到[参考文献](#参考文献)中。\n\n## 目录\n\n* [安全准则](#安全准则)\n* [已知漏洞](#已知漏洞)\n   * [数值溢出](#数值溢出)\n      * [漏洞示例](#漏洞示例)\n      * [防御方法](#防御方法)\n      * [真实案例](#真实案例)\n   * [权限校验](#权限校验)\n      * [漏洞示例](#漏洞示例-1)\n      * [防御方法](#防御方法-1)\n      * [真实案例](#真实案例-1)\n   * [apply 校验](#apply-校验)\n      * [漏洞示例](#漏洞示例-2)\n      * [防御方法](#防御方法-2)\n      * [真实案例](#真实案例-2)\n   * [transfer 假通知](#transfer-假通知)\n      * [漏洞示例](#漏洞示例-3)\n      * [防御方法](#防御方法-3)\n      * [真实案例](#真实案例-3)\n   * [随机数实践](#随机数实践)\n      * [漏洞示例](#漏洞示例-4)\n      * [防御方法](#防御方法-4)\n      * [真实案例](#真实案例-4)\n   * [回滚攻击](#回滚攻击)\n      * [漏洞示例](#漏洞示例-5)\n      * [防御方法](#防御方法-5)\n      * [真实案例](#真实案例-5)\n* [参考文献](#参考文献)\n* [致谢](#致谢)\n\n## 安全准则\n\nEOS 处于早期阶段并且有很强的实验性质。因此，随着新的 bug 和安全漏洞被发现，新的功能不断被开发出来，其面临的安全威胁也是不断变化的。这篇文章对于开发人员编写安全的智能合约来说只是个开始。\n\n开发智能合约需要一个全新的工程思维，它不同于我们以往项目的开发。因为它犯错的代价是巨大的，很难像中心化类型的软件那样，打上补丁就可以弥补损失。就像直接给硬件编程或金融服务类软件开发，相比于 Web 开发和移动开发都有更大的挑战。因此，仅仅防范已知的漏洞是不够的，还需要学习新的开发理念：\n\n- **对可能的错误有所准备**。任何有意义的智能合约或多或少都存在错误，因此你的代码必须能够正确的处理出现的 bug 和漏洞。需始终保证以下规则：\n\t- 当智能合约出现错误时，停止合约\n\t- 管理账户的资金风险，如限制（转账）速率、最大（转账）额度\n\t- 有效的途径来进行 bug 修复和功能提升\n- **谨慎发布智能合约**。 尽量在正式发布智能合约之前发现并修复可能的 bug。\n\t- 对智能合约进行彻底的测试，并在任何新的攻击手法被发现后及时的测试（包括已经发布的合约）\n\t- 从 alpha 版本在麒麟测试网(CryptoKylin-Testnet)上发布开始便邀请专业安全审计机构进行审计，并提供漏洞赏金计划(Bug Bounty)\n\t- 阶段性发布，每个阶段都提供足够的测试\n- **保持智能合约的简洁**。复杂会增加出错的风险。\n\t- 确保智能合约逻辑简洁\n\t- 确保合约和函数模块化\n\t- 使用已经被广泛使用的合约或工具（比如，不要自己写一个随机数生成器）\n\t- 条件允许的话，清晰明了比性能更重要\n\t- 只在你系统的去中心化部分使用区块链\n- **保持更新**。通过公开资源来确保获取到最新的安全进展。\n\t- 在任何新的漏洞被发现时检查你的智能合约\n\t- 尽可能快的将使用到的库或者工具更新到最新\n\t- 使用最新的安全技术\n- **清楚区块链的特性**。尽管你先前所拥有的编程经验同样适用于智能合约开发，但这里仍然有些陷阱你需要留意：\n\t- `require_recipient(account_name name)` 可触发通知，如果账户`name`下有合约，会调用`name`合约中的同名函数，[官方文档](https://developers.eos.io/eosio-cpp/v1.2.0/reference#section-require_recipient)\n\n## 已知漏洞\n\n### 数值溢出\n\n在进行算术运算时，未进行边界检查可能导致数值上下溢，引起智能合约用户资产受损。\n\n#### 漏洞示例\n\n存在缺陷的代码：`batchtransfer` 批量转账\n\n```c++\ntypedef struct acnts {\n    account_name name0;\n    account_name name1;\n    account_name name2;\n    account_name name3;\n} account_names;\n\nvoid batchtransfer(symbol_name symbol, account_name from, account_names to, uint64_t balance)\n{\n    require_auth(from);\n    account fromaccount;\n\n    require_recipient(from);\n    require_recipient(to.name0);\n    require_recipient(to.name1);\n    require_recipient(to.name2);\n    require_recipient(to.name3);\n\n    eosio_assert(is_balance_within_range(balance), \"invalid balance\");\n    eosio_assert(balance \u003e 0, \"must transfer positive balance\");\n\n    uint64_t amount = balance * 4; //乘法溢出\n\n    int itr = db_find_i64(_self, symbol, N(table), from);\n    eosio_assert(itr \u003e= 0, \"Sub-- wrong name\");\n    db_get_i64(itr, \u0026fromaccount, (account));\n    eosio_assert(fromaccount.balance \u003e= amount, \"overdrawn balance\");\n\n    sub_balance(symbol, from, amount);\n\n    add_balance(symbol, to.name0, balance);\n    add_balance(symbol, to.name1, balance);\n    add_balance(symbol, to.name2, balance);\n    add_balance(symbol, to.name3, balance);\n}\n```\n\n#### 防御方法\n\n尽可能使用 asset 结构体进行运算，而不是把 balance 提取出来进行运算。\n\n#### 真实案例\n\n- [【EOS Fomo3D你千万别玩】狼人杀遭到溢出攻击, 已经凉凉](https://bihu.com/article/995093)\n\n### 权限校验\n\n在进行相关操作时，应严格判断函数入参和实际调用者是否一致，使用`require_auth`进行校验。\n\n#### 漏洞示例\n\n存在缺陷的代码：`transfer` 转账\n\n```c++\nvoid token::transfer( account_name from,\n                      account_name to,\n                      asset        quantity,\n                      string       memo )\n{\n    eosio_assert( from != to, \"cannot transfer to self\" );\n    eosio_assert( is_account( to ), \"to account does not exist\");\n    auto sym = quantity.symbol.name();\n    stats statstable( _self, sym );\n    const auto\u0026 st = statstable.get( sym );\n\n    require_recipient( from );\n    require_recipient( to );\n\n    eosio_assert( quantity.is_valid(), \"invalid quantity\" );\n    eosio_assert( quantity.amount \u003e 0, \"must transfer positive quantity\" );\n    eosio_assert( quantity.symbol == st.supply.symbol, \"symbol precision mismatch\" );\n    eosio_assert( memo.size() \u003c= 256, \"memo has more than 256 bytes\" );\n\n    auto payer = has_auth( to ) ? to : from;\n\n    sub_balance( from, quantity );\n    add_balance( to, quantity, payer );\n}\n```\n\n#### 防御方法\n\n使用`require_auth( from )`校验资产转出账户与调用账户是否一致。\n\n#### 真实案例\n\n暂无\n\n### apply 校验\n\n在处理合约调用时，应确保每个 action 与 code 均满足关联要求。\n\n#### 漏洞示例\n\n存在缺陷的代码：\n\n```c++\n// extend from EOSIO_ABI\n#define EOSIO_ABI_EX( TYPE, MEMBERS ) \\\nextern \"C\" { \\\n   void apply( uint64_t receiver, uint64_t code, uint64_t action ) { \\\n      auto self = receiver; \\\n      if( action == N(onerror)) { \\\n         /* onerror is only valid if it is for the \"eosio\" code account and authorized by \"eosio\"'s \"active permission */ \\\n         eosio_assert(code == N(eosio), \"onerror action's are only valid from the \\\"eosio\\\" system account\"); \\\n      } \\\n      if( code == self || code == N(eosio.token) || action == N(onerror) ) { \\\n         TYPE thiscontract( self ); \\\n         switch( action ) { \\\n            EOSIO_API( TYPE, MEMBERS ) \\\n         } \\\n         /* does not allow destructor of thiscontract to run: eosio_exit(0); */ \\\n      } \\\n   } \\\n}\n\nEOSIO_ABI_EX(eosio::charity, (hi)(transfer))\n```\n\n#### 防御方法\n\n使用\n\n```\nif( ((code == self  \u0026\u0026 action != N(transfer) ) || (code == N(eosio.token) \u0026\u0026 action == N(transfer)) || action == N(onerror)) ) { }\n```\n\n绑定每个关键 action 与 code 是否满足要求，避免异常调用。\n\n#### 真实案例\n\n- [EOSBet 黑客攻击事件复盘](https://medium.com/@eosbetcasino/eosbet-%E9%BB%91%E5%AE%A2%E6%94%BB%E5%87%BB%E4%BA%8B%E4%BB%B6%E5%A4%8D%E7%9B%98-13663d8f3f1)\n\n### transfer 假通知\n\n在处理 `require_recipient` 触发的通知时，应确保 `transfer.to` 为 `_self`。\n\n#### 漏洞示例\n\n存在缺陷的代码：\n\n```c++\n// source code: https://gitlab.com/EOSBetCasino/eosbetdice_public/blob/master/EOSBetDice.cpp#L115\nvoid transfer(uint64_t sender, uint64_t receiver) {\n\n\tauto transfer_data = unpack_action_data\u003cst_transfer\u003e();\n\n\tif (transfer_data.from == _self || transfer_data.from == N(eosbetcasino)){\n\t\treturn;\n\t}\n\n\teosio_assert( transfer_data.quantity.is_valid(), \"Invalid asset\");\n}\n```\n\n#### 防御方法\n\n增加\n\n```\nif (transfer_data.to != _self) return;\n```\n\n#### 真实案例\n\n- [EOS DApp 充值“假通知”漏洞分析](https://mp.weixin.qq.com/s/8hg-Ykj0RmqQ69gWbVwsyg)\n\n### 随机数实践\n\n随机数生成算法不要引入可控或者可预测的种子\n\n#### 漏洞示例\n\n存在缺陷的代码：\n\n```c++\n// source code: https://github.com/loveblockchain/eosdice/blob/3c6f9bac570cac236302e94b62432b73f6e74c3b/eosbocai2222.hpp#L174\nuint8_t random(account_name name, uint64_t game_id)\n{\n    auto eos_token = eosio::token(N(eosio.token));\n    asset pool_eos = eos_token.get_balance(_self, symbol_type(S(4, EOS)).name());\n    asset ram_eos = eos_token.get_balance(N(eosio.ram), symbol_type(S(4, EOS)).name());\n    asset betdiceadmin_eos = eos_token.get_balance(N(betdiceadmin), symbol_type(S(4, EOS)).name());\n    asset newdexpocket_eos = eos_token.get_balance(N(newdexpocket), symbol_type(S(4, EOS)).name());\n    asset chintailease_eos = eos_token.get_balance(N(chintailease), symbol_type(S(4, EOS)).name());\n    asset eosbiggame44_eos = eos_token.get_balance(N(eosbiggame44), symbol_type(S(4, EOS)).name());\n    asset total_eos = asset(0, EOS_SYMBOL);\n    //攻击者可通过inline_action改变余额total_eos，从而控制结果\n    total_eos = pool_eos + ram_eos + betdiceadmin_eos + newdexpocket_eos + chintailease_eos + eosbiggame44_eos;\n    auto mixd = tapos_block_prefix() * tapos_block_num() + name + game_id - current_time() + total_eos.amount;\n    const char *mixedChar = reinterpret_cast\u003cconst char *\u003e(\u0026mixd);\n\n    checksum256 result;\n    sha256((char *)mixedChar, sizeof(mixedChar), \u0026result);\n\n    uint64_t random_num = *(uint64_t *)(\u0026result.hash[0]) + *(uint64_t *)(\u0026result.hash[8]) + *(uint64_t *)(\u0026result.hash[16]) + *(uint64_t *)(\u0026result.hash[24]);\n    return (uint8_t)(random_num % 100 + 1);\n}\n```\n\n#### 防御方法\n\nEOS链上不能生成真随机数，在设计随机类应用时建议参考官方的示例\n\n- [Randomization in Contracts](https://developers.eos.io/eosio-cpp/v1.3.2/docs/random-number-generation)\n\n\n#### 真实案例\n\n- [慢雾预警：知名DApp EOSDice由于随机数问题再次被黑](http://www.chaindd.com/nictation/3140025.html)\n\n\n### 回滚攻击\n\n- 手法1：在事务中探测执行结果(如收款金额、账号余额、表记录、随机数计算结果等)，当结果满足一定条件时调用 eosio_assert ，使得当前事务失败回滚。\n- 手法2：利用超级节点黑名单账号发起事务，欺骗普通节点做出响应，但此事务不会被打包。\n\n#### 漏洞示例\n\n常见的有缺陷的模式：\n\n- 博弈类游戏下注随即开奖并转账，恶意合约可通过 inline_action 检测余额是否增加，从而回滚失败的开奖\n- 博弈类游戏下注随即将开奖结果写入表内，恶意合约可通过 inline_action 检测表中记录，从而回滚失败的开奖\n- 博弈类游戏开奖结果与游戏内奖券号相关联，恶意合约可通过同时发起多笔小额下注事务和一笔大额下注事务，当收到小额中奖时回滚事务，从而达到将可中奖的奖券号“转让”给大额下注的目的。\n- 博弈类游戏开奖事务与下注事务没有关联，攻击者可用黑名单账号或者恶意合约回滚下注事务\n\n#### 防御方法\n\n- 使用 defer action 转账和发送收据\n- 建立开奖依赖，如订单依赖，开奖的时候判断订单是否存在，就算在节点服务器上开奖成功，由于在 bp 上下注订单被回滚，所以相应的开奖记录也会被回滚。\n\n\n#### 真实案例\n\n- [EOS 回滚攻击手法分析之黑名单篇](https://mp.weixin.qq.com/s/WyZ4j3O68qfN5IOvjx3MOg)\n\n## 参考文献\n\n- [保管好私钥就安全了吗？注意隐藏在EOS DAPP中的安全隐患](https://zhuanlan.zhihu.com/p/40625180)\n- [漏洞详解|恶意 EOS 合约存在吞噬用户 RAM 的安全风险](https://zhuanlan.zhihu.com/p/40469719)\n- [How EOSBET attacked by aabbccddeefg](https://www.reddit.com/r/eos/comments/9fpcik/how_eosbet_attacked_by_aabbccddeefg/)\n- [BET被黑客攻击始末，实锤还原作案现场和攻击手段](https://github.com/ganjingcun/bet-death-causes/blob/master/README.md)\n- [累计薅走数百万，EOS Dapps已成黑客提款机？](https://mp.weixin.qq.com/s/74ggygC3nbDihLkobXOW2w)\n\n## 致谢\n\n- [麒麟工作组](https://github.com/cryptokylin)\n- eosiofans\n- 荆凯(EOS42)\n- 星魂\n- 岛娘\n- 赵余(EOSLaoMao)\n- 字符\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fslowmist%2Feos-smart-contract-security-best-practices","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fslowmist%2Feos-smart-contract-security-best-practices","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fslowmist%2Feos-smart-contract-security-best-practices/lists"}