sshのconfigファイルのpermissionは600にしないといけない？理由を調査

## 背景

* sshでサーバーに接続したときに「そういえばconfigファイルの権限が600にしたら読み取れるって話だけど，あれはなんでなんだろ？」と疑問に

## 調査方法

* OpenSSHのGitHubリポジトリをcloneしてコールドリーディング
    * https://github.com/openssh/openssh-portable
* configファイルを読み取っている場所を探してどのような判定がされているか見てみる

## 調査

### configファイルを読みっ取っている場所特定

* configファイルは手元のPCでは`ホームディレクトリ/.ssh/config`に配置してあるので，VSCodeの検索欄で`config`で検索
* 予想はしていましたが，結果は大量に…

<img width="500" alt="スクリーンショット 2024-03-09 133052.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3724444/668bd6c6-2c28-2952-a8d3-99de761ccaa1.png">

* `config file`に変えたかなり減った

<img width="500" alt="スクリーンショット 2024-03-09 135013.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3724444/220bfb3d-1955-ddd6-7347-ab3ee916b4b9.png">

* しかも`check permissions on config file`！ドンピシャ！
    * ファイル名も`readconf.h`

<img width="500" alt="スクリーンショット 2024-03-09 135116.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3724444/3403d5ac-6e7a-3b3c-8d02-00b620535f35.png">

* ファイルを開いて見た感じ，ファイルのパーミッションチェックをするかどうかのフラグに見える

```c++
...
#define SESSION_TYPE_NONE	0
#define SESSION_TYPE_SUBSYSTEM	1
#define SESSION_TYPE_DEFAULT	2

#define SSHCONF_CHECKPERM	1  /* check permissions on config file */
#define SSHCONF_USERCONF	2  /* user provided config file not system */
#define SSHCONF_FINAL		4  /* Final pass over config, after canon. */
#define SSHCONF_NEVERMATCH	8  /* Match/Host never matches; internal only */
...
```

* 実装は`readconf.c`っぽい
* 先程の`SSHCONF_CHECKPERM`でファイル内検索
* １件目
    * `read_config_file_depth()`という関数の引数で使われている
    * パーミッションチェックのような処理はなさそう

```c++
for (i = 0; i < gl.gl_pathc; i++) {
    debug3("%.200s line %d: Including file %s "
        "depth %d%s", filename, linenum,
        gl.gl_pathv[i], depth,
        oactive ? "" : " (parse only)");
    r = read_config_file_depth(gl.gl_pathv[i],
        pw, host, original_host, options,
        flags | SSHCONF_CHECKPERM | // ここ
        (oactive ? 0 : SSHCONF_NEVERMATCH),
        activep, want_final_pass, depth + 1);
...
```

* ２件目
    * 先程の`read_config_file_depth()`内に存在
    * パーミッションチェック処理は`(sb.st_mode & 022) != 0`の部分！ここだ！

```c++
if (flags & SSHCONF_CHECKPERM) { // ここ
    struct stat sb;

    if (fstat(fileno(f), &sb) == -1)
        fatal("fstat %s: %s", filename, strerror(errno));
    if (((sb.st_uid != 0 && sb.st_uid != getuid()) ||
        (sb.st_mode & 022) != 0)) // パーミッションチェック
        fatal("Bad owner or permissions on %s", filename);
}
...
```

### パーミッションの判定処理で何をしているのか

* 判定処理の部分

```c++
(sb.st_mode & 022) != 0
```

* `sb.st_mode`は，ファイルのパーミッション情報
    * [ファイルの状態を取得する](https://www.c-lang.net/stat/index.html)
* ファイルのパーミッション情報と022のビット演算を行い，結果が0になればOK
* ってことは，600以外でもいけるんじゃ？

### 試す

* https://yanohirota.com/bitwise-operator/

|ファイルパーミッション|結果|
|--:|--:|
|640|OK|
|604|OK|
|600|OK|
|660|NG|
|620|NG|
|602|NG|

* 結果として，ユーザー以外に書き込みがあるとNG

### SSHのconfigファイルのベストプラクティス

* 追加調査でconfigファイルについてのベストプラクティスを発見
    * https://ja.linux-console.net/?p=16070
> ベスト プラクティスでは、デフォルトの権限を 664 または 600 のままにし、所有者のみが読み取りおよび書き込み権限 (rw) を持つようにすることをお勧めします。こうすることで、ファイルは権限のないユーザーによる変更から安全に保たれます。

## 結論

* sshのconfigファイルのパーミッションは600じゃなくてOK
* 所有者のみが読み取り・書き込みができるようにするのが望ましい
* 普段使っているツールのコードを読むとおもしろい発見があったりする