スマートコントラクトセキュリティ 

## スマートコントラクトとは
・ブロックチェーンであらかじめ設定されたルールに従って、トランザクション（取引）などを自動的に実行するプログラムです。
・主の開発言語は Solidity（Ethereum）

## スマートコントラクトセキュリティ
・ブロックチェーン自体は安全だが、アプリケーションはそうではない。
・仮想通貨を扱っているため、脆弱性によって多くの財産の損失になる可能性がある。
・言語の特性上、デプロイすると修正できなくなるので。より気を付ける必要がある。
・コードを公開する場合が多い、多くの人がソースを見えることができる。

## 過去事例
TheDAO事件 リエントラント攻撃 約 52億円 損失

https://coincheck.blog/1514

ParityWallet事件 アクセス修飾子脆弱性 約 3000万ドル 損失

https://jp.reuters.com/article/idJP00093300_20170721_02020170721

EOS.WIN事件 ランダム数予測攻撃 約 10万ドル 損失

https://cointelegraph.com/news/hacker-spends-1k-to-win-over-110k-in-eos-betting-game-using-rex


## 本編を読む前、見たほうがよい予備知識
Solidity言語 勉強サイト CryptoZombies

https://cryptozombies.io/jp/

ブロックチェーンとは

https://www.softbank.jp/biz/blog/business/articles/201804/blockchain-basic/

スマートコントラクトとは何ですか？

https://www.coinbase.com/ja/learn/crypto-basics/what-is-a-smart-contract

# 本編

## 警告
本文で展示しているサンプルコードは、あくまでセキュリティを理解するため、勉強用のサンプルです。
悪用などしないでください。

## よくある攻撃手段と事例（一部）
### リエントラント攻撃
本来であれば、関数を一度実行すると中断することなく上から下まで実行されます。
脆弱性を利用して、関数の実行が途中で中断し、任意の処理を差し込めるようになります。
任意の処理なので、同じ関数をもう一度実行可能です。
その場合、実行中断中にもう一度頭から再実行されることになります。

### サービス拒否攻撃
脆弱性を利用して、スマートコントラクトを機能させなくする攻撃手段。

### ランダム数予測攻撃
ランダム数生成アルゴリズムを知った上で、ランダム数の結果を予測する

### アクセス修飾子脆弱性
正しくないアクセス修飾子を利用する原因で外部から送金などの関数実行される

## リエントラント攻撃

### 今回例になるスマコン
銀行みたい、入金出金の機能。１回は１Ether以上の入出金制限、ロジック自体問題なさそうですか....
![スクリーンショット 2022-12-04 21.41.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/451854/7eab56ee-7876-477d-e3ec-951ecd4b989e.png)

### 今回攻撃用のスマコン
注目のところは「fallback」関数
![スクリーンショット 2022-12-04 21.41.46.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/451854/85b303d9-9f49-70e5-9041-2b163a3ea3d1.png)

### 説明
fallback関数は このスマコンが Receive 時呼び出しする
![スクリーンショット 2022-12-04 21.41.46.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/451854/85b303d9-9f49-70e5-9041-2b163a3ea3d1.png)

1. etherを入金し、bankのwithdraw関数を呼び出しする（出金操作）
![スクリーンショット 2022-12-12 17.45.32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/451854/df017f91-2502-0d38-df38-a9d4f3393ddd.png)

2. Bankスマコンのwithdraw関数を実行
![スクリーンショット 2022-12-12 17.46.58.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/451854/a4782423-53b1-2e81-3b7e-e9aec97fa921.png)

3. 出金する人が1 ether以上持つことを確認し、出金操作を実行する
![スクリーンショット 2022-12-12 17.47.39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/451854/c014b1af-55ff-3edf-528a-3d3e4aee8cce.png)

4. Attackスマコンのfallback関数を呼び出し、bankスマコンのwithdrawを呼び出し
![スクリーンショット 2022-12-12 17.48.09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/451854/96c7ba5a-59b0-f3cb-7bae-6ea76fc6de5c.png)

5. withdrawを再呼び出し、残高を減らす処理が実行されなかった。
![スクリーンショット 2022-12-12 17.48.38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/451854/6bc5bc83-699a-5fbb-aa5f-3cb9ce256d02.png)
AttackスマコンはBankスマコンで持っている1 Etherが減っていないため、Bankスマコンの残高が無くなるまで出金することができる。

### 攻撃前:
Bank: 10 ether
Attack : 1 ether
![スクリーンショット 2022-12-12 17.50.13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/451854/49077415-0827-8636-9e34-1a80923608e2.png)

### 攻撃後:
Bank: 0 ether
Attack : 11 ether
![スクリーンショット 2022-12-12 17.51.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/451854/14c84373-0dbd-2757-115b-eba1010897d0.png)

### リエントラント攻撃 - 結果
#### 損失：
直接の財産損失
#### 対策：
・検査 -> 有効 -> 実行の手順で書く　（今回の修正例）
![2022-12-04 21.47のイメージ.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/451854/24e594c2-44d0-5978-8841-ee1d6a97ac9a.jpeg)
・send、callではなくtransfer関数を使う （gasが足りなくなって、リエントラントができなくなる）

## サービス拒否攻撃
### 今回例になるスマコン
シンプルのオークション機能
現在価格より上回る場合は最高入札者になる。
![スクリーンショット 2022-12-02 17.51.41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/451854/14d99934-4370-d044-a55a-542441fbf6b5.png)

### 今回攻撃用のスマコン
注目のところは「Receive」関数がないこと
つまり「受け取る」ことができません
![スクリーンショット 2022-12-02 17.52.03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/451854/9425da59-ef42-7317-e668-903a33dca0a7.png)

### 説明
攻撃用スマコンを使って、Auctionスマコンのbid関数を呼び出し
![スクリーンショット 2022-12-02 17.52.03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/451854/9425da59-ef42-7317-e668-903a33dca0a7.png)
![スクリーンショット 2022-12-02 17.51.41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/451854/14d99934-4370-d044-a55a-542441fbf6b5.png)
１回目は最高入札者がいないため正常実行。
![スクリーンショット 2022-12-02 17.53.46.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/451854/d533e320-8fd0-af11-70f5-324e02921fd1.jpeg)
攻撃スマコンもう一回使って、Auctionスマコンのbid関数を呼び出し
攻撃スマコンは返金を Receive(受け取る) ことができませんので、payableのところまで実行するとサービス拒否になる。
![スクリーンショット 2022-12-02 17.51.41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/451854/14d99934-4370-d044-a55a-542441fbf6b5.png)
ここまで、このスマコンはもう使うことができない（攻撃者より上回ることができない）
![スクリーンショット 2022-12-02 17.54.02.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/451854/c383eefd-f169-b42f-6b19-0a0e188c1933.jpeg)

### サービス拒否攻撃 - 結果
#### 損失：
・スマコンが使えなくなります。
・スマコン内の残高が取れなくなる事例もあります。
#### 対策：
・今回の例限りなく、いろんなところで発生する可能性があります(ガス代設定していない外部呼び出し、配列長さ長すぎるなどなど色々な原因)
・今回の例は、払い戻しの処理を別関数にして、解決できます。（ただし払い戻しの処理はまだ別のところで呼び出しする必要がある）

### サービス拒否攻撃 ー 対策修正例
・bidから払い戻しの処理を外す
・withdrawという払い戻しの別関数追加
・アプリ側で適切なタイミングでwithdrawを呼び出し、前の最高入札者へ払い戻し
![2022-12-02 19.25のイメージ.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/451854/3692b52f-b876-2c76-97d4-f3d353b2e167.jpeg)

## ランダム数予測攻撃
### 今回例になるスマコン
数字を予測するゲーム、奇数の場合当たると判定、偶数なら当たらないと判定。
ブロック難易度＋タイムスタンプのハッシュ値でランダム数生成する、一見ランダム性があって、安全な感じですか...
![スクリーンショット 2022-12-03 14.14.04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/451854/585fb469-3521-f721-6d1b-6405cab8443b.png)

### 今回攻撃用のスマコン
ランダム数を先に予測し、勝つ結果だけguess関数を呼び出し、二つのスマコンとも同じブロックで実行されるので、取れたブロック難易度とタイムスタンプは同じになる。
これによって、事前予測ができるようになる。

![スクリーンショット 2022-12-03 14.15.03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/451854/8c445de5-2ee6-5a96-a7c6-a993e3650056.png)

### 説明
ブロック難易度＋タイムスタンプのハッシュ値でランダム数生成、ランダム性はありますか、実際は予測される可能性がある
![スクリーンショット 2022-12-03 14.14.04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/451854/585fb469-3521-f721-6d1b-6405cab8443b.png)
![スクリーンショット 2022-12-03 14.15.03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/451854/8c445de5-2ee6-5a96-a7c6-a993e3650056.png)

### サービス拒否攻撃 - 結果
#### 損失
・ロジックによって、スマコン内の残高が取られる可能性があります
#### 対策
・より安全なランダム数生成方法を使う
・ランダム数生成のサービスなどを使う

## アクセス修飾子脆弱性
### 今回例になるスマコン
関数内の処理は省略します。
問題のところは簡単で、_transferのところ、本来privateの方が正しいのだが、publicになっている。これによって外部から呼び出しができ、お金が取られる。
![2022-12-03 23.15のイメージ.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/451854/b8cf003e-5e10-c329-6cb8-140cb51698c7.jpeg)

### アクセス修飾子脆弱性
#### 損失
Transferなど、本来外部呼び出ししちゃいけない関数を呼び出しされて。財産の損失になる。
#### 対策
正しいアクセス修飾子を使うこと

# 最後に
#### スマートコントラクトは実際の「資産」を扱っているので、よりセキュリティを重視しないといけない。
#### 対策は色々あります。外部監査やライブラリーを使うこともあり。（もちろん外部に頼めるもリスクあります）
#### 重要なのはセキュリティを意識してスマコンを書くこと。
#### そして、正式デプロイする前さらにチェックすること。