【入門編】 アクセス制御の不備:OwnableとAccessControlの適切な使い分け – IoT・OT(制御システム) & ブロックチェーンセキュリティ防御ガイド

こんにちは!セキュリティの世界へようこそ。

スマートコントラクトやIoT・OT(制御システム)のセキュリティと聞くと、「なんだか難しそう……」「自分に理解できるかな?」と不安に思う方も多いかもしれません。でも、安心してくださいね。

これらはすべて、私たちが日常で行っている「お家の防犯」や「鍵の管理」とまったく同じ考え方で理解できるんです。

今回は、スマートコントラクト開発で非常によく使われる「アクセス制御(誰がどの操作をしてよいか決めるルール)」の仕組みについて、泥棒の侵入を防ぐ防犯対策に例えながら、一歩ずつ丁寧に学んでいきましょう!

—

1. なぜスマートコントラクトに「鍵(アクセス制御)」が必要なの?

ブロックチェーン上で動くスマートコントラクトは、一度公開すると世界中の誰からでもアクセスできるようになります。

もし、お家の玄関に鍵がついていなかったらどうなるでしょうか?
泥棒が勝手に入ってきて、中の家具を盗んだり、勝手に壁の色を塗り替えたりしてしまいますよね。

スマートコントラクトも同じです。
例えば、「コントラクトに貯まったお金を引き出す関数」や「IoTデバイスを遠隔操作するための設定を変更する関数」が、誰でも自由に呼び出せる状態(=鍵がかかっていない状態)になっていたら、悪意ある攻撃者に一瞬でハッキングされてしまいます。

だからこそ、「この操作ができるのは、この鍵(アドレス)を持っている人だけ!」という制限をかける必要があるのです。これがアクセス制御になります。

—

2. 「Ownable」と「AccessControl」:2つの鍵の仕組み

スマートコントラクトのデファクトスタンダード(標準的なライブラリ)である「OpenZeppelin」には、主に2つのアクセス制御の仕組みが用意されています。それが Ownable と AccessControl です。

これらを身近な防犯に例えて比較してみましょう。

① Ownable(オーナー制)=「一軒家のたった1つの玄関の鍵」

Ownable は、コントラクトに「たった一人のオーナー(Owner)」を設定する、最もシンプルな仕組みです。

  • イメージ: あなたのマイホームの玄関の鍵です。あなたが鍵を持っていれば、家の中に入ってすべての部屋を自由に操作できます。
  • メリット: 実装がとても簡単で、コードもすっきりします。
  • デメリット: もしその鍵を落としたり、泥棒に盗まれたり(=オーナーの秘密鍵が流出したり)したら、家の中のすべてが支配されてしまいます。

② AccessControl(ロールベース:RBAC)=「ホテルのマスターキーと部門ごとのカードキー」

AccessControl は、「役割(ロール)」ごとに細かく鍵を分ける仕組みです。

  • イメージ: ホテルの管理システムです。
  • 「支配人(DEFAULT_ADMIN_ROLE)」:すべての部屋の鍵を発行・剥奪できる。
  • 「清掃員(STAFF_ROLE)」:客室のドアだけを開けられる。
  • 「設備エンジニア(ENGINEER_ROLE)」:ボイラー室(IoT/OT制御部など)だけに入れる。
  • メリット: 清掃員の鍵が盗まれても、ボイラー室や金庫は守られます。被害を最小限に抑える(最小権限の原則)ことができます。
  • デメリット: どの役割にどの権限を与えるかを設計する必要があるため、少しだけコードが複雑になります。

—

3. 実際のコードで見てみよう!

では、この2つの違いを Solidity というスマートコントラクト言語のコード例で見てみましょう。

パターンA:シンプルな Ownable を使った実装

まずは、一軒家の鍵である Ownable を使った例です。

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

// OpenZeppelinからOwnableライブラリをインポートします
import "@openzeppelin/contracts/access/Ownable.sol";

// Ownableを継承してコントラクトを作成します
contract SimpleIoTController is Ownable {

    // IoTデバイスの稼働ステータス
    bool public isDeviceRunning;

    // 初期設定:コントラクトを配備(デプロイ)した人がオーナーになります
    constructor(address initialOwner) Ownable(initialOwner) {
        isDeviceRunning = false;
    }

    // 「onlyOwner」という修飾子をつけることで、オーナーしか実行できなくなります
    function toggleDevice() public onlyOwner {
        isDeviceRunning = !isDeviceRunning;
    }
}

【現場での盲点】
この SimpleIoTController はシンプルで分かりやすいですよね。しかし、もしこのコントラクトが「工場の重要なインフラ設備(OTシステム)」を動かすものだった場合、オーナーの秘密鍵を管理するパソコンがウイルスに感染したらどうなるでしょうか?
ハッカーにすべての制御を乗っ取られてしまい、工場が停止する大惨事になりかねません。

—

パターンB:より安全な AccessControl を使った実装

そこで登場するのが、役割を分担する AccessControl です。

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

// OpenZeppelinからAccessControlライブラリをインポートします
import "@openzeppelin/contracts/access/AccessControl.sol";

contract SecureIoTController is AccessControl {
    
    // 1. 各役割(ロール)を一意のデータ(ハッシュ値)として定義します
    bytes32 public constant ADMIN_ROLE = keccak256("ADMIN_ROLE");
    bytes32 public constant OPERATOR_ROLE = keccak256("OPERATOR_ROLE");

    bool public isDeviceRunning;

    constructor(address defaultAdmin, address initialOperator) {
        // 2. 初期設定で、それぞれの役割を特定のアドレスに割り当てます
        
        // 管理者ロール(このロールを持つ人は、他の人にオペレーター権限をあげたり奪ったりできます)
        _grantRole(DEFAULT_ADMIN_ROLE, defaultAdmin); 
        _grantRole(ADMIN_ROLE, defaultAdmin);

        // オペレーターロール(実際にデバイスを動かす権限を持つ人)
        _grantRole(OPERATOR_ROLE, initialOperator);
    }

    // 「onlyRole(OPERATOR_ROLE)」をつけることで、オペレーターだけが実行可能になります
    function toggleDevice() public onlyRole(OPERATOR_ROLE) {
        isDeviceRunning = !isDeviceRunning;
    }

    // 管理者だけが実行できる、新しいオペレーターを追加する関数
    function addOperator(address newOperator) public onlyRole(ADMIN_ROLE) {
        grantRole(OPERATOR_ROLE, newOperator);
    }
}

このように設計しておけば、万が一現場で操作を行うオペレーターの鍵(OPERATOR_ROLE)が紛失・盗難に遭っても、管理者が速やかにその権限を剥奪(レボーク)し、新しいオペレーターに権限を移し替えることができます。これならお家全体の鍵を取り替える必要はありませんよね!

—

4. 泥臭い現場のリアル:一番偉い鍵(管理者権限)はどう守る?

「なるほど、役割を分ければ安全なんだね!」と思ったあなた、素晴らしい気づきです。
しかし、セキュリティの現場ではもう一歩、踏み込んだ対策を行います。

それは、「一番偉い権限(DEFAULT_ADMIN_ROLE や Ownable のオーナー権限)を持っている人が、もし悪い人に脅されたり、鍵を盗まれたらどうするの?」という問題です。

これを解決するのが、マルチシグ(マルチ・シグネチャー)ウォレットです。

マルチシグとは? =「2人以上のハンコが必要な重要書類」

マルチシグとは、1つの取引を実行するために「複数人の署名(鍵)」を必要とする仕組みのことです。

  • イメージ: 会社の金庫を開けるために、社長の鍵と、副社長の鍵の「2つの鍵を同時に回さないと開かない」という仕組みです。
  • 実務での推奨: スマートコントラクトのオーナー権限(または管理者ロール)のアドレスを、個人のウォレットではなく、Gnosis Safe(現在はSafe)などの実績あるマルチシグウォレットに設定します。

こうすることで、ハッカーが管理者のうち1人のパソコンをハッキングしても、他のメンバーの承認が得られないため、勝手にコントラクトの設定を変更される(権限昇格や不正操作)を防ぐことができます。

—

5. まとめ:一歩ずつ対策を学んでいきましょう!

最後に、今回のポイントをおさらいしましょう。

1. アクセス制御は必須: 鍵がかかっていないスマートコントラクトは、泥棒に入り放題の家と同じ。
2. Ownable(オーナー制): シンプルで使いやすいけれど、鍵が1つなので紛失・盗難時のリスクが高い。
3. AccessControl(ロールベース): 役割ごとに鍵を分けることで、万が一の被害を一部分に限定できる。
4. マルチシグの導入: 最も強い権限を持つ鍵は、1人ではなく複数人で管理する(マルチシグウォレットの利用)。

セキュリティ対策は、一朝一夕で完璧にする必要はありません。まずは「この操作は誰ができるべきなのか?」を整理することから始まります。

身近な防犯の知恵をスマートコントラクトの世界にも応用して、一歩ずつ安全なシステムを構築していきましょう!

コメント

タイトルとURLをコピーしました