mysqlクエリとCPU状況をシェルスクリプトで監視
カテゴリー:Linux
使用してるサーバに負荷がかかっていてmysqlが原因として疑われたのでCPUの状況とMysqlの実行中クエリを表示するシェルスクリプトを組んでみました。
まず、mysqlの実行中クエリを取得する方法について調べてみると以下のSQLで得られることがわかりました。
show full processlist;
次にこのSQLをmysqlにログインせずにコマンドとして送って結果の出力を得られないか調べてみました。
以下のようなコマンドで、結果を得られるようです。-pの後に、スペースをはさまずにパスワードを入れてるところがポイント。
mysql -uuser -ppassword -e 'show full processlist'
ということで、これをつかって以下のようなシェルスクリプトを書いてみました。
if test -f $1;
then
num=0
else
num=`expr $1 + 1`
fi
while [ $count -ne $num ];
do
date
echo ' '
top -c -b -n 1 | head
echo ' '
mysql -uuser -ppassword -e 'show full processlist'
count=`expr $count + 1`
echo ' '
echo '********************************************************************'
echo ' '
sleep 3
done
使い方は、上のコードをfilename.shという名前で保存後、"filename.sh 実行回数"と実行すると指定した回数だけ3秒間隔でtopコマンドでとってきたCPUの状態とmysqlで実行中のクエリが表示されます。
ちなみに、回数の指定がないときはCtrl+Cが入力されるまで実行される。
↓実行例
filename.sh 3
FirefoxでPHPが二重実行
カテゴリー:Linux
ブラウザ上に出力するテキストが大量にあるPHPを実行していると、想定していたよりかなり時間が、かかるという問題を調べていた。
なお調べている途中で、PHPファイル内部に以下のような記述をしてPHPファイルが実行されたときの時間をログに出力するようにしていた。
<?php exec("echo 'date:".date("H:i:s")."' >> log"); ?>
そこでブラウザからファイルに1度アクセスしてログを確認してみると、実行ログが2回分はいっていた。
つまり、1度のアクセスにつきPHPが2回実行されているようだ。
この問題について調べてみた。
環境
- クライアント
- Firefox/2.0.0.11
- Windows Vista
- サーバ
- PHP Version 4.3.9
ここで、他のブラウザ、環境で試すと再現しないことから、クライアント側のhtmlファイルの解釈によって問題がおきるかどうかが変わっていることがわかった。
そこでサーバ側のPHPファイルを見直してみるとデバッグ用の出力をhtml開始タグの記述前の箇所で行っていたためデバッグ用の出力をhtmlのbody内部に出力するようにさせたところ二重実行はされなくなった。
Webアプリケーションからシェルスクリプトを動作させるときのサニタイズ
カテゴリー:Linux
作成しているWebアプリケーションに、GETパラメータから値を受け取ってその値を元にシェルスクリプトを動作させるという処理がありました。
このような処理があるときは値を受け取ったときに適切にサニタイズしなければサーバに致命的な脆弱性を生みます。
では、どのよう値が危険なのかを説明していきたいと思います。
今回、以下のようなシェルスクリプトを実行するとします。$1はWebアプリから受け取った値です。
cp $1
セミコロン
ここでもし$1の中身が「;rm -rf *」であればシェルスクリプトが実行する内容は
cp;rm -rf *
ディレクトリ内のファイルが全て削除されてしまいます。
これを防ぐため「;」はバックスラッシュでエスケープしておくべきです。
スラッシュ
次に$1の中身が「../../../../etc/filename」のようにシステムにかかわるパスであれば、システムファイルが書き換えられてしまう危険性があります。
そこで上の階層のディレクトリをディレクトリを書き換えられないようにするため「/」もエスケープする文字列に指定しておくべきでしょう。
ユーザー領域にインストールしたcpanをシェル以外から実行したときの問題点
カテゴリー:Linux
ユーザー領域にインストールしたcpanをシェル以外から実行したときの問題点
cpanのインストールディレクトリをユーザ領域に設定することで ルート権限を持たないユーザでもcpanライブラリを利用することができる。
参考URL:
注意しなければいけないのはライブラリの保存場所の環境変数を設定しておく必要があること。
例えばbashであれば、インストールしたディレクトリが/home/user/perllibだとすると
export PERL5LIB=/home/user/perllib
としてライブラリを指定する必要がある。
(いちいち打ち込まなくても.bashrcを設定しておけば大丈夫)
しかし、この方法でCrypt::CBCをインストールした後、perlプログラムをbash以外から実行しようとした時、環境変数の設定が上の方法だと通らないことに気づいた。
(今回はメールの自動応答プログラム作成のため.forwardから実行するようにしていた、詳細はこの記事を参考に)
プログラム中に以下のようなことを試してみたがダメだった。
exec("export PERL5LIB=/home/user/perllib");
$ENV{"PERL5LIB"} = "/home/start/perllib";
そこで環境変数を通さずにローカルにインストールしたライブラリを読み込む方法を調べてみた。
環境変数を通さずにローカルにインストールしたライブラリを読み込む方法
プログラムを実行するときのカレントディレクトリにperlのライブラリディレクトリ(perllib)がインストールされている場合は
use perllib::Crypt::CBC
とすれば実行することができる。
ただし今回は.forwardが実行するのでカレントディレクトリがインストールディレクトリと一致しなく、ディレクトリの移動もできなかったため、上の方法では動作しなかった。
最終的にperlの-Iオプションでライブラリのパスが指定できることがわかり
これで対応した。 .forwardで実行する部分を以下のように書き換えた。
/usr/bin/perl -I /home/user/perllib ~/filename.pl
メール自動返信の追加・修正点
カテゴリー:Linux
メールの無限ループ回避
メール自動返信プログラム2 perlでの実装
http://www.nanbu.com/blog/blog1/detail-234.html
上の記事でperlを使ってメール自動返信プログラムを書いていますが
このプログラムではメールデーモンからエラーメッセージが返ってきたり、
自分のアドレスがFromに入っていたりした場合に無限ループになってしまいます。
そこで以下の2つの条件の時にメールを送信しないようにして、無限ループを回避させるようにします。
1.送信アドレスがメールデーモンのアドレスである時
2.送信アドレスが自分のメールアドレスと一致する時
コードにすると、以下のようなコードをメール送信の直前に挿入します。
エラーの発生とその内容をログファイルに記録して、処理を停止します。
$pt1 = "DAEMON";
$pt2 = "autoresponse@nanbu.com";
if($mailaddress =~ /$pt1/ ||$mailaddress =~ /$pt2/ ){
open(OUT, ">> /home/start/returnmail.log");
print(OUT localtime(time()).":::mail test ");
print(OUT "********ERROR:possibility of infinite loop************* ");
print(OUT $content);
print(OUT " ");
print(OUT "--");
print(OUT " ");
print(OUT $mailaddress);
print(OUT " ");
print(OUT $ma16);
print(OUT "----------------------------------------------------------");
close(OUT);
exit;
}
メールアドレスに「DAEMON」(メールデーモンのアドレス)が含まれている場合、または「autoresponse@nanbu.com」(自分のアドレス)が含まれている場合に処理を停止してエラーメッセージを書き込むようになっています。
なおメールデーモンのアドレスを「DAEMON」だけで判別するのは、ユーザのアドレスまでメールデーモンと判別される可能性がありますので、実際にはもっと厳密な判定をするほうが望ましいと思います。
Blowfishをつかってメールアドレスを暗号化
メール自動返信プログラム2 perlでの実装
http://www.nanbu.com/blog/blog1/detail-234.html
上の記事の仕様では、メールアドレスをアスキーコード変換して記号化しています。
これをアスキーコード変換ではなく、なんらかの方法でアドレスを暗号化することで
認証の役割をつけたいと思います。
暗号化方式の選択ですが、
1.PHP,perlでの実装ができること
(メール送信はperlで行って、アドレスの読み取りはPHPで行うため、perlで暗号化してPHPで復号化する必要がある)
2.使用に費用や手間がかからないこと
3.暗号化した時にデータが長くなりすぎない(携帯メールにURLのGETパラメータとしてつけて送信することを考えて)
を考えて、PHP,perlの両方にライブラリがあり、ライセンスがフリーであるBlowfishを使用することにしました。
perl-Blowfish
cpanでCrypt::CBCモジュールをインストールします。
ただし、今回は移植性を考えてユーザのホームディレクトリにインストールするようにしました。
この方法については下のサイトに詳しい説明があります。
CPANで自分のホームディレクトリ内にモジュールをインストール
http://wo.skr.jp/mt/2005/11/cpan.html
Crypt::CBCのインストールが終わったら以下のようなサンプルコードを書いて動作を確認してみます。
use Crypt::CBC;
$cipher = Crypt::CBC->new( {'key' => 'my secret key',
'cipher' => 'Blowfish',
'iv' => '$KJh#(}q',
'regenerate_key' => 0, # default true
'padding' => 'space',
'prepend_iv' => 0
});
$ciphertext = $cipher->encrypt("This data is hush hush");
$plaintext = $cipher->decrypt($ciphertext);
$cipher->start('encrypting');
open(F,"./BIG_FILE");
while (read(F,$buffer,1024)) {
print $cipher->crypt($buffer);
}
print $cipher->finish;
(サンプルコードはhttp://perldoc.jp/docs/modules/Crypt-CBC-2.08/CBC.podに掲載されているもの)
ただ、今回これで実行すると以下のようなエラーがでました。
If specified by -literal_key, then the key length must be equal to the chosen cipher's key length of 56 bytes at blowfish2.pl line 3
そこでkeyの部分を56バイトに変更するとエラーは表示されなくなりました。
PHP-Blowfish
まずPEARのPEAR::Crypt_Blowfishモジュールをインストールします。
その後以下のようなサンプルコードを書いて動作を確認してみます。
include_once 'Crypt/Blowfish.php';
$key = 'thisiskey';
$text = 'tihsisdata';
$blowfish = new Crypt_Blowfish($key); $crypttext = $blowfish->encrypt($text); $plaintext = $blowfish->decrypt($encrypt);
echo $crypttext;
echo $plaintext;
PHPとperlの連携-Blowfish
今回、perlで暗号化、PHPで復号化することが必要です。
そこで上に書いたサンプルプログラムをいじって、perlとPHPで同じkeyを使ってperlで暗号化,PHPで復号化したのですが、元のデータが復元できませんでした。
これはそれぞれのモジュールの初期化設定や、パラメータ設定の問題だと思います。
どのようにすれば連携できるのか現在調査中です