2006年06月13日

http_proxy にパスワードを指定する場合の注意点(続)

http://kumaneko-sakura.sblo.jp/article/517004.html で DNS パケットによるパスワード誤流出の可能性について示しましたが、実際に環境を作って試してみました。

/etc/resolv.conf に自分自身を指定します。

[root@tomoyo ~]# cat /etc/resolv.conf
nameserver 127.0.0.1

即席のパケットダンプを行うプログラムを用意します。

[root@tomoyo ~]# cat dnsdump.c
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

int main(int argc, char *argv[]) {
  struct sockaddr_in addr;
  int fd = socket(AF_INET, SOCK_DGRAM, 0);
  addr.sin_family = AF_INET;
  addr.sin_addr.s_addr = htonl(INADDR_ANY);
  addr.sin_port = htons(53);
  if (bind(fd, (struct sockaddr *) &addr, sizeof(addr)) == 0) {
    int i, len;
    int size = sizeof(addr);
    static char buf[65536];
    while ((len = recvfrom(fd, buf, sizeof(buf), 0, (struct sockaddr *) &addr, &size)) != EOF) {
      for (i = 0; i < len; i++) {
        if (buf[i] >= 32 && buf[i] <= 126) putchar(buf[i]);
        else putchar('=');
      }
      putchar('\n');
    }
  }
  return 0;
}

コンパイルして実行します。

[root@tomoyo ~]# gcc -Wall -O3 dnsdump.c
[root@tomoyo ~]# ./a.out

別の画面で、以下のコマンドを実行します。

[root@tomoyo ~]# export http_proxy="http://USER:@PASS@WORD@127.0.0.1:8080"
[root@tomoyo ~]# wget http://localhost/
--16:33:02--  http://localhost/
           => `index.html'
Resolving pass@word@127.0.0.1... failed: Host not found.
[root@tomoyo ~]# yum update
Gathering header information file(s) from server(s)
Server: Red Hat Linux 9 (i386)
retrygrab() failed for:
  http://riksun.riken.go.jp/pub/Linux/fedoralegacy/redhat/9/os/i386/headers/header.info
  Executing failover method
retrygrab() failed for:
  http://download.fedoralegacy.org/redhat/9/os/i386/headers/header.info
  Executing failover method
failover: out of servers to try
Error getting file http://riksun.riken.go.jp/pub/Linux/fedoralegacy/redhat/9/os/i386/headers/header.info
[Errno 7] HTTP Error (CannotSendRequest):

./a.out を実行中の画面には、以下のような内容が表示されるはずです。

=============pass@word@127=0=0=1=====
=============pass@word@127=0=0=1=====
=============pass@word@127=0=0=1=====
=============pass@word@127=0=0=1=====
=u===========PASS@WORD@127=0=0=1=====
=u===========PASS@WORD@127=0=0=1=====
=v===========PASS@WORD@127=0=0=1=====
=v===========PASS@WORD@127=0=0=1=====
=w===========PASS@WORD@127=0=0=1=====
=w===========PASS@WORD@127=0=0=1=====
=x===========PASS@WORD@127=0=0=1=====
=x===========PASS@WORD@127=0=0=1=====

ちゃんとパスワードが流出していることを確認できました。

この原因は、 http_proxy の内容を最初に出現した @ の位置で分割してしまうためです。 @ が複数回出現したらエラーにしてくれると嬉しいんですがね。しかし、 RFC1738 によると、ユーザ名やパスワードの部分に @ を使ってはいけないということになっているので、アプリケーションの責任ではなく、ユーザの責任ということになるのでしょう。

話は違いますが、ユーザ名やパスワードをホスト名のように見せかけるといった攻撃手法もあるんですね。 http://itpro.nikkeibp.co.jp/free/ITPro/OPINION/20040306/141018/ 「URL ユーザ名 偽装」で検索するといろいろ出てきました。

posted by 熊猫さくら at 20:15| Comment(0) | TrackBack(0) | Linux

2006年05月18日

カーネルモジュールを小さくするためのコツについて

カーネル 2.6 には、 CONFIG_DEBUG_INFO という名前のコンパイルオプションが存在します。このオプションが有効である場合、コンパイルされたコードのサイズが約8倍〜10倍の大きさになります。
このオプションが有効になっている場合、(カーネルのコンフィグにもよりますが) /usr/src/ ディレクトリで約1GB、 /lib/modules/ ディレクトリで約300MBの余分なディスク領域を消費します。いくつかのディストリビューションではデフォルトで有効になっています。
ディスク領域を節約したい場合、以下のオプションが選択されていないことを確認してください。

Kernel hacking --->[ ]  Compile the kernel with debug info

VMware のようにディスク領域が貴重な場合は無効にすることを推奨します。私の場合、このオプションに気がつくまでは仮想ディスクを10GB割り当てていましたが、このオプションを無効にすることで4GBでやりくりできるようになりました。

posted by 熊猫さくら at 21:22| Comment(0) | TrackBack(0) | Linux

2006年03月31日

http_proxy にパスワードを指定する場合の注意点

認証が必要なプロキシ環境( http_proxy や ftp_proxy で「 http://プロキシユーザID:プロキシパスワード@プロキシホスト:プロキシポート」のような指定を行っている環境)で使用する場合には、以下の点に注意してください。

1つ目は、コマンドラインヒストリが有効になっているシェルから入力しないことです。私は、ヒストリが有効になっている bash から入力せずに、ヒストリが無効になっている tcsh を起動してから入力するようにしています。尤も、他のプロセスの環境変数(/proc/<PID>/environ)へのアクセスが可能であればどのみち盗まれてしまうわけですが。

2つ目は、パスワードに @ を使ってはいけないということです。これは、 http_proxy に @ が含まれている場合、最初の @ 以前を「プロキシユーザID:プロキシパスワード」、最初の @ 以降を「プロキシホスト:プロキシポート」として解釈するため、 「プロキシパスワード」に @ が含まれていると、「 @ 以降の部分」がプロキシホストのホスト名だと解釈されて、DNSの問い合わせパケット経由でプロキシサーバ以外のサーバにプロキシパスワードの一部を教えてしまうことになります。
これに気が付くまでは、どうしてホスト名が解決できないのか悩みました。そして、 http_proxy にパスワードを指定できるようにするために、わざわざパスワードを変更しました。もしも、「プロキシユーザID」に @ が含まれていたら「プロキシパスワード」全体をDNSサーバに教えてしまうことになるのでしょうね。怖くて試していませんけど。

posted by 熊猫さくら at 20:09| Comment(0) | TrackBack(0) | Linux

2006年03月23日

yum の罠

yum はコマンド1つでパッケージを最新版にアップデートしてくれる便利なプログラムですが、気をつけなければいけない点が2つあります。

1つは、設定ファイルに最新版を置いてあるサーバを指定しておくことです。全てのサーバが永遠に最新版を置き続けてくれる訳ではないため、時々確認してやらないと、最新版が存在しているのに当該サーバに置かれてないからダウンロードされないという状況が発生します。

もう1つは、キャッシュされたメタデータを時々削除することです。「yum update」を実行しても何もダウンロードされず、「最近、パッケージの更新が全然無いようだけどどうしたのかな?」と思ったら、「yum clean metadata」または「yum clean all」を実行してみてください。
その後、再度「yum update」を実行すると・・・「あら不思議。 yum clean metadata を実行前に yum update したときには表示されなかったパッケージが次々とダウンロードされてきた。」なんてことがあります。何かの拍子に、 yum が管理するメタデータが最新の情報を反映しなくなってしまうようです。

posted by 熊猫さくら at 21:49| Comment(0) | TrackBack(1) | Linux

2006年03月20日

簡単に作れる find もどき

Linux には ftw という関数があります。これは、 find コマンドのように指定されたディレクトリ以下をスキャンする関数です。以下、 RedHat Linux 9 で find もどきの関数を作る方法を紹介します。

プログラムの先頭で、ファイルサイズを64ビットで扱えるように以下の3行を記述します。これを指定しないと、32ビットでは扱えないファイルに遭遇した場合に ftw がエラーになってしまいます。

#define _FILE_OFFSET_BITS 64
#define _LARGEFILE_SOURCE
#define _LARGEFILE64_SOURCE

次に、以下の内容を記述します。(これらの内容は、 #include <ftw.h> で取り込まれるはずなのですが、何故かうまくいかないので直接記述します。)

#include <sys/types.h>
#include <sys/stat.h>
#define FTW_PHYS 1
struct FTW;
int nftw64(const char *dir, int (*fn)(const char *file, const struct stat64 *sb, int flag, struct FTW *s), int nopenfd, int flags);

コールバック関数 fn は、以下のような内容です。

#include <stdio.h>
int ftw_func(const char *file, const struct stat64 *sb, int flag, struct FTW *s) {
    printf("%s\n", file); // ここに処理内容を記述します。
    return 0;
}

呼び出し方は以下のようにします。

if (nftw64("/", ftw_func, 1000, FTW_PHYS)) {
    fprintf(stderr, "nftw64() returned %d\n", errno);
    exit(1);
}

これだけで、 find / 相当の機能が実現できます。詳細は man ftw を参照してください。

posted by 熊猫さくら at 22:04| Comment(0) | TrackBack(0) | Linux

2006年03月17日

仮想ディスクファイルの圧縮時に圧縮率を高めるためのファイルの削除方法について

VMware 仮想マシンを持ち運ぶために zip ファイル化したり、ホスト側のディスク領域を節約するために NTFS 等の圧縮機能を利用したりすることがあると思います。

通常のファイル圧縮の場合、必要なファイルだけを圧縮することができるため、圧縮されたファイルのサイズを小さくすることができます。
しかし、仮想ディスクファイルを圧縮する場合、その中に含まれる全てのデータを圧縮する必要があります。仮想ディスクファイル内の消去されたデータまで圧縮を行うことになり、消去されたデータの内容によっては全く圧縮が効きません。

しかし、逆に言えば、消去されたデータの内容を圧縮が効きやすいものに書き換えてやれば、消去されたデータが最初から存在しなかった場合と同じくらいの圧縮効果を期待できます。

以下は、約3GBの ISO イメージファイルを VMware 環境内からダウンロードして、ホスト側に移動後、そのファイルを削除した後のディスクの使用量です。 NTFS の圧縮機能で圧縮していますが、あまり小さくなっていません。

before-zeroclear.png

以下は、そのディスクの空き領域を全てゼロクリア(実際にはスパースファイル化されると困るので 0xFF でクリア)してみた結果です。

after-zeroclear.png

最初からディスク領域を割り当てずに必要に応じて拡大していく方式を利用しているので、未使用の領域までゼロクリアしたことで圧縮前のディスク使用量も若干増えてしまっていますが、圧縮後のディスク使用量は ISO イメージファイルのサイズと同じくらい減少していることがわかります。 (ファイルの内容が含まれている領域だけゼロクリアできれば、未使用の領域までゼロクリアしないで済むので、圧縮前のディスク使用量の増加も避けられます。)

/bin/rm や /bin/unlink にファイルの内容をゼロクリアしてから削除するようなオプションがあると嬉しいですね。

posted by 熊猫さくら at 19:56| Comment(0) | TrackBack(0) | Linux

2006年03月13日

お遊び:テンポラリファイルで使われるパス名を見つけようとしたら・・・

テンポラリファイルを作成する場合、パス名の末尾を XXXXXX としてテンポラリファイルを作成する関数を呼び出すようになっています。そのため、 XXXXXX で終わる文字列は、テンポラリファイルとして使われるパス名である可能性が高いわけです。そこで、 strings を使ってそのような文字列の抽出を試みたのですが、予想外の結果が出てきました。

find / -type f -perm +100 -print0 | xargs -0 strings -f -- | grep -F XXXXXX

を実行すると、インストールされているパッケージによっては面白いものが表示されます。

strings に渡す -f オプションは、ファイル名を表示するためのものです。最初は -f を指定せずに実行したため、一瞬「ウィルスに感染したのか?」と疑ってしまいました。(笑)

大量にヒットするので、スクロール機能が無いコンソールから実行すると一瞬で消えてしまいます。スクロールバッファを1000行以上に設定してお試しください。

ちなみに、ウィルスに感染したのかと疑ってしまうような表示をしていたのは、 /usr/bin/xboard でした。

posted by 熊猫さくら at 20:08| Comment(0) | TrackBack(0) | Linux

2006年03月11日

scp の罠

ssh を使ってコピーを行う scp には、ちょっと困った問題点があるようです。

問題1

例えば、

scp -p 'remotehost: ; touch /tmp/testfile' .

と実行すると、 remotehost で touch /tmp/testfile というコマンドを実行できてしまいます。

これは、接続元の scp が remotehost のログインシェルを「-c 'scp -p -f "接続元で実行された scp に渡された引数から最初の : までを取り除いたもの"'」という形式で起動するため、 remotehost のログインシェルは「scp -p -f "接続元で実行された scp に渡された引数から最初の : までを取り除いたもの"」つまり「scp -p -f ; touch /tmp/testfile」というコマンドを展開して実行してしまうためです。

もしも、

scp -p 'root@remotehost: ; rm -fR /*' .

などというパラメータを渡された場合には、全ファイルが削除されてしまうことでしょう。

このように ; を使って余計なコマンドを実行されないようにするには、 rssh を使う必要があります。

問題2

しかし、 rssh を使っても、 remotehost で scp の実行を禁止できるわけではない点に注意が必要です。 scp は remotehost 上でも scp を起動することで動作するように設計されているためです。

scp は、 -f オプションが指定されておらず、ファイル名に : が含まれている場合には、そのファイルがリモートホスト上にあると判断して ssh を起動してしまいます。つまり、 remotehost1 で rssh が使われていても、

ssh remotehost1 'scp -p remotehost2:/etc/passwd .'

というコマンドを実行することは可能なわけです。そのため、自動的に remotehost1 から remotehost2 へ接続できるような設定になっている(例えば remotehost2 の ~/.ssh/authorized_keys に remotehost1 の公開鍵が登録されている)場合、

ssh remotehost1 'scp -p -i ~/.ssh/id_rsa remotehost2:/etc/passwd .'
scp -p remotehost1:passwd .

とすることで、 remotehost1 にログインできる任意のホストから remotehost2 の /etc/passwd が取得できてしまいます。

問題3

また、ファイル名に : が含まれている場合、ホスト名を指定する区切り文字だと解釈されてしまい誤動作の原因になります。例えば、

touch /tmp/file1 /tmp/somehost:file2
cd /tmp/
scp -p file1 somehost:file2 remotehost:/tmp/

と実行しても、 /tmp/somehost:file2 を remotehost にコピーすることができません。 ただし、ファイル名に : が含まれる場合でも、 : より前に / が出現すれば問題ないようですので、

touch /tmp/file1 /tmp/somehost:file2
cd /tmp/
scp -p file1 ./somehost:file2 remotehost:/tmp/

のようにすれば回避できます。

問題4

また、

scp -p -f file1 remotehost:/tmp/

のように、 -f オプションが指定されてしまうと入力待ち状態になってしまいます。もしも、

touch /tmp/-f
cd /tmp/
scp -p * remotehost:/tmp/

と実行した場合、 * の展開結果として -f が先頭に来てしまい、

scp -p -f * remotehost:/tmp/

と同様の結果になりかねません。これを回避するには、

touch /tmp/-f
cd /tmp/
scp -p ./* remotehost:/tmp/

のように ./ を指定するのが良いと思います。もし、

scp -p -- * remotehost:/tmp/

のように -- を指定しても、 * を展開した結果 somehost:file2 のようなファイルが含まれてしまう可能性があり、問題3が発生してしまいます。

posted by 熊猫さくら at 15:13| Comment(2) | TrackBack(0) | Linux

2006年02月13日

メモ: apt-get による emacs のインストール

Debian Sarge で emacs をインストールしようとしてはまりました。

「apt-get install emacs」と指定してもインストールできないので不思議に思っていたら、 「apt-get install emacs21」と指定すれば良いことが判りました。(笑)

posted by 熊猫さくら at 20:44| Comment(0) | TrackBack(0) | Linux

2006年01月23日

帳票入力アプリケーションの見直しについて

世間には、ブラウザ上で動作する帳票入力アプリケーションがたくさんあります。
でも、私にはブラウザを使う(http/https)よりもログインして操作する(ssh)ほうが安全・確実・簡単・便利・省エネ・低コストだと思える場合があります。

ブラウザを使ったアプリケーションを開発したがる理由としては、以下のようなものがあると私は思います。

不正に ssh ログインされるのが怖い。
サーバにログインさせると不要な操作をされるので、ログインさせたくない。
アプリケーションの配布が面倒くさい。

でも、ブラウザを使うといろいろな問題が発生します。

セッション管理が必要になる。
Cookie を受け付けるためにブラウザのセキュリティ設定を下げなければいけない。
ActiveX を受け付けるためにブラウザのセキュリティ設定を下げなければいけない。
JavaScript を有効にするためにブラウザのセキュリティ設定を下げなければいけない。
HTML を使う必要があるので通信トラフィックが増大する。
HTML を使う必要があるのでクロスサイトスクリプティング等に注意しなければいけない。
10セキュリティパッチを適用するとブラウザの挙動に影響を受ける場合がある。

帳票入力アプリケーションを http/https を使う設計から ssh を使う設計に変更すれば、これらの問題を簡単に回避できるのです。

複数回の認証により不正な ssh ログインを確実に排除できる。
ログイン後の操作を一挙手一投足まで制限できる。
アプリケーションの更新はサーバ側で行なうだけで済む。
セッションは ssh が管理してくれる。
Cookie を使う必要が無いのでブラウザのセキュリティ設定を下げる必要が無い。
ActiveX を使う必要が無いのでブラウザのセキュリティ設定を下げる必要が無い。
JavaScript を使う必要が無いのでブラウザのセキュリティ設定を下げる必要が無い。
HTML を使う必要が無いので通信トラフィックが激減する。
HTML ではないのでクロスサイトスクリプティング等が発生しない。
10セキュリティパッチを適用しても ssh クライアントの挙動には影響を与えない。

この内、1番と2番が TOMOYO Linux を導入することで得られるメリットです。その他は TOMOYO Linux を導入しないでも得られるメリットです。デメリットは ssh クライアントソフトを配布する必要がある点と、ユーザインタフェースのデザインが面倒である点でしょう。

元々ブラウザとは閲覧するためのものなのですから、閲覧操作だけでなく更新操作も必要な帳票入力アプリケーションにブラウザは不向きだと私は思います。昔は CUI で帳票入力アプリケーションを実現していたのですから、現在でも ssh のターミナルで実現できるでしょう。セキュリティが重要視されている今日、UIデザインの簡単さの為にブラウザを使うことでこれほど多くのセキュリティリスクを背負うのは如何なものかと私は思っています。

posted by 熊猫さくら at 21:01| Comment(2) | TrackBack(0) | Linux

Re: CentOSの認証プロキシ経由でのyumアップデート

http://ld616ge281.seesaa.net/article/9428448.html の記事に対するトラックバックです。トラックバックのテストも兼ねてます。ちゃんと張れるかな?(^^;

−−−−−

 こんにちは。
CentOS は使ったことが無いのですが、

 user_pass = base64.encodestring('%s:%s' % (unquote(user), unquote(password)))
 user_pass = user_pass.rstrip('\n')
 req.add_header('Proxy-authorization', 'Basic ' + user_pass)

(行頭のインデントはタブではなくスペースにする)
のようにしても駄目でしたか?
ファイルが壊れたというのが気になった(多分、インデントの問題で実行時にコンパイルエラーメッセージが表示されたのだと思います)のでコメントさせていただきました。

posted by 熊猫さくら at 20:03| Comment(6) | TrackBack(1) | Linux