そこそこセキュアなlinuxサーバーを作る

  • 3035
    いいね
  • 10
    コメント
この記事は最終更新日から1年以上が経過しています。

先日「サーバーのセキュリティ設定がなにすればいいかわからない」と相談をうけまして。
自分も初心者の時どこまでやればいいかわからず手当たりしだいにやって沼に入っていたのを思い出しながら自鯖構築したときのメモを元にまとめてみました。

注意

セキュリティ対策は用途や場合などによって違います。

自分で理解したうえで自己責任でおねがいします。

対象読者

  • Linuxのサーバーを建て慣れていない人
  • Linuxはある程度さわれる人(自分でパッケージを入れたり、サービスを止めたりできる)

ラインナップ

☆は導入の重要度と導入の容易さから個人的偏見からつけた値です。
4つ以上が"最低限やること"だと思ってください。

sshd                       
☆☆☆☆☆  sshポート変更
☆☆☆☆ sshでrootにlogin出来なくする
☆☆☆☆ パスワード認証を切る
☆☆☆ ssh可能ユーザーを限定する
☆☆ sshdのプロトコルを2に限定する
☆☆ 認証時の時間と試行回数を制限する
sshguard,fail2banを導入する
firewall                       
☆☆☆☆☆  使わないポートを閉じる
☆☆☆☆ ip spoofing対策
☆☆☆ port scan対策
ICMPパケットのfilteringやstealth port scan対策
sudo                       
☆☆☆    passpromptを変える
☆☆ セッションタイムアウトの時間を設定する
web(nginx)                       
☆☆☆☆   バージョンを見えなくする
misc                       
☆☆☆☆   不要なサービスを止める
☆☆☆ logwatchを入れる
☆☆ 使わないユーザーをログイン不可にする
umaskを027にする

sshd関連

ほとんどのサーバーはsshでアクセスできるようにsshdを常駐させています。
いわば外部からログインする脳関門のようなものなので重要です。

sshdはかなり奥が深いのでman sshdman sshd_configを読むとたのしめると思います。

☆5 ポート変更

sshのポートは標準でTCP 22番ポートですが、一般的すぎるためbotなどから攻撃がきます
そのため、22番以外のポートに変えるのが一般的です。

代替の番号は予約されているポート(/etc/serviceswikipedia参照)以外を使うのが理想ですが、SMTPやHTTPなど有名なものに被らなければ(自分や他人が使わなければ)なんでもいいと私は思います。

学校や企業などのネットワークでは上流のfirewallなども考慮にいれて決める必要があります。

Port 1234

☆4 sshでrootにlogin出来なくする

rootは本丸なので外から直に触れる場所には置かないほうが良いです。
なので、ssh経由でrootにログインできないようにします。

(sudo権限のある一般ユーザーにsshしてsudo suしてrootになることはできます)

rootはどのサーバーにもあるアカウントなので総当り攻撃される危険性があります。

DebianもArchLinuxもデフォルトがyesなので自分で設定したほうが安心です。

/etc/ssh/sshd_config
PermitRootLogin no

☆4 パスワード認証を切る

パスワード認証が有効では辞書攻撃(dictionary attack)される危険があるので、切れるのであれば切ったほうが安全です。

代替の認証は公開鍵方式の認証があります。
公開鍵方式で自分が入れるように公開鍵を~/.ssh/authorized_keysに登録した上で切らないと閉めだされてしまいますので注意してください。

(ssh-keygenコマンドで秘密鍵を作成し、クライアントの~/.ssh/configに登録すると便利です)

(公開鍵登録はssh-copy-idコマンドを使えば便利に登録できます)

/etc/ssh/sshd_config
PasswordAuthentication no
ChallengeResponseAuthentication no

何らかの理由でパスワード認証をonにしておく場合は、
空パスワードでのloginを不許可にしておきましょう(たぶんデフォルトはnoですが一応)

/etc/ssh/sshd_config
PermitEmptyPasswords no
2014 11/24 22:09追記

ChallengeResponseAuthentication noについて@mimimizuさんからご指摘をいただきました。ありがとうございます。

☆3 ssh可能ユーザーを限定する

sshが可能なユーザーを限定しておくと安心です。AllowUsersはwhiltelist方式ですが、DenyUsersでblacklist方式でもできます。

例えば、Webアプリをweb_appというユーザーの権限で動かす場合、
直接web_appにsshできる必要はないのssh出来ないようにします。
(デプロイを自動化する場合とかは話は別です)

/etc/ssh/sshd_config
AllowUsers hogeuser git
# DenyUsers web_app

☆2 sshdのプロトコルを2にする

sshdのプロトコル1は脆弱性が発見されており「もうサポートしないよ」と言われているため、
なにかしらの理由がない限りプロトコル2を使うべきです。

普通はデフォルト値が2のみのはずですが、古いLinuxディストリビューションでは1,2だったりするため、自分で設定したほうが安心です。

/etc/ssh/sshd_config
Protocol 2

☆2 認証時の時間や試行回数を制限する

コネクションを貼って認証するまでの猶予時間LoginGraceTimeと、試行回数MaxAuthTriesを設定しておきます。

/etc/ssh/sshd_config
LoginGraceTime 30
MaxAuthTries 3

☆1 sshguard, fail2banを導入する

sshguardやfail2banはsshへの総当り攻撃(bruteforce attack)を検知して、
一定時間アクセスを拒否するなどができます。
sshのポート変更をしない場合は導入を検討してください。

☆1の理由は、sshのポート番号を変えポートスキャン対策を行えば、sshのポート番号は攻撃者はわからないため、sshへのbruteforce attackはされにくいであろうという想定のためです。
複数ipからポートスキャンを分散して行えばsshのポートはわかるため絶対にないとは言えないのですが相対的に重要度をさげました。

ここでは紹介にとどめます。

firewall(iptables)

firewallは許可していないポートやプロトコルでのアクセスを拒否したりログをとったりできます。
(余談ですがアドレスの書き換え(NAT)も出来ます。)

firewallもなかなかに奥が深いのです。
firewallの一つであるiptablesに関してはman iptablesman iptables-extensitonsを参照してください。

設定にはネットワークの知識が必須なので、書籍のマスタリングTCP/IPを読んだり自分でネットワークを構築したり業務用ルーターで遊んだりして勉強するのが良いと思います。

systemdでサービスを管理しているときはsystemctl start iptablesするだけでなく、次回の起動時のためにsystemctl enable iptablesをするなどを忘れないでください。

☆5 使わないポートを閉じる

iptablesを使うのであれば、/etc/iptables/iptables.rules(ipv4)と/etc/iptables/ip6tables.rules(ipv6)に設定ファイルがあります。
(ディストリビューションによっては/etc/iptables/rules.v4(Debian)とかだったりするかもしれません。)
ipv6に関してはここでは触れません。

何も考えなければ下みたいな感じでいいと思います。(archlinuxのsimple_firewall.rulesの改変)
Allow HTTP connectionで80番ポートを開けています。
sshできるようにsshのポートも開けておいてください。

/etc/iptables/iptables.rules
*filter
:INPUT DROP [0:0]
:FORWARD DROP [0:0]
:OUTPUT ACCEPT [0:0]
-A INPUT -p icmp -j ACCEPT 
-A INPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT 
-A INPUT -i lo -j ACCEPT 

# Allow HTTP connection(port:80)
-A INPUT -p tcp --dport 80 -j ACCEPT

# Allow SSH connection(port:1234)
-A INPUT -p tcp --dport 1234 -j ACCEPT

-A INPUT -p tcp -j REJECT --reject-with tcp-reset 
-A INPUT -p udp -j REJECT --reject-with icmp-port-unreachable 
-A INPUT -j REJECT --reject-with icmp-proto-unreachable 
COMMIT

☆4 ip spoofing対策

WANに直接つないでいる場合は、プライベートアドレスやブロードキャストアドレスは偽装されていると思われるのでDROPする処理を入れます。

/etc/iptables/iptables.rules
*filter
:INPUT DROP [0:0]
:FORWARD DROP [0:0]
:OUTPUT ACCEPT [0:0]
-A INPUT -p icmp -j ACCEPT 
-A INPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT 
-A INPUT -i lo -j ACCEPT 

# ip spoofing
-A INPUT -s 10.0.0.0/8 -j DROP
-A INPUT -s 172.16.0.0/12 -j DROP
-A INPUT -s 192.168.0.0/16 -j DROP

-A INPUT -d 0.0.0.0/8 -j DROP
-A INPUT -s 127.0.0.0/8 -j DROP
-A INPUT -s 169.254.0.0/16 -j DROP
-A INPUT -s 192.0.2.0/24 -j DROP

# multicast address
-A INPUT -s 224.0.0.0/4 -j DROP

# broadcast address
-A INPUT -d 255.255.255.255 -j DROP

# Allow HTTP connection(port:80)
-A INPUT -p tcp --dport 80 -j ACCEPT

# Allow SSH connection(port:1234)
-A INPUT -p tcp --dport 1234 -j ACCEPT

-A INPUT -p tcp -j REJECT --reject-with tcp-reset 
-A INPUT -p udp -j REJECT --reject-with icmp-port-unreachable 
-A INPUT -j REJECT --reject-with icmp-proto-unreachable 
COMMIT
参考

別の書き方として(iptables match)

iptablesの機能の一つにmatchという機能があり、アドレスタイプを指定して処理をすることが出来ます。ちょっと実験的ですが。
いろんな方々のiptablesをみてもなぜか直でずらずら書いてあるので、なにか理由があって使っていないのか知らないだけなのかわからないため、先の例では書きませんでした。知ってる方がいらしたら教えてください。

/etc/iptables/iptables.rules
-A INPUT -m pkttype --pkt-type broadcast -j DROP
-A INPUT -m pkttype --pkt-type multicast -j DROP
参考

☆3 port scan対策

昔はportsentryを使ったりしていましたが、最近はiptablesでするのがモダン(?)なようです。

port一覧はportsentryを参考にしました。
http://wiki.netbsd.org/nsps/portsentry.conf

/etc/iptables/iptables.rules
# locked for 1day (60*60*24 = 86400 sec)
-A INPUT -m recent --name portscan --rcheck --seconds 86400
-A INPUT -m recent --name portscan --remove

# 以下のポートにアクセスしてきたらportscanとみなす
-A INPUT -p tcp -m multiport --dports 1,7,9,11,15,23,70,79,109,110,111,119,138,138,512,513,514,515,540,635 -m recent --name portscan --set -j DROP
-A INPUT -p udp -m multiport --dports 1,7,9,23,66,67,68,69,111,137,138,161,162,474,513,517,518,635,640,641,666,700 -m recent --name portscan --set -j DROP

別の書き方として(2014/11/27 18:40 追記)

先ほどのやり方だと使わないポートをたくさん書かないといけなかったり、1秒にnパケットきたらのような処理ができないです。
ちょっと考えてみたらもう少し綺麗に書けそうだったので書いてみました。
hashlimitを使ってみました。

/etc/iptables/iptables.v4
# block portscanner(1 day)
-A INPUT -m recent --name portscan --rcheck --seconds 86400 -j DROP
-A INPUT -m recent --name portscan --remove

# ポート開く処理をここに

# portscanner chain
-N portscanner
# register portscanner and log
-A portscanner -m recent --name portscan --set -j LOG --log-prefix "portscan:"
-A portscanner -j DROP

# 10パケット/秒を超えるアクセスがきたらportscan chainに流す(調節すること)
-A INPUT -m hashlimit --hashlimit-name portscan --hashlimit-mode srcip --hashlimit-upto 10/second --hashlimit-burst 10 -j portscanner

できればなにも考えずにpsd macherを使いたいのですがパッチを当てないといけないようなのでこうしました。

参考

☆1 ICMPパケットのfilteringやstealth port scan対策

ICMPパケットをやステルスポートスキャンもiptablesでフィルタできますが、ネットワークの知識が必要でめんどくさいですし長くなるのでここでは書きません。
しなくても標的にされたりなどしない限りは大丈夫なはずです。

ネットワーク関連の攻撃に興味ある方は以下のリンクを読むと楽しいと思います。

更に深いiptablesの設定をしたい方へ

読んでいて参考になったサイトなどです。
- man iptablesman iptables-extensions
- http://qiita.com/suin/items/5c4e21fa284497782f71
- https://www.oregontechsupport.com/articles/icmp.txt

sudo

☆3 passpromptを変える

管理者は[sudo] password for user:と表示されるとパスワードを入力したくなる節があるので、ダミーなプロンプトを表示させてパスワードを盗んだりがんばればできます(そんな事態が発生する時点でやばいですが)。

なので私はオリジナルなpasspromptにしています。
複数サーバーを管理している人がサーバーを間違えていても気づく可能性を増やせる利点もあります。

visudo
Defaults passprompt = "%u@%h -> Password!!! -> "

☆2 セッションタイムアウトを設定する

デフォルト値ですがArchLinuxでは5分、Debianでは15分のようで意外と長いです。
気になる方はもっと短めにして良いと思います。
意識的にsudoを使った後にsudo -kすることでセッションが切れるのでそれで代替することもできます。

持ち歩きしているArch端末は0.1(6秒)にしています。
(短めにするとメンテ時に結構めんどくさくなります)

visudo
Defaults timestamp_timeout = 3

最近こわいと思っていることは、sudoしてセッションが有効な状態でsudoが含まれているシェルスクリプトなどを実行するとセッションが有効なままになってシェルスクリプト内のsudoが有効になることになんどか遭遇しました。
トロイの木馬的にblogなどに、sudoさせた後にsudoの入ったシェルスクリプトを一般ユーザー権限で実行したようにみせかけて後ろではやばい何かしているとかできそうなので気をつけたいところです。

webサーバー(nginx)

webサーバーはapacheとnginxの2勢力がありますが、私はいつもnginxを使ってます。
apacheに関してはあまり詳しくないのでほとんど書けません。

参考になるものは、他の方がまとめたものでもよいのですが、やっぱり公式ドキュメントが面白いです。
(読むのはかなり大変ですが)

☆4 バージョンを見えなくする

HTTPのレスポンスのServerヘッダにwebサーバーがなにであるかが書いてあります。
標準ではバージョンまで書いてあるのでどの脆弱性をつけばいいかの参考になってしまいます。
(apache 2.2.25 vulnerabilityなどでggるとこわいです)

ディストリビューションによってはpathが違うので注意してください。

/etc/nginx/nginx.conf
http {
    ...

    server_tokens off;

    ...
}

apacheでは

/etc/apache/httpd.conf
ServerTokens Prod;

(apacheに関して)

個人的にapacheを運用するときに注意している点は以下あたりです。
他にありましたらコメントにおねがいします。

  • AllowOverride None;
  • Options -Indexes -FollowSymLinks;
    • Optionsに予期しないものが含まれていないか
  • ServerSignature off;

misc

☆4 不要なサービスを止める

動かさなくても良いサービスや想定していないサービスが動いていると、
管理者の管理するべきものが増えたり予期しないことが起きたりします。

ArchLinuxやCentOS7などではsystemctlコマンドで現在動いているサービスを確認することが出来ます。
最初はなにが必要なサービスかわからないと思いますが、サービス名で調べながらなにが必要かを考えるとスキルアップにつながります。

☆3 logwatchを入れる

大量のログの要約を出力するソフトウェアです。ログを纏めてくれるので不正アクセスや不具合発見などがしやすくなります。

メール転送エージェント(MTA)であるpostfixなどを導入すると、毎日メールを送信してくれます。私はこのメールが欲しいのでpostfixと一緒にlogwatchを入れます。

注意としては異常発生時のアラートではなく、ある時刻にスケジュールされた処理なので即時対応はできません。

☆3の理由は、一緒に入れたいpostfixの導入コストが高い(OP25Bなど)という理由とlogwatchが主流になりつつあるsystemdのjournalに未対応という理由で、"そこそこセキュア"であればなくてもいいかなという個人的評価からきてます。
どのような攻撃が来ているかという勉強する上では毎日読むと楽しいと思います。

☆2 使わないユーザーをログイン不可にする

chsh -s/bin/false/sbin/nologinに設定するとログインできなくなります。
ユーザー一覧は/etc/passwd内に書いてあります。

# chsh -s /bin/false nologinuser
# chsh -s /sbin/nologin nologinuser

/sbin/nologinは、ログインに失敗した趣旨もしくは/etc/nologinの内容を表示した後に終了しますが。/bin/falseは何も表示せずに終了します。
(ディストリビューションによってpathが違うかもしれないのでwhere nologinman nologinを参照してください。)

2014/11/26 19:20追記

指摘してもらいまして、一応知識として知っておいたほうがいいと思ったので紹介しました。

☆1 umaskを027にする

umaskは新規生成したファイルパーミッションを司ります。
ディレクトリは777ファイルは666でデフォルトのumaskは022なので、
作成されるパーミッションはディレクトリであれば777-022=755ファイルであれば666-022=644となります。

umaskを027にするとothersのreadとexecができなくなるため、
他のユーザーが新規作成したディレクトリにcdしたりファイルをreadできなくなります。
(最小権限の原則など)

すべてのユーザーに対して適応する場合は/etc/profileを変更します。
特定ユーザーであれば~theuser/.profileを変更します。

私は/etc/profileでは027にして必要なユーザーに対しては022にしています。

/etc/profile
umask 027

注意点としてはsudoで作成した設定ファイルなどを見るためには、sudoする必要あります。
設定ファイルなどのグループを管理者グループ(wheel)などにすれば、グループに入っている人からはreadはできるようになります。

setgidに関して

setuid, setgid, stickyビットという特殊なビットもあります。(setuidも面白いですが紹介にとどめます)
http://ja.wikipedia.org/wiki/Setuid

私はumask 027と組み合わせてsetgidをよく使います。
あるディレクトリのsetgidビットを立てると、そのディレクトリ内で作成したファイルやディレクトリのgroupが継承されます。

通常は新規作成した所有権はtheuser:theuserとなりグループ間で共有したいファイルを毎回chownする必要がでてしまいますが、
setgidを立てたディレクトリではその必要がなくなります。

umaskやsetgidの知名度が意外と低いので紹介しました。

おわりに

自宅サーバー(ArchLinux)を作りながら書いたメモを主軸にまとめたため、サーバーの構築が主軸でサーバーの保守というベクトルが弱くなっています。

サーバーの保守で必要なことを個人的に上げてみると、

  • サーバーを常に最新にする
  • 常に情報収集をする
    • 新しい脆弱性
    • 新しい・ホットなソフトウェア

の2つだとおもいます。

また、Linuxサーバーのセキュリティに関してはLinuxサーバーセキュリティ徹底入門(ISBN: 978-4798132389)が非常によくまとまっています。
最後に一部熟考調べ不足などがあると思いますが、その際はコメントにてご指摘お願いします。