ホストレベルセキュリティの総仕上げ
第2回 ホストレベルセキュリティの総仕上げ今回は、前回から行っているホストレベルのセキュリティ対策を完成させる。Linuxでファイアウォールを構築するには、まずホストレベルのセキュリティが重要になる。セキュリティホールだらけのファイアウォールなど何の役にも立たないからだ。
サービスのアクセス制御
前回に続き、ホストレベルのセキュリティ対策を行います。セキュリティ対策に「絶対」というものはありません。可能な限りの対策を施しましょう。
デフォルトで起動されるすべてのサービスに制限なくアクセスさせるのは危険です。サービスについては、特定のネットワークあるいはホストからのアクセスのみを許可するようにすべきです。例えば、メンテナンス用にtelnetを使うのであれば、パスワードが適切に設定されていたとしてもアクセスは制御する必要があります。
そこで、アクセス制御の方法を説明します。アクセス制御には、xinetdのみで行う方法と、TCP_Wrapperを併用する方法の2種類があります。それぞれについて見ていきましょう。
■xinetdでのアクセス制御
Red Hat Linux 7.1Jは、xinetdを採用しています。前回、xinetd自身にアクセス制御機能があると説明しました。ここでは、その具体的な設定方法を紹介します。
Red Hat Linux 7.1Jのxinetdは、/etc/xinetd.d以下にサービスごとに設定ファイルを用意します。アクセス制御を行う際は、制御したいサービスのファイルに制御条件を追加します。
only_from = 192.168.0.0/24 |
only_fromというパラメータは、アクセスを許可するネットワークあるいはホストを指定します。上記の設定は、「192.168.0.0/24からのアクセスのみを許可」することを意味します。「特定のホスト、ネットワークからの接続を拒否」するにはno_accessというパラメータを使います。192.168.1.1というホストからの接続を拒否するなら、
no_access = 192.168.1.1 |
とします。
/etc/xinetd.d/telnetのサンプルファイルを以下に挙げるので、参考にしてください。
service telnet |
disable | サービスを無効化:yes 無効化しない:no |
protocol | プロトコル:/etc/protocolsのプロトコルを指定 |
socket_type | ソケットタイプ:stream(TCP)、dgram(UDP)、rawなど |
wait | 単一のスレッドとする:yes 単一のスレッドとはしない:no |
user | telnetdを起動するユーザー名 |
server | サービス:サービスを実行するプログラム名(絶対パス) |
only_from | 接続を許可するネットワークアドレス |
表1 各パラメータの説明(一部) |
コラム:xinetdでアクセスログを取る方法 | |
不審なアクセスの有無などを監視できるように、アクセスログを取得しておきましょう。そのためには、/etc/xinetd.confを以下のように修正します。
変更後、xinetdを再起動してください。 |
■TCP_Wrapperを用いたアクセス制御
telnetサービスがxinetdやinetdを介して呼び出されることは前回説明しました。xinetdあるいはinetdから呼び出されたとき、tcpdが介入して接続の許可/不許可を判断し、許可であればtelnetサービスが起動されます。不許可であれば接続を拒否します。
TCP_Wrapperの設定は、hosts.allow、hosts.denyという2つのファイルに記述されています。これらのファイルを編集することで設定を変更します。
以下では、例として次のような方針で設定を編集します。
まず、viなどを使って/etc/hosts.allowファイルを編集します。
# vi /etc/hosts.allow |
/etc/hosts.allowはアクセスを許可する条件を指定します。次の2行を追加します。
in.telnetd : 192.168.0.0/255.255.255.0 |
これに伴い、/etc/inetd.confファイル(inetdの場合)、/etc/xinetd.dディレクトリ内のtelnet、ftpファイル(xinetdの場合)を変更する必要があります。
●xinetdの場合
telnet、ftpファイルそれぞれのserverの行を次のように修正します。
server =
/sbin/tcpd |
さらに、次の2行を追加します。
flags =
REUSE NAMEINARGS |
telnetファイル |
flags =
REUSE NAMEINARGS |
ftpファイル |
●inetdの場合
inetdの場合は、/etc/inetd.confを以下のように修正します。
telnet stream tcp nowait root /sbin/in.telnetd in.telnetd |
↓
|
telnet stream tcp nowait root /sbin/tcpd /sbin/in.telnetd |
FTPの行も同様に修正します。
次に/etc/hosts.denyの設定です。このファイルは、アクセスを拒否する条件を指定します。
# vi /etc/hosts.deny |
/etc/hosts.denyでは、あらゆるネットワーク/ホストからの接続を拒否するため、次の2行を追加します(編注)。
in.telnetd : ALL |
編注:/etc/hosts.allowと/etc/hosts.denyでは、/etc/hosts.allowの方が優先度は高い。よって、まず/etc/hosts.denyで全サービスへのアクセスをALL(全ホスト/ネットワーク)で拒否し、/etc/hosts.allowで許可するホスト/ネットワークのみを指定するのがセオリーとなる。 |
コラム:TCP_Wrapperのログ取得法 | |||
TCP_Wrapperでログを取りたい場合は以下の作業を行います。まず、TCP_Wrapperインストール時にMakefileを編集し、FACILITYの行を次のように変更します。
さらに、/etc/syslog.confを編集します。
touchコマンドを使い、/var/log/tcp_wrapper.logファイルを作成します。
最後にsyslogにハングアップシグナルを送ります。 |
ipchainsによるパケットフィルタリング
Linuxには、パケットフィルタリング機能としてipchainsという実装があります。これは、kernel 2.2系以降に対応しているものです。Red Hat Linux 7.1Jはkernelは2.4系であり、ipchainsとは別にkernel 2.4系に対応しているiptablesという実装もあるのですが、今回はipchainsを用いたパケットフィルタリングについて説明します。iptablesを使うにはkernelの再構築が必要になりますが、ipchainsはそのまま使えるので採用しました。iptablesを使うためのkernelの再構築については、別の機会に説明させていただきます。
■フィルタリングルールの設計
まず、最初に行うのはルールを考えることです。これは、設定前に十分に考える必要があります。ルールの検討を怠ると思ったよりも甘い設定になってしまったり、逆に制限が強すぎて思いどおりにサービスを提供できなくなってしまいます。
どこからのアクセスを許可するかなどを決めるとき、まずは必要なものを紙に書き出しましょう。その後、ネットワークフロー図に起こしましょう。図にすると分かりやすくなります。
まずは、現在のルールを確認しましょう。現在のルールの確認は以下のようにします。
# /sbin/ipchains -L -n |
ipchainsコマンドのオプションについては、man ipchainsを参照してください。
■フィルタリングスクリプトの作成
ipchainsはコマンドベースで設定します。ipchainsの設定方法についてある程度理解できたらスクリプトを作成しましょう。1つ1つのルールを設定するのに毎回コマンドを実行するのは大変ですし、人為的なミスが発生する可能性も高くなります。
以下に簡単なスクリプト(/usr/local/bin/packetfilter)の例を挙げておくので参考にしてください。例では、対象となるサーバをSMTPサーバとしています。そして、次のような方針で設計されています。
注:第三者による不正中継を禁止する設定などは、アプリケーション(SMTPサーバ)で行ってください。 |
#!/bin/sh |
このスクリプトを/usr/local/bin/packetfilterとして保存したら、スクリプトに実行権限を与えて実行します。
# chmod +x /usr/local/bin/packetfilter |
現在のルールを確認し、実際に設計どおりの設定になっているか確認してください。
# /sbin/ipchains -L -n |
ルールがきちんと設定されていたら、設定を保存しましょう。
# /sbin/ipchains-save |
以上でipchainsの設定作業は終わりです。これはあくまでも設定例ですので、環境に合わせて修正してください。
■フィルタリングの動作確認
設定作業が終わったらパケットフィルタリングの確認を行います。nmapとnetcatというプログラムを使って確認してみます。
MAINTHOST(192.168.1.100)からテストを行うと仮定します。このホストからは、22/TCP、25/TCPの2つのポートが空いているように見えるはずです。実際にサービスを提供しているポートが22/TCPと25/TCPしかなければ完全なテストとはいえません。ほかにもサービスを提供しているポートが存在し、かつそのポートがフィルタリングされることを確認したいからです。そこで、netcatを使います。
netcatでTCPの1000番ポートをLISTENさせます。
# netcat -l -p 1000 & |
netstatコマンドを使って確認します。
# netstat -ant |
この状態で、nmapを使ってポートスキャンを実行します。
# nmap -sT 192.168.0.1 |
上記のような結果を得ることができれば、フィルタリングは成功です。
コラム:ipchainsのログを取る方法 | |||
ipchainsでは、-lオプションを付けることでログを取得できます。ipchainsのルールを設定するスクリプトを編集します。ここではsshに関するルールを例にします。
次に、/etc/syslog.confを修正します。
touchコマンドを使って、ログ用のファイルを作成します。
最後に、syslogにハングアップシグナルを送ります。 |
ファイルシステムに関するセキュリティ対策
ホスト上には、プログラムを実行するファイルや設定ファイルなど、多くのファイルが存在します。これらの中には、第三者に見せてはいけない重要なファイルも多数あります。ファイルのパーミッションが適切に設定されていないと、これらのファイルが読まれてしまったり、書き換えられてしまいます。
すべてのユーザーに対して、すべてのファイルの読み出しや書き込みを許可する必要はありません。環境に合わせて適切なパーミッションを設定しましょう。
■ファイルのパーミッションとは
最初に、ファイルのパーミッションとは何かについて簡単に説明します。試しに、次のコマンドを実行してみてください。
# ls -l test |
注:testはファイル名 |
先頭の1文字を除いたrwxrw-r--がこのファイルのパーミッションを示しています。パーミッションとは、ファイルに対するアクセスの種類を示すビット列です。
最初の3文字は所有者のアクセス権、次の3文字が所有グループのアクセス権、最後の3文字がそのほかのユーザーのアクセス権を示しています。つまり、合計9文字でファイルのアクセス権が表現されているのです。
r、w、x、-には次のような意味があります。
r | 読み取り権 | |
w | 書き込み権 | |
x | 実行権 | |
- | 権限なし | |
表2 パーミッションの文字の意味 |
rwxrw-r--では、次のようなアクセス権があることを意味します。
ログファイルや各種アプリケーションの設定ファイルに、一般ユーザーの書き込み権限を与える必要はありません。もし書き込み権があるなら、パーミッションを変更してください。この作業には、chmodコマンドを使います。
chmodコマンドを使うためには、アクセス権の指定方法を知る必要があります。アクセス権を設定するには、演算子を使う方法と8進数を用いる方法があります。
演算子
|
||
+ | アクセス権を追加 | |
- | アクセス権を削除 | |
= | アクセス権を割り当てる | |
文字
|
||
u | ファイルの所有者 | |
g | ファイルの所有グループ | |
o | そのほかのユーザー | |
8進数
|
||
0 | アクセス権なし | |
1 | 実行 | |
2 | 書き込み | |
3 | 実行、書き込み | |
4 | 読み取り | |
5 | 実行、読み取り | |
6 | 書き込み、読み取り | |
7 | 実行、書き込み、読み取り | |
表3 chmodコマンドの引数 |
ファイルtestの所有グループから書き込み権を削除するようにパーミッションを変更するには、以下のようにします。
# chmod g-w test |
今度は、以下の2つの条件を満たすようにパーミッションを変更する方法です。
# chmod 644 test |
これまでは、ファイルtestのパーミッション部分についてのみを解説していて、-rwxrw-r--の先頭の文字には触れていませんでした。しかし、もちろん先頭の文字にも意味があります。先頭の文字は、ファイルなのかディレクトリなのかを表しています。ここに使われる文字には、以下のような意味があります。
- | ファイル | |
b | ブロック特殊ファイル | |
c | キャラクタ特殊ファイル | |
d | ディレクトリ | |
l | シンボリックリンクファイル | |
表4 先頭文字の意味 |
■SUID/SGIDファイルの意味と危険性
ファイルのパーミッションに「s」という文字が付いているファイルが存在します。これはSUID、SGIDされたファイルであることを意味します。例を見てみましょう。
# ls -l /bin/ping |
これは、所有者rootにSUIDされたファイルであることを意味します。
# ls -l /usr/bin/man |
これは、所有グループmanにSGIDされたファイルであることを意味します。
SUID/SGIDが設定されているファイルは潜在的な危険性を持っています。SUID/SGIDが設定されたファイルは、所有者以外のアカウントで実行されても所有者/所有グループが実行したことになります。つまり、SUID rootが設定されているファイルは、一般ユーザーでもrootとして実行したのと同じになります。これはセキュリティホールとなる可能性があります。
SUID/SGIDされているからといって、必ずしも変更しなければならないというわけではありません。しかしながら、SUIDされたファイルが新たにできていないかを定期的に確認することをお勧めします。SUID/SGIDが設定されたファイルを見つけるには、以下のコマンドを実行します。なお、SUIDとSGIDを8進数で表すと、それぞれ4000と2000になります。
# find / -perm +4000 |
SUIDの場合 |
# find / -perm +2000 |
SGIDの場合 |
SUID/SGIDチェック用のスクリプトを作成し、cronに登録して定期的に確認するようにしましょう。新たにファイルが見つかったら、管理者に通知するような仕組みにしておくと便利です。同様に、.rhostsなどができていないかどうかも確認した方がいいでしょう。
コラム:sudoによる制限の活用 | ||||
sudoを使用することで、実行に高い権限が必要なプログラムを特定のユーザーのみが使用するように制限できます。sudoはログに残すことが可能なので、どのユーザーがsudoコマンドを使ってコマンドを実行したかを監査することができます。 例として、ユーザーuserのみがpingを実行できるように設定します(rootは当然実行できます)。 まず、pingのSUIDを外します。
/etc/sudoersを編集します。編集にはvisudoコマンドを使います。
/etc/sudoersに以下の2行を追加します。
touchコマンドで、sudo用ログファイル/var/log/sudo.logを作成します。
|
■umask値によるデフォルトパーミッション
Red Hat Linux 7.1Jで新規にファイルを作成すると、デフォルトのパーミッションは一般ユーザーの場合が664、rootの場合が644になります。これは、touchコマンドで空のファイルを作成することで確認できます。
$ touch test1 |
デフォルトのパーミッションはもっと厳しく設定しましょう。umask値を設定すると、ファイルのデフォルトパーミッションを決めることができます。
umask値は、「666から与えたいパーミッションを引いた値」を指定します。rootアカウントで作成したファイルには、rootアカウントのみに書き込み、読み取り権を与えるべきでしょう。つまり、デフォルトのパーミッションを「600」にするわけです。すると、
666−600=066 |
となり、umask値は066になります。
Red Hat Linux 7.1Jでは、/etc/profileでumask値を設定します。viなどで/etc/profileを開き、下記のようにumask値を修正してください(編注)。
ulimit -S -c 1000000 > /dev/null
2>&1 |
編注:一般的なUNIXの一般ユーザーumaskは022だが、Red HatではUPG(User
Private Groups)により002としている。UPGについては、以下のURLを参照。 http://www.redhat.com/docs/manuals/linux/RHL-7.1-Manual/ref-guide/s1-users-groups-private-groups.html |
アカウント(シェルはbashとする)が複数存在し、アカウントごとにumask値を設定したい場合は、各アカウントのホームディレクトリにある.bash_profileの最後に以下の1行を追加してください。
# vi /root/.bash_profile |
注:導入したアプリケーションのログを取り、そのログをローテーションさせているのであれば、スクリプト内にumask値を設定するか、新しく生成されるログファイルのパーミッションをrootのみが読み書きできるように設定してください。 |
◆
以上で、ホストレベルのセキュリティ対策の解説は終わりです。しかしながら、これがすべてというわけではありません。セキュリティ対策に「絶対」や「終わり」はありません。いかにそれらに近づけるかがとても重要です。
今回設定方法を紹介したxinetdは、すでに不具合が発見されています。繰り返しますが、最新のものを導入してください。しかしながら、最新だからといって必ずしも不具合がないとはいえませんし、しかるべき設定を行ったからといって絶対に安全とはいえません。セキュリティ情報を常に追いかけ、情報収集を行うこともセキュリティ対策の1つといえるのではないかと思います。