SC Improper Access Control

存取控制不當是一種智能合約中的安全漏洞,會導致未經授權的使用者能夠存取或修改合約中的資料或功能。這種漏洞通常是因為合約的程式碼未根據使用者的權限等級適當限制存取權限所引起的。在智能合約中,存取控制涉及治理和關鍵邏輯,例如:

  • 發行(鑄造)代幣
  • 對提案進行投票
  • 提取資金
  • 暫停或升級合約
  • 更改合約擁有權

如果存取控制不足,任何人都可能呼叫敏感功能,從而引發嚴重的安全問題。

範例(漏洞合約)

以下是一個存在存取控制漏洞的智能合約範例:

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract Solidity_AccessControl {
    mapping(address => uint256) public balances;

    // Burn function with no access control
    function burn(address account, uint256 amount) public {
        _burn(account, amount);
    }
}

問題分析

  • 在這個合約中,burn 函數被標記為 public,這意味著任何人都可以呼叫它,無需任何權限檢查。
  • 這允許未經授權的使用者銷毀(burn)任意帳戶的代幣餘額,嚴重影響合約的安全性和完整性。

影響

存取控制不當的漏洞可能導致以下後果:

  • 未經授權的存取:攻擊者可以存取合約中的關鍵功能或資料,破壞合約的完整性與安全性。
  • 資金損失:漏洞可能導致合約控制的資金或資產被盜,給使用者和利益相關者造成重大財務損失。

修復方法

為了避免存取控制不當的漏洞,可以採取以下措施:

  • 確保初始化函數安全:初始化函數(如設置合約初始狀態的功能)應只能被呼叫一次,且僅限於授權的實體。
    • 初始化函數(通常命名為 initialize 或類似名稱)是用來設置智能合約初始狀態的程式碼,例如:
      • 設置合約的擁有者(owner)。
      • 初始化某些變數(如代幣總量、參數配置等)。
      • 設定合約的初始參數或狀態(如開啟某些功能)。
    • 初始化函數的目的是設置合約的初始狀態。如果允許它被多次呼叫,可能會導致以下問題:
      • 重複初始化可能覆蓋原有的設置,例如更改合約擁有者、改變代幣總量等,導致不一致或不安全的狀態。
      • 攻擊者可能利用多次呼叫來操縱合約狀態,破壞合約的邏輯或安全性。
    • 授權的實體通常是指合約的擁有者(owner)、管理員或其他被賦予特定權限的角色。 如果任何人都能呼叫初始化函數,會導致以下問題:
      • 攻擊者可能會將自己設置為合約擁有者,接管合約控制權。
      • 攻擊者可能會修改關鍵參數,破壞合約的功能或安全性。
  • 使用成熟的存取控制模式
    • Ownable:使用 OpenZeppelin 的 Ownable 合約,限制某些功能僅能由合約擁有者呼叫。
    • RBAC(基於角色的存取控制):根據角色分配權限,確保只有特定角色(如管理員)能執行敏感操作。
  • 添加存取控制修飾符:在敏感函數上使用修飾符(如 onlyOwner 或自訂角色)來限制存取。

修復後的範例

以下是修復後的合約程式碼,加入了適當的存取控制:

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import "@openzeppelin/contracts/access/Ownable.sol";

contract Solidity_AccessControl is Ownable {
    mapping(address => uint256) public balances;

    function burn(address account, uint256 amount) public onlyOwner {
        _burn(account, amount);
    }
}

改進分析

  • 合約繼承了 OpenZeppelin 的 Ownable 合約,提供了 onlyOwner 修飾符。
  • burn 函數現在只能由合約的擁有者(owner)呼叫,其他人無法執行此功能。
  • 這樣的設計確保了只有授權的實體(合約擁有者)能夠銷毀代幣,防止未經授權的操作。

總結

存取控制不當是智能合約中常見且危險的漏洞,可能導致未經授權的操作和資金損失。透過使用成熟的存取控制模式(如 Ownable 或 RBAC)以及適當的修飾符(如 onlyOwner),可以有效防止此類漏洞,確保合約的安全性與可靠性。