【入門編】 整数オーバーフロー・アンダーフローのSolidityバージョン別挙動 – IoT・OT(制御システム) & ブロックチェーンセキュリティ防御ガイド

整数オーバーフロー・アンダーフローの罠:Solidityの進化と「見えない泥棒」の正体

こんにちは!Web3の世界へようこそ。今日はスマートコントラクトにおける「整数オーバーフロー・アンダーフロー」という、少し強そうな名前の脆弱性についてお話しします。

「数字の計算でしょ?何がそんなに怖いの?」と思うかもしれませんが、実はここ、ブロックチェーン上の泥棒が最も好んで狙う「家の鍵の隙間」なんです。新人開発者の方にもわかるよう、身近な例えから紐解いていきましょう。

—

1. 「8ビットの時計」で考えるオーバーフロー

まず、スマートコントラクトの世界では、数字を格納する「箱」の大きさが決まっています。これを「ビット数」と言います。

想像してみてください。「0から255までしか表示できない特殊なデジタル時計」があったとします。
この時計で「255」の次に「+1」ボタンを押すとどうなるでしょうか?
普通の時計なら256になりますが、この時計は枠を超えられないので、「0」に戻ってしまいます。

これが「オーバーフロー」です。逆に、0から1を引くと「255」に戻ってしまうのが「アンダーフロー」です。

なぜこれが攻撃になるのか?

もし、あなたのWeb3アプリで「トークンの送金」処理をしていたらどうでしょう。

  • 攻撃者が「残高0」の状態で「送金額 -1」という命令を出す
  • システムが「0 – 1 = 255」と計算してしまう
  • 結果、「残高0だったはずのユーザーが、いきなり255トークン持っていることになってしまう」

こうなると、泥棒は鍵を使わずに金庫の中身を抜き取れてしまいますよね。これが、かつて多くのプロジェクトを破綻に追い込んだ悪夢の正体です。

—

2. 昔は必須だった「SafeMath」というガードマン

以前のSolidity(バージョン0.7.x以前)では、この計算ミスをプログラム自身が気づけませんでした。そこで、エンジニアたちはSafeMathという「ガードマン」を雇っていました。

// 昔の書き方:SafeMathライブラリをインポートして計算をチェックする
using SafeMath for uint256;

function transfer(address to, uint256 amount) public {
    // もし計算結果がおかしくなったら、ここでプログラムを強制停止(リバート)させる
    balance[msg.sender] = balance[msg.sender].sub(amount); 
}

このsub(引き算)やadd(足し算)という関数が、計算前に「これ、おかしくならない?」と毎回厳しくチェックしてくれていたのです。でも、毎回これを書くのはちょっと面倒でしたよね。

—

3. Solidity 0.8.xからの「自動防犯システム」

しかし、Solidity 0.8.0以降、この状況は劇的に変わりました。なんと、言語そのものが標準で「オーバーフロー・アンダーフローのチェック」を内蔵したのです!

今や、普通に a - b と書くだけで、もし結果がマイナスになるようなら、プログラムは自動的にエラーを吐いて停止するようになりました。

// Solidity 0.8.0以降の書き方
function transfer(address to, uint256 amount) public {
    // もうSafeMathはいりません!
    // もし balance[msg.sender] が amount より小さければ、ここで自動的にエラーになります
    balance[msg.sender] -= amount; 
}

「じゃあ、もう何も心配しなくていいんだ!」……と言いたいところですが、セキュリティリサーチャーとしては、ここで一つだけ注意点を伝えておかなければなりません。

—

4. まだある「盲点」:あえてチェックを外す時

実は、Solidityには unchecked という「安全装置をオフにする」キーワードがあります。

function fastCalculation() public pure returns (uint256) {
    unchecked {
        // ここではオーバーフローしてもエラーになりません
        // 計算速度を優先したい場合など、特殊なケースでのみ使われます
        uint8 x = 255;
        return x + 1; // 結果は 0 になります
    }
}

この unchecked はガス代(手数料)を節約するために使われることがありますが、「絶対に計算がオーバーフローしない」という確信がない限り、初心者のうちは絶対に使わないでください。 鍵のかかっていない玄関を放置するようなものです。

—

一歩ずつ対策を学んでいきましょう!

最後に、セキュリティの基本をまとめますね。

1. 最新のSolidityを使う: 0.8.x系を使うだけで、過去の脆弱性の9割は防げます。
2. unchecked を安易に使わない: どうしても使う必要があるときは、計算ロジックに数学的な証明が必要です。
3. テストを怠らない: Hardhat や Foundry で「わざと大きな数」を引くテストを書いて、エラーがちゃんと出るか確認しましょう。

Web3の開発は、家を建てるようなものです。土台となるプログラムが頑丈であれば、泥棒は入り込む隙を見つけられません。難しく感じるかもしれませんが、今日学んだ「数字の箱の仕組み」を意識するだけで、あなたの書くコードはぐっと安全になります。

一歩ずつ、強固なコントラクトを作っていきましょう!応援しています。

コメント

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