とりあえずの記録

はじめは同学科の人向けのナレッジまとめでした

はじめてのWebサーバ構築 - [オプション]セキュリティコース

まえがき

この記事は,Google Developer Student Clubs - National Institute of Technology, Kumamoto College2022/12/22に開催したイベント資料のアーカイブです.

オプション講座 - セキュリティコース

はじめに

本講座では,基礎講座で製作したWebサーバをよりセキュアにするためにはどうするとよいかを示します.
注) 基礎講座・・・Raspberry Pi にNginxをインストールし,起動するまでを実施したものです.

パッケージの更新・自動化

ソフトウェアのアップデート

基礎講座でWebサーバ"Nginx"をインストールして用いたように,OSの中では様々なソフトウェアが動作しています.
これらのソフトウェアは,単なる機能追加・改善のほか,脆弱性に対処するためなどの目的で日々新たなバージョンが公開されます.
まずは実際にアップデートをかけてみましょう.

  1. はじめに,各ソフトウェアについて最新の情報を取得します.
sudo apt update
  1. 1.で得た情報をもとに,新たなバージョンが配信されているソフトウェアをアップデートします.
    初回あるいは久しぶりに実行する場合,たくさんのソフトウェアについて更新が行われるため相応の時間を要します.
sudo apt upgrade -y

これでアップデートが完了しました.

アップデートの自動化

既知の脆弱性を悪用されないためには,できるだけ速やかにアップデートを適用する必要があります.
しかし,サーバ管理者が24時間365日常に見張り続けることは現実的ではありません.
そこで,アップデートを自動的に実施するように設定してみましょう.

  1. まずは自動アップデート用のパッケージをインストールします.
sudo apt install unattended-upgrades -y
  1. Raspberry Pi 用の設定に書き換えます.
    以下のコマンドで,設定ファイルをnanoというエディタを使って開きます.
    (ご存じの方は,vi/vim/emacs/edなどをご利用いただいても構いません.)
sudo nano /etc/apt/apt.conf.d/50unattended-upgrades

こういった行がありますので,

//      "origin=Debian,codename=${distro_codename}-updates";
//      "origin=Debian,codename=${distro_codename}-proposed-updates";
        "origin=Debian,codename=${distro_codename},label=Debian";
        "origin=Debian,codename=${distro_codename},label=Debian-Security";
        "origin=Debian,codename=${distro_codename}-security,label=Debian-Security";

以下のように書き換えてください.

//      "origin=Debian,codename=${distro_codename}-updates";
//      "origin=Debian,codename=${distro_codename}-proposed-updates";
//      "origin=Debian,codename=${distro_codename},label=Debian";
//      "origin=Debian,codename=${distro_codename},label=Debian-Security";
//      "origin=Debian,codename=${distro_codename}-security,label=Debian-Security";
        "o=*,a=*";

編集を終えたら,Ctrlキーを押しながらXを押します.
すると保存するのかと聞かれますので,Yを押してEnterキーを押してください.
これでnanoエディタが終了し,もとのシェルの画面に戻ったはずです.

以上で自動アップデートの設定は終了です.

補足

ソフトウェアをアップデートすると,何らかの事情でシステムがうまく動作しなくなることも稀にあります.
よって,手動でのアップデート前に悪意のあるユーザからゼロデイ攻撃を受けるリスクと, 自動アップデート時に何らかの不具合が発生して正常な動作を停止するリスクを天秤にかけて比較検討する必要があります.

例えば,金融系・医療系などのミッションクリティカルなシステムの場合,どんな事情であれ停止することは許されません.
アップデートの前に試験環境で動作を確認し,問題がなかった場合に本番環境へ手動でアップデートを適用するといった運用が想定されます.
動作を確認するためにアップデートの適用が遅れますので,その分を他の対策によって攻撃から防御できるように設計されています.

一方で,我々一般ユーザが使用するシステムの場合,バージョンアップが提供されるたびに逐一試験環境で動作を確認することは現実的ではありません.
よって自動アップデートを有効にしますが,その代わり万が一アップデート時に不具合が発生したときのため,定期的にバックアップをとっておくことが大変重要となります.

参考:「3-2-1バックアップ

SSHポートの変更

ポートとは

1台のサーバであっても,利用する"ポート"を使い分けることで複数の通信を同時に捌くことができます.
TCP/IPにおいて,0番から65535番までの65536(2の16乗)個のポートを利用できると規定されています.

このうち,著名なサービスにおいて「このサービスはこのポートを利用します」と定められているものがあり,このうち0~1023までのものをウェルノウン(well-known)ポートと呼びます.
例) http:80,https:443,DNS:53,SSH:22

以下のコマンドで,ウェルノウンポートをはじめとするさまざまなポートについての情報を得ることができます.

cat /etc/services

ただし,記載されている全てのサービスが自分のサーバで動いているわけではない点に注意が必要です.
あくまで,IANAという組織に「このポートは私たちが開発するサービスで利用します」と届け出られたものの一覧です.

あえてウェルノウンポートとは別のポートを使う

通常は標準の値を使用すればよいのですが,我々にとって不都合な場面もあります.

例えば,SSH
他人のサーバを操ってやろうと画策する攻撃者にとって,SSHは格好のアクセス方法です.
よって,不特定のサーバを対象とする攻撃者はとりあえず22番への攻撃を行います.

そこで我々が22番でないポートでSSHを利用しているとどうなるでしょうか.
攻撃者は,0から65535までのどこのポートでSSHが動いているのか調べる必要が出てきます.
不特定のサーバへの攻撃を試みる攻撃者は,22番のまま利用している他のサーバに目移りしてくれるでしょう.

そういった経緯で,SSHでは標準の22のままではなく,なにか別のポートを利用するように設定することがあります.

sshdの設定

それでは,実際に使用するポートを変更してみることにしましょう.
今回は試しに54723番を利用してみることにします.
以降,操作を誤るとSSH接続ができなくなりますのでよく注意して入力・実行してください.

  1. SSH接続を受け付けるsshdの設定ファイルを編集します.
sudo nano /etc/ssh/sshd_config

上の方にこういった行がありますので,

#Port 22

以下のように書き換えてください.

Port 54723

編集を終えたら,Ctrlキーを押しながらXを押します.
すると保存するのかと聞かれますので,Yを押してEnterキーを押してください.
これでnanoエディタが終了し,もとのシェルの画面に戻ったはずです.

  1. 記述内容に異常がないか確認します.
sudo sshd -t

何も出力されなければOKです.

  1. sshdに設定を読み込ませます.
sudo systemctl reload sshd

これで,次回以降接続する際には54723番を利用することでSSH接続ができるよう設定されました.
(設定適用時,接続中のものについては引き続き22番で通信できます.以降の新規接続は全て54723番で受け付けられます.)

仮にこれまで以下のコマンドで接続していた場合,

ssh user@server.example.com

これからは次のようにポート番号を示した上で接続する必要があります.

ssh -p 54723 user@server.example.com

補足(1)

sshdの設定ファイルを改めて眺めてみます.

sudo cat /etc/ssh/sshd_config

今回編集したPort以外にも,非常に多くの設定項目が存在していることが確認できます.

IPv4によってのみ接続する場合,IPv6による接続を遮断したり,パスワードを用いないより安全な公開鍵認証のみを許可したり,接続試行許容回数を6回から3回に減らしたり,rootによるログインを拒絶したり,...

特にインターネット上からアクセスできる状況では,設定内容をしっかりと精査する必要があります.

補足(2)

今回はPort22 → 54723へダイレクトに変更しました.
しかし,サーバ本体が遠隔地にある環境などでは,接続経路のネットワーク機器において通過させるパケットに制限が設けられており,変更後にアクセスができなくなってしまうことがあります.

このような状況では,

Port 22
Port 54723

のように複数のポートで接続を待ち受けるように設定し,新たなポートでの接続が可能であることを確認した上で,

Port 54723

と変更することで,ポート変更時のトラブルを防ぐことが可能です.
いずれの場合も,systemctl reloadによる設定ファイルの読み込みを忘れないように気をつけてくださいね.

ファイアウォールの利用

ファイアウォールとは

簡単に示すと,「予め許可した通信のみを通過させる仕組み」です.

多くのLinuxでは,iptablesというソフトウェアファイアウォールを使うことができます.
ちょっと扱いにくいので,今回はufwというツールを介して使用します.

ハードウェアファイアウォールとしては,Fortinet社のfortiGateなどが有名です.

ufwの設定

  1. まずはufwをインストールします.
sudo apt install ufw -y
  1. はじめに,ufwが現在有効になっていないことを確認します.
sudo ufw status

Status: inactiveとなっていればOKです.

  1. 全ての接続を拒否する設定を行います.
sudo ufw default deny
  1. 次に,必要なポートへの接続を許可します.
    今回は,SSH用の54723番とhttp(Web)用の80番を開放します.
sudo ufw allow 54723
sudo ufw allow 80

ufwの起動

  1. 起動します.
sudo ufw enable

このとき,「SSH接続が切れる可能性があるがよいか」と尋ねられます.
SSH用のポートは開放したので,yを押してEnterキーを押してください.
(もしSSH接続が終了した場合は,改めて接続しなおしてください.)

  1. 状況を確認します.
sudo ufw status

Status: activeとなっていればOKです.

これで,54723番,80番ポート以外へのアクセスは全て遮断されるようになりました.

おわりに

ソフトウェアアップデートの自動化,SSHポートの変更,ソフトウェアファイアウォールの利用に焦点を絞ってお届けしました.
今回の演習,お楽しみいただけたでしょうか.

セキュリティに関連する,昨今流行りの(?)キーワードをいくつか以下に示します.
もしご興味がありましたら,ぜひ調べてみてください.