FlaskにおけるSECRET_KEYの役割についてざっくり理解する

# SECRET_KEY

### 公式ドキュメント
https://flask.palletsprojects.com/en/2.2.x/config/#SECRET_KEY
> セッションCookieに安全に署名するために使用され、拡張機能またはアプリケーションによるその他のセキュリティ関連のニーズに使用できる秘密鍵。それは長い乱数bytesまたはstr. 

https://study-flask.readthedocs.io/ja/latest/02.html#flaskr-config-py
> データベースの設定と、セッション情報を暗号化するためのキーを設定します。

### 一言で
結論、SECRET_KEYとは

**セッション情報（Cookie）を暗号化する際に使用する秘密鍵（文字列）**

ということですね。この文をちゃんと理解するためには、Cookieについても深く知っておく必要がありそうです。以下でCookieについても今一度確認してみましょう。

# Cookie
https://developer.mozilla.org/ja/docs/Web/HTTP/Cookies
> HTTP Cookie (ウェブ Cookie、ブラウザー Cookie) は、サーバーがユーザーのウェブブラウザーに送信する小さなデータであり、ブラウザーに保存され、その後のリクエストと共に同じサーバーへ返送されます。一般的には、二つのリクエストが同じブラウザーから送信されたものであるかを知るために使用されます。例えば、ユーザーのログイン状態を維持することができます。Cookie は、ステートレスな HTTP プロトコルのためにステートフルな情報を記憶します。

Cookieとはユーザーのログイン状態が記録されたデータのことで、クライアント側（webにアクセスしているスマホやPC）に直接保存されものです。以下のようにChromeの設定や、デベロッパーツールなどからもみることができます。

<table>
<tr>
<td>設定画面</td>
<td><img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/965436/2a6ca181-64aa-24e8-ce82-f84f3d5ab363.png"></td>
</tr>
<tr>
<td>DevTools</td>
<td><img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/965436/ac488c9e-9def-d7b2-0bb5-aba8879242a5.png"></td>
</tr>
</table>

### 保存方法

具体的に何をして保存されるかというと、クライアントがサーバーにアクセスした時にサーバーが以下のレスポンスヘッダーを含めて応答することでクライアントの端末にCookieデータが保存されています。

```
Set-Cookie: <cookie-name>=<cookie-value>
```

したがって、どんな`<cookie-value>`を送るかはサーバー側に委ねられています。

### セッション情報の管理

セッション情報を`<cookie-name>=<cookie-value>`に記述して送信することでセッションを管理するのですが、この実装方式には大きく分けて以下の2種類があります。

- セッションのキー情報のみクライアントのブラウザに送信する
- セッション情報全てをクライアントのブラウザに送信する


https://jp.quora.com/sesshon-wo-angou-ka-suru-kotoni-nan-no-imi-ga-arima-suka-angou-ka-shita-toshite-mo-sono-angou-ka-shita-mono-wo-shi-tte-rikuesuto-shi-te-shima-e-ba-sa-ba-gawa-de-fukugou-shi-te-kureru-node-toori-tte-shimau-to-omoi

> 一つは、Cookie等にセッションのキー情報のみを保存し、セッションの中身はサーバー側で保存する方式です。キーのことをセッションIDと呼び、セッションIDには乱数を使います。この方式は、通常暗号化は用いません。  
もう一つは、Cookieそのものにセッションの値を入れる方式で、CookieStoreなどと呼ばれます。セッションの値は、利用者からも改ざんされるとまずいので、CookieStoreに格納する値は暗号化します。CookieStoreのメリットは、サーバー側で状態を保持する必要がない点で、RESTとの相性がよく、サーバーの負荷分散が容易だという現実的なメリットもあります。

Flaskで作ったアプリケーションは基本的に後者のセッション情報全て送信する方式を採用しているようです。この方式では、利用者が自身のセッション情報を改ざんできてしまう危険性があるため、改ざんを防ぐために暗号化を施す必要があり、この暗号化にSECRET_KEYが使われます。

# セッション情報をいじってみる
セッション情報を改ざんされるといってもピンと来ないため、シンプルな例を用いてセッション情報をいじってみて改ざんという現象のイメージができるようにします。

例えば、以下のようにルーティングが設定されているアプリを考えてみます。

```python
@dev.route("/register/<string:session_id>")
def send_cookie(session_id):
    content = f"session: {session_id}として登録しました"

    response = make_response(content)
    response.set_cookie('session_id', value=session_id)
    return response

@dev.route("/login_mitaina")
def get_cookie():
    session = request.cookies.get('session_id', None)

    if session == 'HogeHoge':
        content = "こんにちは、HogeHogeさん"
        # HogeHogeさん用の処理
    elif session == 'fuga':
        content = "こんにちは、fugaさん"
        # fugaさん用の処理
    else:
        content = "piyopiyo"
    return make_response(content)
```

### HogeHogeとして登録
ブラウザ（Chrome）を使用して↓のような感じでリクエストを送ってみます。
![スクリーンショット 2022-12-25 20.00.44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/965436/6dffbf22-77a3-6440-387a-04ab39d25b6c.png)

その後、`/login_mitaina`へアクセスすると、正しくログインできてそうですね。  
![スクリーンショット 2022-12-24 10.33.13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/965436/5a628298-708b-b62e-99a0-e432aa694322.png)

ここで、Cookieの修正を試してみましょう。
Chromeのデベロッパーツールから確認してみると、`Name: session_id, Value: HogeHoge`としてChromeのCookieに登録されていることが確認できます。このデベロッパーツールからCookieを修正することができて、Valueのところをダブルクリックすると値を自由に編集できます。今回は`fuga`に変更してみました。

|修正前|修正後|
|---|---|
|![スクリーンショット 2022-12-24 11.19.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/965436/c61b7031-a0be-190e-7663-86be2c84a8ea.png)|![スクリーンショット 2022-12-24 11.20.49.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/965436/4e024538-aa61-2329-f474-827820cd9b15.png)|

再度`/login_mitaina`へアクセスすると、fugaさんとして認識されてしまっていることが確認できます。ちょっと改ざんのイメージが付きましたね。   
![スクリーンショット 2022-12-24 10.43.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/965436/79539fc9-b242-cd83-f7d5-84732c343126.png)

### セッション情報暗号化の利点
上記の例では`session_id`を想定しましたが、`session_id`以外でも例えばECサイトであればカート内の商品数とか、クーポンの保有数とか、そのあたりがCookieに`cart_item: 3, coupon_num: 4`とかで保存されてたら`coupon_num: 1000`とかにいじりたくなっちゃいますよね（←良くない）

仮にこれが`SECRET_KEY`で暗号化されていて、暗号化前は`coupon_num: 4`であったものが`Xalo88f_feem: YYYfjkoooo`みたいな文字列でブラウザのCookieに保存されていたら簡単には改ざんできなさそうだなと想像が付きます。
`SECRET_KEY`が漏れてしまった場合、`Xalo88f_feem: YYYfjkoooo`→`coupon_num: 4`に復号することが可能になりセッション情報の改ざんをされる恐れが出てくるため、やはり`SECRET_KEY`は慎重に管理する必要がありますね。