こんにちは!CryptoGamesというブロックチェーンゲーム企業でエンジニアをしているかるでねです!
スマートコントラクトを書いたり、フロントエンド・バックエンド・インフラと幅広く触れています。
このブログ以外でも情報発信しているので、よければ他の記事も見ていってください。
https://mirror.xyz/0xcE77b9fCd390847627c84359fC1Bc02fC78f0e58
今回は「タイムスタンプ」の脆弱性について解説していきます!
Solidityではblock.timestamp
という「タイムスタンプ」がよく使用されています。
実はこの「タイムスタンプ」には脆弱性につながるような危険性が含まれています...。
よく使用されるからこそ注意が必要なので、ぜひこの記事で学んでいってください!
Solidityスキルを1段階あげたい方やバグ・バウンティに参加したいバグハンターを目指している方は必須の知識となるので、この記事で学んでいってください。
バグ・バウンティが何かわからない人は以下の記事を読んでください。
また、以下の記事でもこの記事では取り上げていないblock.timestampの危険性について紹介しているので参考にしてください!
タイムスタンプとは?
まずはタイムスタンプの定義から確認していきましょう!
タイムスタンプの定義
Wikipediaでは以下のように書かれています。
タイムスタンプ(英: timestamp)とはある出来事が発生した日時・日付・時刻などを示す文字列。狭義には郵便物の発送日時等を示すために押される郵便印のことを指す(画像を参照のこと)[1]。現在ではコンピュータにおける「タイムスタンプ」が良く知られている。
https://ja.wikipedia.org/wiki/タイムスタンプ
ある時点での日付や日時を表したものがタイムスタンプであると書かれていますね。
例えばOSでは、「ファイルの作成時」、「ファイルの更新時」に自動で付与されたりします。
Solidityでのタイムスタンプ
では、次にSolidityではタイムスタンプをどのように使用するのか見ていきましょう。
Solidityの公式ドキュメントを確認すると以下のように書かれています。
•
https://solidity-jp.readthedocs.io/ja/latest/units-and-global-variables.htmlblock.timestamp
(uint
): 現在のunixのタイムスタンプ(秒)
まずはuint
型かつ秒で示されると言うことがわかりました。
unixと書かれているのですがこれは何でしょう?
unix時間についてwikipediaで調べると以下のように書かれています。
UNIX時間(ユニックスじかん)またはUNIX時刻(ユニックスじこく、UNIX time(ユニックスタイム)、POSIXtime(ポジックスタイム))とはコンピューターシステム上での時刻表現の一種。協定世界時 (UTC) での1970年1月1日午前0時0分0秒(UNIXエポック)から形式的な経過秒数として表される。
真の経過秒数ではなく[1]、その間に挿入された閏秒を引き、削除された閏秒を加えた値である。大多数のシステムで採用されている[注 2]。
UNIX系のオペレーティングシステム(データ型はtime_t)だけでなく、他の多くのオペレーティングシステムにおいてもこの表現方法が用いられている。システム内部では64ビット符号付整数(signed int)や64ビット倍精度浮動小数点数で扱われていることが多い。ここで、以前は多かった32ビット整数で扱われていた場合で、符号付きであった場合、その最大値 2,147,483,647 を超えると負の値になり、正しく時刻を扱えなくなるという問題がある。これを2038年問題という。
https://ja.wikipedia.org/wiki/UNIX時間
読んでも理解しづらいと思うので、コンピューターシステム上での時間表現の1つと覚えておけば良いです!
では実際にSolidityで実行してみましょう。
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.13;
contract Timestamp {
uint public time;
function updateTimestamp() public {
time = block.timestamp;
}
}
上記のコードを実行すると以下の数値がtime変数に格納されました。
1672451295
ではこの数値を通常の日時に変換してみましょう。
以下のサイトを使います。
https://tool.konisimple.net/date/unixtime
2022-12-31 10:48:15
このように変換されました。
タイムスタンプ操作とは?
前章でタイムスタンプの基礎について理解できました。
実はこのタイムスタンプですがマイナーによって操作することができてしまいます。
マイナーとは「トランザクションを検証し、問題なければブロックに含める作業」を行う人のことを指します。
詳しくはcoinbaseさんの以下の記事などが参考になります。
https://www.coinbase.com/ja/learn/crypto-basics/what-is-mining
このマイナーによって以下の条件のもとタイムスタンプを自由に操作され、スマートコントラクトを攻撃することができてしまいます。
条件
- 最後のブロックのタイムスタンプよりも後の時間になっている。
- 追加するタイムスタンプがあまりにも遠い未来であってはいけない。
この条件を満たせばマイナーによって自由に操作される危険性があります。
具体的には次の章で紹介していきます!
タイムスタンプ操作の実装
前章ではタイムスタンプ操作について確認してきました。
この章では実際のコードをもとにタイムスタンプ操作の危険性について確認してきます!
コード
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.13;
contract Roulette {
constructor() payable {}
/// @notice block.timestampが7で割り切れる場合コントラクト内の資金を取得できる関数。
function judgment() external payable {
require(msg.value == 1 ether);
if (block.timestamp % 7 == 0) {
(bool sent, ) = msg.sender.call{value: address(this).balance}("");
require(sent, "Failed to send Ether");
}
}
}
コードの解説
上記のコードは1 ether
を預けてjudgment
関数を実行すると、実行タイミングでのタイムスタンプを取得し、もしタイムスタンプが7
で割り切れる場合はコントラクト内の資金を全て取得できるものです。
このコードの何がいけないかというと、マイナーが7
で割り切れるタイムスタンプを指定してトランザクションを通すことができてしまうことです。
そうするとランダム性は失われ、マイナーにコントラクト内の資金を好き放題に抜かれてしまいます。
以下の記事でもblock.timesampの危険性を取り上げているので、ぜひ参考にしてください。
回避策
ではどうすればマイナーにタイムスタンプを操作されないようにできるでしょうか?
方法は2つあります。
block.timestampを使用しない
そもそもblock.timestamp
を使用して判定しない設計にすれば、マイナーに好き放題資金を抜かれなくなります。
以下の記事でもblock.timestamp
の脆弱性を取り上げているように、block.timestamp
を使用する際は注意が必要なので、使用する部分は注意深く考える必要があります。
15秒ルール
「5秒ルール」は聞いたことあっても、「15秒ルール」は聞いたことないと思います。
では15秒ルールとは何でしょうか?
先ほどマイナーがタイムスタンプを操作できる条件として「追加するタイムスタンプがあまりにも遠い未来であってはいけない。」と言うものがありました。
この「あまりにも遠い未来」が15秒先と言うことです。
15秒先のタイムスタンプを持つブロックはブロックされるように設計されています。
つまり、もし15秒経っても整合性が保たれるのであれば、block.timestamp
を使用しても問題ないという事になります。
最後に
今回は「タイムスタンプ」について紹介していきました!
いかがだったでしょうか?
ポイント
- 「タイムスタンプについて理解できた!」
- 「タイムスタンプの脆弱性について理解できた!」
- 「タイムスタンプを使用する際の注意点を理解できた!」
あなたが上記が当てはまっていれば嬉しいです!
もし何か質問などがあれば以下のTwitterなどから連絡ください!
普段はSolidityやブロックチェーン、Web3についての情報発信をしています。
Twiiterでは気になった記事などを共有しているので、ぜひフォローしてくれると嬉しいです!
参考
https://consensys.net/blog/developers/solidity-best-practices-for-smart-contract-security/
https://dev.to/kamilpolak/hack-solidity-block-timestamp-manipulation-1mbg