SHOYAN BLOG

I am a pragmatic programmer.

TCPWrappersとは何なのかを調べてみた

sshのハンドシェイクでこけてしまい、その原因がわからずハマりました。
原因としては、TCPWrappersで拒否されていました。
TCPWrappersとはなんだろうということで調べてみました。

TCPWrappersとは

TCPWrapperとは、ネットワークのアクセス制御をする機能です。
デフォルトでインストールされています。

Linuxの基本的なアクセス制御の仕組み

Access Control to Network Services

アクセス制御の仕組みとして、FirewallとTCP Wrappersがあります。
Firewallはiptablesで制御します。
なぜ2つの仕組みが存在するのかはわかりません(誰か教えてください)。

クライアント→Firewall→TCPWrappers→サービスという流れで処理を行います。
TCPWrappersは接続を許可するかどうかのファイルを参照し、許可リストにあればサービスに処理を受け渡します。

処理のログはsyslog daemon (syslogd)によってクライアントと接続先サービスの情報を /var/log/secure または /var/log/messages に書き込まれます。

TCPWrappersのアドバンテージ

TCPWrappersを使うことで、以下のメリットがあるとのこと。

  • 接続したクライアントとそのサービスがログに残る
  • 様々なプロトコルを集約して管理できる

##TCPWrappersの設定ファイル

以下の2つのファイルがあります。

  • /etc/hosts.allow
  • /etc/hosts.deny

TCPWrappersはクライアントからのリクエストを受けると、以下の処理を行います。

  • /etc/hosts.allow を参照します。クライアントがリストに存在した場合、接続を許可します。リストに存在しない場合は次のステップに進みます。
  • /etc/hosts.denyを参照します。クライアントがリストに存在した場合、接続を拒否します。リストにない場合は接続を許可します。

注意点

  • /etc/hosts.allowから先に評価され、そこでリストに一致した場合/etc/hosts.denyは評価されません。/etc/hosts.allow/etc/hosts.denyに同じクライアントを指定した場合は/etc/hosts.allowが優先されます。
  • ファイルの上から評価されていき、一致した時点で評価を打ち切ります。順番が重要です。
  • TCPWrappersはキャッシュを持ちません。ですので、設定ファイルを書き換えたら即反映されます。デーモンをリスタートする必要はありません。
  • 最後に改行を含めるとエラーメッセージが出るとのことなので、含めないほうがよさそうです。warning: /etc/hosts.allow, line 20: missing newline or line too longというメッセージが /var/log/messages または /var/log/secureに出力されるとのことです。

参考リンク

クロスサイトスクリプティングの脆弱性とその対策

クロスサイトスクリプティングはユーザーの入力を受け付ける動的なアプリケーションに含まれる脆弱性を利用した攻撃です。
英語ではCross Site Scriptingと呼ばれその頭文字をとるとCSSとなりますが、「Cascading Style Sheets」との区別が紛らわしいため一般的にXSSの表記が使われています。

クロスサイトスクリプティングとはどのような脆弱性であるのか

XSSとは動的なWebサイトのプログラムの脆弱性を利用した攻撃です。
この脆弱性を利用することで、攻撃者は悪意のあるJavaScriptコードをサイトに埋め込み、そのコードを実行することができるようになります。

例えば、XSSの脆弱性がある掲示板があったとします。
攻撃者はフィッシングサイトにページを遷移させるJavaScriptコードを投稿しました。
すると、他の利用者がこの掲示板を閲覧したときにそのJavaScriptコードが実行され、フィッシングサイトが表示されるようになります。

この脆弱性を持ったサイトが攻撃されるとどのような被害が起き得るのか

上記の例のようにXSSはWebサイトの利用者を攻撃の対象とします。

例えば、以下のような被害が出る可能性があります。

  • ユーザーのcookie情報を盗み、その情報を利用してそのユーザーでログインする
  • 不正なページへユーザーを誘導する
  • 不正なファイルをダウンロードさせる

Webサイトを直接攻撃することも可能です。
JavaScriptのhtmlを書き換える機能を使って、攻撃対象のサイトの内容を書き換えることができてしまいます。

なぜそのようなセキュリティホールが作り込まれてしまうのか

HTMLには特殊文字が存在します。
具体的には「’”<>&」といった文字です。
これらの特殊文字をHTML上に表示するには適切な方法で変換しなければなりません。
しかし、XSSの脆弱性のあるプログラムはこのような特殊文字を意識せずに作られてしまっています。

どのように対策をすればよいのか

入力時のチェックと出力時のチェックを行います。

入力時のチェック

具体的には、入力時に入力できる文字を制限します。
例えば、郵便番号を入力するフォームの場合は、数字と-しか入力できないようにします。
そうすれば、悪意のあるコード自体が入力できなくなります。
入り口でとめる作戦です。

注意点としては、入力文字のチェックは必ずサーバサイドで行わなければなりません。
PHP等のサーバサイドで実行されるプログラムでチェックする必要があるということです。
クライアントサイド(JavaScript)のチェックでは攻撃者がそのチェック機構自体を無効にすることが可能です。

出力時のチェック

実際には仕様上、入力文字を制限することができないことがあります。
例えばフリーフォームの場合、無闇に入力文字を制限するとユーザーは自由に文章を入力することができなくなってしまいます。

そこで、出力時に文字を無害化(サニタイジング)します。

サニタイジングについては、プログラム言語やフレームワークに専用の機能が用意されています。
その機能を使うことを強く推奨します。

例えばPHPであれば、htmlspecialcharsというhtmlの特殊文字を無害化する関数が用意されています。
http://php.net/manual/ja/function.htmlspecialchars.php

また、フレームワークはデフォルトでサニタイズされた文字が出力される仕組みになっているはずなので、そのようなフレームワークを使ったほうがよいでしょう。

参考リンク

Shellで日本語ドメインをPunycode(IDNドメイン)に変換する方法

Shellで日本語ドメインをIDNフォーマットに変換する方法を紹介します。
対象のOSはMacです。

libidnというGNUのライブラリがあるので、それを使います。

libidnのインストール

homebrewでインストールします。

1
$ brew install libidn

インストールしたら、idnコマンドが使えるようになります。

1
2
3
4
5
6
7
8
$ idn
libidn 1.32
Copyright 2002-2015 Simon Josefsson.
GNU Libidn is free software with ABSOLUTELY NO WARRANTY.  For more
information about these matters, see <http://www.gnu.org/licenses/>.
Type each input string on a line by itself, terminated by a newline character.

idn: tld_check_4z: Missing input

libidnでPunycodeに変換する

以下のようにPunycodeに変換できます。

1
2
$ idn しょーやん.xyz
xn--68jwei3c27a.xyz

unicodeに変換する場合は-uオプションを使います。

1
2
$ idn -u xn--68jwei3c27a.xyz
しょーやん.xyz

digとidnを組み合わせて使う

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
⇒  dig `idn しょーやん.xyz` NS

; <<>> DiG 9.8.3-P1 <<>> xn--68jwei3c27a.xyz NS
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 59533
;; flags: qr rd ra; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 0

;; QUESTION SECTION:
;xn--68jwei3c27a.xyz.   IN  NS

;; ANSWER SECTION:
xn--68jwei3c27a.xyz.  3578  IN  NS  dns01.muumuu-domain.com.
xn--68jwei3c27a.xyz.  3578  IN  NS  dns02.muumuu-domain.com.

;; Query time: 34 msec
;; SERVER: 192.168.74.20#53(192.168.74.20)
;; WHEN: Fri Jun  3 09:25:40 2016
;; MSG SIZE  rcvd: 94)>>>>>>

Capistranoの導入手順とプラグインの紹介

Capistranoのインストールと設定、プラグインの紹介をします。

Capistranoのインストール

bundle initコマンドでGemfileを作成します。

1
2
$  bundle init
Writing new Gemfile to /Users/shoyan/app/Gemfile

以下のGemfileが作成されます。

1
2
3
4
5
$ cat Gemfile
# A sample Gemfile
source "https://rubygems.org"

# gem "rails"

GemfileにCapistranoを定義します。

1
2
3
group :development do
  gem "capistrano", "~> 3.4"
end

bundle installコマンドでインストールします。

1
$ bundle install

Capistranoの設定

Capistranoがインストールできたので、設定をしていきます。
cap installコマンドで雛形を作成します。

1
$ bundle exec cap install

config/deploy.rbconfig/deploy/{production, staging}.rb が作成されているので適宜編集します。

config/deploy.rb

1
2
3
4
5
6
7
8
9
10
11
# config valid only for current version of Capistrano
lock '3.5.0'

set :application, ‘app'
set :repo_url, 'git@github.com:shoyan/shoyan.git'

ask :branch, `git rev-parse --abbrev-ref HEAD`.chomp
set :deploy_to, '/var/www/app'
set :scm, :git
set :format, :airbrussh
set :keep_releases, 5
  • application: アプリケーション名
  • repo_url: リポジトリのURI
  • branch: デプロイ対象のブランチ
  • deploy_to: サーバーのアプリケーションのディレクトリ
  • scm: git or svn
  • format: ログのフォーマット
  • keep_releases: 過去にデプロイしたアプリケーションを何世代保持するか

デプロイするサーバーを定義します。
事前に鍵認証でsshログインできるようにしておくととスムーズです。

config/deploy/production.rb

1
role :app, %w{shoyan@server001.example.jp shoyan@server002.example.jp}

Capistranoでデプロイする

以下のコマンドでデプロイします。

1
$ bundle exec cap production deploy

便利なCapistranoプラグイン

Capistranoには様々なプラグインがあります。
ここでは私が使っているプラグインを紹介します。

capistrano-github-releases

デプロイ時にタグをつけたり、PRにリリースコメントをつけれます。

https://github.com/linyows/capistrano-github-releases

capistrano/slack_notification

デプロイ時にSlackに通知できるようになります。

https://github.com/linyows/capistrano-slack_notification

capistrano_banner

デプロイ時にASCIIアートを設定できます。
また、productionにデプロイする前に確認をしてくれるようになります。

https://github.com/holysugar/capistrano_banner

capistrano-bundler

デプロイ時にbundle installを実行できるようになります。

https://github.com/capistrano/bundler

capistrano3-unicorn

デプロイ時にunicornのコマンドを実行できるようになります。

https://github.com/tablexi/capistrano3-unicorn

###capistrano-withrsync

rsyncでデプロイしてくれるプラグインです。
デプロイするファイルが大きい場合に便利です。

https://github.com/linyows/capistrano-withrsync

NginxのCookbookでハマった

Nginxのcookbookでversionを指定しているのに、指定したバージョンでインストールされない問題でハマった。

https://supermarket.chef.io/cookbooks/nginx

結果としてわかったこと

パッケージでインストールする場合はバージョンが指定できない。
バージョンを指定したい場合はソースでインストールする必要がある。

Nginx cookbookはパッケージでのインストールかソースでのインストールのいずれかを選ぶことができる。
デフォルトはパッケージである。
ソースでインストールしたい場合は、node['nginx']['install_method’]='source' とする必要がある。
install_methodを指定したときにはじめてversionの指定が可能となる。

立ちはだかる様々な問題

### versionが反映されない

attributes/default.rbにversionを定義してみたが、指定されたバージョンがインストールされない問題にハマった。
デフォルトである、1.4.4がインストールされている。

解決方法

rolesのoverride_attributesとして指定すると指定されたバージョンがインストールされた。
基本的にvendor cookbookの値の定義はroleのoverride_attributeで指定したほうがいいのかもしれない。
とはいえ、パラメーターによっては上書きされる場合もあってそのあたりの挙動がよくわかっていない。

Checksumを指定しないといけない

sourceからインストールする場合、checksumを設定する必要がある。
checksumは以下のようにして作成できる。

1
shasum -a 256 nginx-x.x.x.tar.gz

もしくは

1
curl http://nginx.org/download/nginx-x.x.x.tar.gz | shasum -a 256

checksumは node['nginx']['source']['checksum’] に指定する。

ChefのAttributeの優先順位について

マニュアルによると、以下のようになっている(しかし、versionをoverrideで定義しても上書きできなかった)。

  • A default attribute located in a cookbook attribute file
  • A default attribute located in a recipe
  • A default attribute located in an environment
  • A default attribute located in role
  • A force_default attribute located in a cookbook attribute file
  • A force_default attribute located in a recipe
  • A normal attribute located in a cookbook attribute file
  • A normal attribute located in a recipe
  • An override attribute located in a cookbook attribute file
  • An override attribute located in a recipe
  • An override attribute located in a role
  • An override attribute located in an environment
  • A force_override attribute located in a cookbook attribute file
  • A force_override attribute located in a recipe
  • An automatic attribute identified by Ohai at the start of the chef-client run

https://docs.chef.io/attributes.html#attribute-precedence

Attributeの使い分けについて

以下のようにルール決めをしているという記事もあった。

Attributeファイル=>文言変更
recipeファイル=>テスト的に変えたいものがある時のみ。本番では消す。
Environmentファイル=>development(開発),alpha(実験用)、staging(テスト)、production(本番)でのIPやOSバージョンの違い。同じ構成が複数台ある時もここで区別。
Role=>ミドルウェアのバージョン違い

http://dev.classmethod.jp/server-side/chef/attribute-overrides-pattern/

参考リンク