データの安全性について考える (2)

# システムセキュリティの重要性

[昨日](http://qiita.com/ynakayama/items/74096212b8177234be8a)は重要な研究データの保全性について考えましたが、引き続きみんな大好きセキュリティの話です。そもそも物理攻撃の対策として暗号化の対策を施しても、稼働中のシステムに侵入されたらデータはメモリ上に非暗号化状態で展開されていますし、操作権限を奪取されたらひとたまりもありません。そこでいわゆる一般的なネットワーク上のシステムのセキュリティが必要になってきます。

## 基本的なセキュリティ設定

一般論としてインターネットなど無防備な場所にサーバーを用意する場合、まずは基本的なセキュリティ設定が必要になります。主に次の通りになります。

インターネットに公開するサーバーの基本的なセキュリティ設定
http://blog.id774.net/post/2014/01/29/457/

### 管理作業を限定する (sudo)

/etc/sudoers で sudo を利用可能なグループを定義します。

```bash
Defaults    env_reset
# sudo 実行時のパス
Defaults    secure_path="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
Defaults    !lecture,tty_tickets,!fqdn
# password 再入力を免除する時間 (分)
Defaults    timestamp_timeout = 180
# プロンプトをカスタマイズして誰のパスワードでどんな権限を行使するのかわかりやすくする
Defaults    passprompt = "[sudo] <%U@%h> Enter %u's password: "

# パスワードを入力しなくても利用できるコマンドの一覧を定義する
Cmnd_Alias ADMIN = /sbin/shutdown
Cmnd_Alias NETWORK = /etc/init.d/networking

root    ALL=(ALL) ALL
# admin グループに属していれば sudo 利用可能に
%admin ALL=(ALL) ALL
# これらのコマンドはパスワード無しでもそのまま sudo で使える
%admin ALL=(root) NOPASSWD: ADMIN, NETWORK
```

また su コマンドによる root への昇格を制限します。これは /etc/pam.d/su で次のように定義することで wheel グループに属していない限り su が使えなくなります。

```bash
auth       required   pam_wheel.so
```

sudoers なら管理作業には困らないはずなので、余計な抜け穴は塞いでおいたほうがいいでしょう。

また /etc/securetty は root で対話的にログインできる端末の一覧を定義します。このファイルを 0 バイトの空のファイルにすることで、対話的に root ログインすることができなくなります。直接 root でログインする必要があるのはリカバリーモードの時くらいですので、このファイルもあわせてカスタマイズしておきましょう。

### 認証方式を強固にする (ssh)

まさかパスワード認証を有効にしてインターネット上に計算機を公開している人は居ないとは思いますが、少なくともインターネットのような無防備な場所に公開するホストではパスワード認証を無効化しなければなりません。次のように /etc/ssh/sshd_config を設定します。

```bash
PasswordAuthentication no # パスワード認証無効化
ChallengeResponseAuthentication no
PubkeyAuthentication yes # ssh 公開鍵認証を有効化
PermitRootLogin no # または without-password 等
Port 11111 # ポート番号をランダムな数値に変更
```

ポート番号については、接続する側は ~/.ssh/config などでホストに対応したポート番号をあらかじめ定義することができます。ですので接続する側のホストから見れば人間が頭で覚えておく必要はありませんから乱数で番号を決定してしまうのが良いでしょう。

また、さらなるセキュリティを考慮するなら ssh 公開鍵認証とパスワード認証のニ段階で認証するとさらに堅牢です。これは踏み台となるサーバーを公開鍵認証にしておいて、さらにそこからしか接続できない設定にしたパスワード認証のホストを奥に設置すれば実現できます。

![1.png](https://qiita-image-store.s3.amazonaws.com/0/38501/b30c11d8-fc35-3e1f-5a65-ba1bc34b7299.png)

以前も [OpenSSL](http://ja.wikipedia.org/wiki/%E3%83%8F%E3%83%BC%E3%83%88%E3%83%96%E3%83%AA%E3%83%BC%E3%83%89) に致命的な脆弱性が発見され騒ぎになりましたが、そういう話をするならば[以前にも発見されて騒ぎになった](http://www.jpcert.or.jp/at/2008/at080008.txt)ようにいつ OpenSSH に脆弱性が見つかるともわかりません。ですから鍵認証一枚のみの城塞であれば突破されないとも限りません。

そこで上図のようにニ段階に別の認証方式を採用し、内部の計算機にデータを置いておけば最悪の事態を寸前で回避して少しでもリスクを低減することができます。

これと組み合わせて、後述する iptables によってパスワード認証の試行回数等に制限を加えておけば、一般的にインターネットに公開されているサーバーと比較してもかなり強固な要塞が完成することになります。

もちろんパスワード認証のパスフレーズは強力なものを利用し鍵認証は無効化、パスワード試行三回でキックアウトするなどの備えをしておきます。また例えば外からの最初の鍵認証が成功した時点で管理者の携帯にメールするなど常に侵入を検知する仕組みと組み合わせることが大前提です。

なお多段 ssh の認証を簡略化する方法については[こちら](http://qiita.com/ynakayama/items/92fa443fe5926e17d8dc)をご覧ください。

### パケットフィルタリングをする (iptables)

Linux カーネルに備わっている Netfilter の機能を操作します。 iptables といえばポートを閉じる機能が有名ですが、それだけではなく短時間に送信された過剰なパケットや不正なパケットを破棄したり、過度な認証要求をシャットアウトするなどの機能も備わっています。

特に有用なものは前述したニ段階認証では必須となる、一定時間に制限を超えた認証試行があったホストをキックアウトする機能です。

```bash
SSH_PORT=11111
IPTABLES=/sbin/iptables

# ssh のポートに 10 分 (= 600 秒) 以内に 3 回を超える認証試行があった場合、ログに記録してキックアウトする
$IPTABLES -A INPUT -p tcp --dport $SSH_PORT -m state --state NEW -m recent --set --name SSH
$IPTABLES -A INPUT -p tcp --dport $SSH_PORT -m state --state NEW -m recent --update --seconds 600 --hitcount 3 --rttl --name SSH -j LOG --log-prefix 'SSH attack: '
$IPTABLES -A INPUT -p tcp --dport $SSH_PORT -m state --state NEW -m recent --update --seconds 600 --hitcount 3 --rttl
```

## 未知の脆弱性に備える

基本的なセキュリティ設定をきちんとしても、未知の脆弱性がいちはやく利用された場合にシステムが脅威に脅かされる可能性は残ります。データの安全性を確保するためには、こういったリスクを少しでも低減する必要性があります。

### 自動セキュリティアップデートをする

Debian 系ディストリビューションなら [cron-apt](https://packages.debian.org/stable/cron-apt) 、 RHEL またはそのクローンなら [yum-cron](http://man7.org/linux/man-pages/man8/yum-cron.8.html) があります。他にもソリューションがあるでしょう。これらを利用してシステムのセキュリティに発見された脆弱性を自動更新によりパッチ適用します。システムを自動更新しないのはいわば Windows Update を怠っているのと似たようなものですので発見された脆弱性の放置、パッチの適用漏れを防ぐためにも必ず自動化しましょう。

動作中のシステムに自動的な変更を加えるのは賛否両論あるかもしれませんが、安定版なのにパッチの自動更新で壊れるようなディストリビューションはそもそも使うべきではありませんし、セキュリティアップデートで動作しなくなるようなシステムやアプリケーションがあるとしたらそれらの設計を見直すべきです。

### セキュア OS を利用する

[SELinux](http://www.nsa.gov/research/selinux/) は伝統と実績を備えた古くからあるセキュア OS の代表格で、[アメリカ国家安全保障局](http://ja.wikipedia.org/wiki/%E3%82%A2%E3%83%A1%E3%83%AA%E3%82%AB%E5%9B%BD%E5%AE%B6%E5%AE%89%E5%85%A8%E4%BF%9D%E9%9A%9C%E5%B1%80)によって開発された軍事レベルのソリューションです。 Linux カーネルのメインラインにマージ済みであり RHEL クローンのディストリビューションであれば既定でオンになっていますから安心して使うことができます。

#### 恒久的なコンテキストの変更

ファイルやディレクトリのセキュリティコンテキストは semanage で変更ができます。

```bash
# 設定の参照
semanage fcontext -l

# コンテキストの追加 (-a オプション)
sudo semanage fcontext -a -t httpd_sys_content_t "/var/www/presentation/(/.*)?"
# 上記の例では /var/www/presentation に httpd がアクセスするための権限を付与している

# コンテキストの剥奪 (-d オプション)
sudo semanage fcontext -d -t httpd_sys_content_t "/var/www/presentation/(/.*)?"
```

#### コンテキストの復元

semanage で設定した恒久的変更はそのままでは反映されません。 restorecon コマンドはファイルやディレクトリのコンテキストを規定値に戻します。これによって semanage で設定した値が反映されるわけです。

```bash
sudo restorecon /var/www/presentation/ -RF 
```

#### プロセスのドメインを取得する

ps の -Z オプションで参照することが可能です。 SELinux を有効にしたホストでの ps コマンドは -Z を付けると覚えておけば簡単です。

```bash
ps -H auxZwww
```

#### ファイルのコンテキストを表示する

これも同じく ls の -Z オプションで参照できます。

```bash
ls -laZ /var/www/presentation/
```

昨今ではデータ分析結果を Web システムで可視化するといったことが一般的になってきつつありますので、それと同時にいわゆる Web システムに必要とされるセキュリティの配慮が必要になってきます。生半可な Web システムでデータを公開していたら脆弱性や設定ミスにより思わぬデータが漏洩してしまったといった事態は絶対に避けなければなりません。

## まとめ

[前回](http://qiita.com/ynakayama/items/74096212b8177234be8a)から引き続きデータの安全性を確保するためのあれこれについてまとめました。物理攻撃に対しても通信経由での攻撃に対してもこの対策さえしておけば絶対という保証はありませんので、特にセンシティブで重大なデータを扱う計算機においては油断の無いシステムセキュリティ設計が必要です。セキュリティの基礎基盤となる暗号技術も今後将来的に渡って絶対に破られないとは限りませんからアンテナを高く持って情報収集することも大切です。