モーグルとカバとパウダーの日記 このページをアンテナに追加 RSSフィード Twitter

モーグルやカバ(EXカービングスキー)、山スキー(BC)の山行記録などがメインの日記です。
いろんな条件のいろんなところを、その時々の条件にあった滑り方で楽しむ、フリースキーをして遊んでいます。

検索で来られた方は、上の検索窓から再度検索していただくか、右サイドバーのカテゴリーやトピックスの項目で絞り込んでみてください。
仕事柄、コンピュータ系のネタも多いので、スキー関連ネタだけ読みたい方は[ski]、コンピュータ関連ネタは[pc]、スパム関連ネタは[spam]で絞り込んでください。

2015-03-10 (Tue)

[]Javaサーブレットでユーザのセッション数を取得する Javaサーブレットでユーザのセッション数を取得するを含むブックマーク Javaサーブレットでユーザのセッション数を取得するのブックマークコメント

Tomcatで動いているWebアプリケーションで、ユーザアカウント毎のセッション数制限を実装する必要が出ました。


調査したところ、3通りの方法が考えられました。


1. サーブレットにプローブを挿しといてそこから取得する

2. セッション生成削除のリスナーを設定してセッション情報コピーを作る

3. セッション情報をDBに持つように設定してDB経由で見る


このうち、1と2の方法を実際に作って試しました。


1の「サーブレットにプローブを挿しといてそこから取得する」という方法は、下記ページのやり方を真似しました。

DAY2907 セッション情報の一覧を取得する(Tomcat限定) - LHD Peugeot

ContainerServletのsetWrapperメソッドをオーバーライドしておいて、渡されてきた containerWrapper を保持しておき、セッション情報を見たいときにはそれ経由でセッションリストにアクセスするというものです。


取得した後の値のセッション情報の触り方などは、tomcatが標準で提供しているmanagerサーブレットのソースが参考になりました。

GC: ManagerServlet - org.apache.catalina.manager.ManagerServlet (.java) - GrepCode Class Source


ただ、この方法はtomcat依存になってしまう、という問題と、このサーブレット自体をJSPなどに埋め込むことはできない(オブジェクトとして持てない)ため、サーブレットに対してWebAPIなどを通じて情報を取得する必要がありました。



そこで2の「セッション生成削除のリスナーを設定してセッション情報コピーを作る」を試しました。


これは下記のページを参考にしました。

8. リスナー2 | TECHSCORE(テックスコア)

javax.servlet.http.HttpSessionListener は、web.xmlに<listener>で設定しておくと、サーブレットセッションが生成されたときと削除された時に呼び出されるように出来ます。


この時に得られるセッションオブジェクトは、単にその時のセッション状況コピーではなくて、サーブレット内のセッションオブジェクトそのものなので、そのまま保持しておくとセッション生成後に行われた変更も含めて全てのセッション情報を取得することが出来ます。

なので、セッション生成後にログイン処理がされてユーザ名のセットがされても、ちゃんと取得することが出来ます。

(最初その認識がなかったため、この手法は使えないと思っていた)


下記程度の簡単な内容でセッション情報を保持することが出来るようになり、JSPから普通にUserCounterオブジェクトを生成してユーザのセッション数などを得ることが出来ます。

public class UserCounter {
    private static final UserCounter INSTANCE = new UserCounter();
    private final Map<String, HttpSession> sessions = new HashMap<>();

    private UserCounter() {
    }
    
    public static UserCounter getInstance() {
        return INSTANCE;
    }
    
    synchronized public void addSession(HttpSession session) {
        sessions.put(session.getId(), session);
    }

    synchronized public void delSession(HttpSession session) {
        sessions.remove(session.getId());
    }
    
    synchronized public int countAllSessions() {
        return sessions.size();
    }
    
    synchronized public int countUserSessions(String username) {
        int userCounter = 0;
        for (HttpSession session: sessions.values()) {
            String sessionUsername = (String) session.getAttribute("username");
            if (sessionUsername != null && sessionUsername.equals(username)) {
                userCounter ++;
            }
        }
        return userCounter;
    }
}

public class UserCountListner implements HttpSessionListener {
    private final UserCounter counter = UserCounter.getInstance();

    @Override
    public void sessionCreated(HttpSessionEvent event) {
        HttpSession session = event.getSession();
        counter.addSession(session);
    }

    @Override
    public void sessionDestroyed(HttpSessionEvent event) {
        HttpSession session = event.getSession();
        counter.delSession(session);
    }
}

これはtomcat依存ではないため他のWebコンテナでも動くはずです。

ただ、1の方法のように全サーブレットセッション情報を取得するのではなく、listnerの設定をしたサーブレットセッションのみになります。

トラックバック - http://d.hatena.ne.jp/stealthinu/20150310

2015-03-09 (Mon)

[]ムービーメーカー2012で縦長になる問題 ムービーメーカー2012で縦長になる問題を含むブックマーク ムービーメーカー2012で縦長になる問題のブックマークコメント

Lenovo G560でムービーメーカーが起動できない問題 でちょっと書いてたのですが、幼稚園のアルバム作成で付けるDVDの作成のため、ムービーメーカー2012を使って作っていました。(嫁が)


で、使いにくい部分が多々ありつつまあなんとか出来たのですが、最後DVD焼くところで問題が。

普通にPC上で作成した動画を確認すると普通に見えるのに、DVDに焼いたものを確認すると画像や動画がなぜか縦長になるのです。

ムービーメーカー 2012 縦長」あたりでぐぐると、マイクロソフトコミュニティサイトとかでも結構話題に上がっているのですが、そこで提示されている回答(ワイドスクリーン16:9を選択する)を試しても解決しませんでした。


非常に困ったのですが、下記サイトの方法で解決しました。

Windows ムービーメーカー 2012 で DVD を作成するとアスペクト比が 4:3 固定になる件 - hd 4.0

1. ムービーメーカーから直接 DVD 書き込みではなく、 mp4 形式で「高解像度用ディスプレイ用」で動画ファイルとして保存する

2. Windows DVD メーカー以外の DVD オーサリングソフトで DVD 書き込みを行う


また、こうやって作成したほうが画質もよくなるようです。

この問題はムービーメーカー2012のバグらしく、上記ページやぐぐって出てくるサイトを見ると結構多くの方が困っていることがわかります。

なんでこんなすぐわかりそうなバグが何年も放置されてるんだろ?と不思議です。

まあ、ちゃんと動画編集するような人はムービーメーカーなんて使わないってことなんでしょうね。

2015-02-20 (Fri)

[]Tomcatが動いているJavaだけ古いバージョンになる問題 Tomcatが動いているJavaだけ古いバージョンになる問題を含むブックマーク Tomcatが動いているJavaだけ古いバージョンになる問題のブックマークコメント

慣れないJavaTomcat用にサーブレットを書いていたのですが、それが開発PC上のNetBeansでは動くものの、テストサーバの上に持って行くと動かない、という状況になりました。


開発PC環境はWindows8+NetBeans8+Java7+Tomcat8で、(本番環境と同じにした)テストサーバ環境はCentOS6+Java7+Tomcat6という構成でした。


サーブレットTomcatのクラスを利用するものだったため、Tomcat8とTomcat6の違いの問題と考え、開発環境側のTomcatを6にしたりテストサーバTomcatを8にしたりして試したのですがダメでした。


最初、明確にTomcatのバージョンが違ったのでそっちのせいだろう、と思ってたのですが、よくよくcatalina.outのエラーを確認してみると

java.lang.UnsupportedClassVersionError: …

と言われており、TomcatのバージョンではなくJavaのバージョンが違うっぽいのが原因、とわかりました。

でもさすがに最初にそこは確認してたはず、と思ってNetBeansの利用ライブラリのバージョンが「JDK 1.7」であることを確認し、テストサーバ上でも

% java -version
java version "1.7.0_75"

となることを確認しました。


しかし、TomcatのWeb Application Manager

http://【テストサーバIP】:8080/manager/status

で確認すると、JVM Versionが「1.6.0_30」になっていることが確認できました。

というわけで、/etc/init.d/tomcat6 から起動されるTomcatはJava6を利用してしまうっぽい、ということがわかったのですが、なぜ1.7ではなく1.6が使われてしまうのかわからないという状況になりました。


そしてその時のtweet@_hito_ さんと @satoh_fumiyasu さんのからのリプライ。

この後、お二人から色々とアドバイスいただきました。超感謝です!

そのやりとり詳細見たい方は僕の最初のtweetとかから参照してみてください。


そのアドバイスと、そこから調査した結論をまとめると

  • JAVA_HOMEは /etc/tomcat6/tomcat6.conf で指定しとくべき

(じゃないとなにかちょっとしたことでJavaのバージョンが変わってしまうから)

  • JAVA_HOMEが指定されてない時のtomcat6のJavaのバージョンはjavacのバージョンになる

(/usr/share/java-utils/java-functions の set_jvm() 中でjavacのバージョン見てる)

ということになりました。


そこで /etc/tomcat6/tomcat6.conf の最初にコメントアウトされたJAVA_HOMEのところを /usr/lib/jvm/java-1.7.0-openjdk-1.7.0.75.x86_64 にすることで、無事にTomcatもJava7で動かすことが出来るようになりました。


ただ、疑問だったのがなぜこの状況になったのか、ということです。

実は /etc/alternatives/java* を確認していて、javaだけが1.7を指しており、javacなど他のものはみな1.6系を指していることがわかっていました。

そこでyumで入れたjava系のものを確認すると

% yum list installed | grep java
java-1.5.0-gcj.x86_64  1.5.0.0-29.1.el6 @base
java-1.6.0-openjdk.x86_64
java-1.6.0-openjdk-devel.x86_64
java-1.7.0-openjdk.x86_64

と、develが入っているのは1.6だけで1.7は入っていないことがわかりました。

yumJavaの1.7を入れるとき、公開サーバ用だからdevelは要らないよね?ということで「java-1.7.0-openjdk」のほうだけを入れていたのでした。

ただ、java-1.6.0-openjdk-develは入っていたので /var/log/yum.log を確認したところ、なにかで ant が必要だった時に yumant を入れた際に java-1.6.0-openjdk-devel が入っていたことがわかりました。

すると、javacのバージョンは1.6になるため、前述のとおりjava-functionsの中で javac のバージョンを見て Java6 が選択されてしまう、という流れになったようです。


ということで最終的な結論。

CentOS6 で tomcat6 使っててjavaのバージョンを変更したい場合、java-1.7.0-openjdk-develなど「devel」のほうを入れて、/etc/tomcat6/tomcat6.conf で JAVA_HOME も明示的に指定しておくのが良い、ということでした。

トラックバック - http://d.hatena.ne.jp/stealthinu/20150220

2015-02-18 (Wed)

[]WindowsNetBeans 8組み込みのTomcatでユーザとロールの設定場所 WindowsのNetBeans 8組み込みのTomcatでユーザとロールの設定場所を含むブックマーク WindowsのNetBeans 8組み込みのTomcatでユーザとロールの設定場所のブックマークコメント

NetBeansTomcat用のservletを作っていたのですが、Tomcat Webアプリケーションマネージャなどを使うためのユーザとロールの設定場所がわからずに困ったのでメモ。


まず最初に、Tomcatインストールされているディレクトリ以下の、conf/tomcat-users.xml ファイル

C:\Program Files\Apache Software Foundation\Apache Tomcat 8.0.1\conf\tomcat-users.xml

を修正してみたのですが反映されませんでした。


そこでNetBeansのサイトで、ここの設定について書いてるページを見ると

NetBeans IDEでのWebアプリケーションのセキュリティ保護

https://netbeans.org/kb/docs/web/security-webapps_ja.html


「サービス」→「Tomcat 8.x」→「プロパティ」→「ユーザ名/パスワード

あたりで変更できそうな感じになっているのですが、ここをやってもうまくいきませんでした。

というか、それ以前にユーザ名パスワードとも変更出来ない感じでした。


ここの「接続」タブの「Catalinaのベース」を確認すると

C:\Users\【ユーザ名】\AppData\Roaming\NetBeans\8.0.2\apache-tomcat-8.0.15.0_base

となっており、Windowsの場合だとこの下の設定が実際には効いているようです。


ここに conf/tomcat-users.xml ファイルが存在しているため、これにロールとユーザを追記します。

  <role rolename="manager-gui"/>
  <role rolename="manager-script"/>
  <role rolename="manager-jmx"/>
  <role rolename="manager-status"/>
  <user username="admin" password="admin" roles="manager-gui,manager-script,manager-jmx,manager-status"/>

修正後は先程のNetBeansの右クリックメニューから「リフレッシュ」で完了です。

トラックバック - http://d.hatena.ne.jp/stealthinu/20150218

2015-02-09 (Mon)

[][]prelinkによりlsなどの基本的なバイナリのmd5sum値が変化してしまう prelinkによりlsなどの基本的なバイナリのmd5sum値が変化してしまうを含むブックマーク prelinkによりlsなどの基本的なバイナリのmd5sum値が変化してしまうのブックマークコメント

先日、すんごい焦った事例がありました。


サーバクラックされると、クラッカーにより/bin/lsや/bin/psなどの基本的なコマンドが置き換えられ、クラックされて置かれたファイルや動いているプロセスだけが見えなくなるようにして、クラックされていることがわからなくなるよう細工させられる場合があります。

そのため、そういったバイナリが置き換えられていないか、定期的にmd5sum値を取って確認するような簡単なチェック機構を入れていました。

(こういった用途にはTripwireのような専用ツールがありますが、あくまで簡易的な確認のためでここでは使っていませんでした。)

それが、確認するとmd5sumが先週と違っているという相談を受けました。

環境は CentOS 6.x です。


早速調べてみると、タイムスタンプは変化していないのにmd5sum値は違っていました。

また、md5sum値はサーバ毎に違っていたものの、バイナリサイズはどれも一緒でした。

ただ、先週はglibc脆弱性対応があり、/var/yum.log を確認してもupdateされていることが確認出来ました。

なので通常ならば glibcアップデートのせいだね〜、で済むところなのですが、今回の glibcアップデートは gethostbyname の脆弱性なので /bin/ls なんかが影響が受けるとは考えにくいところでした。


そこで、クラックされている可能性もある、という前提で調べてみることになりました。

とりあえず、新たに同じVPSで新規にCentOS6を生成して、そのmd5sum値を確認しました。

すると、その素のmd5sum値と、クラックされたことを疑っているサーバ群のmd5sum値はどれも違っており、バイナリサイズすら違っている状況でした。

また、glibcアップデートを掛けて、その後の変化を確認したのですが、md5sum値もバイナリサイズも、どちらも変化ないことを確認できました。

となると、クラックされてしまったと考えるほうが俄然優勢になってきます…


そこに救世主が!

prelinkとは共有ライブラリのリンク情報から事前にリンクを行うというものです。

それまで、確かにcronの中で見かけるものの、prelinkが何やってくれるものなのか、良く認識していませんでした。


先ほどの新規で生成したCentOS6環境に対して、

# prelink /bin/ls

すると、見事にmd5sum値が変わり、他サーバのファイルサイズと同じになることが確認できました。

また、glibcアップデート前にmd5sumを取ったものと、glibcアップデート後に取ったものを比較したところ、これも同様に変化しました。

これで、今回の変化はglibcアップデート+prelinkによるもの、と考えることが出来ました。


これまでもglibcのような基本的なライブラリに変更があった場合、md5sum値が変わっていたはずですが、それは「glibc更新したからだね」ということで流していたのだと思います。

それが今回は「gethostbyname」使っているものしか影響がない、というふうに、予測される影響範囲がわかりやすく限定されていたため、「lsならば影響受けないはず」という心理が働いて、クラックの可能性を考えてしまったのでしした。


そもそも、rpm(yum)で入れたバイナリは、同じバイナリがコピーされるわけだから、サーバが違っていてもmd5sum値は同じになる気がするのに、なんでサーバ間で違ってるんだろう?という疑問はあったのですが、これまではあまり深く考えていませんでした。

実際、インストールされたprelinkが掛かる前のバイナリと、rpmからrpm2cpioで直接取り出したバイナリとをmd5sum値を比べたところ、まったく同じものになりました。

また

# prelink -u /bin/ls

でprelinkの処理を戻すと、やはりmd5sum値がおなじになることがわかります。


CentOS6だとprelinkは cron.dailyに設定入っていて、デイリーで動くようになっています。

しかし、CentOS7だとデフォルト設定ではprelinkされないようになっているそうです。

prelinkのせいでAIDEのような改竄検知が誤動作したりやrubyのバイナリが破壊したりする問題があったそうなので、そういったことが考慮されたのかもしれません。


また今回のようにrpmで入れたバイナリのチェックには、独自にmd5sumを取るのではなく、「rpm -Va」を使ったほうが良いようです。

この場合だと、内部で prelink を戻してから比較されるため問題ないそうです。


これ、prelinkについてどんなものか知らないと、なかなか真の理由に辿りつけないと思います。

なにかの際に遭遇して、クラックされたか!?と思って焦らないように、ちょこっと覚えておいていただければ。


僕が泣き入ってる時にtwitterで色々とアドバイスいただいた、@hATrayfloodさん、@DQNEOさん、そして@hkobaさんに多謝です!!


(関連)

rpmで入れたバイナリのchecksumが一致しないと思ったらprelinkのせいだった - As a Futurist...

CentOS7からprelinkが無効に変更されていた件 - Qiita

CentOS 4.7 では prelink が ruby 1.9.1 のバイナリを破壊する - MoreslowlyWiki

CentOS6にアップグレードしたときのAIDE(改ざん検知)の注意点 | 気になるボックス

SIOS "OSSよろず" ブログ出張所: prelink されたバイナリの "rpm -V" での検証は無問題Linux Hacks:Linuxのパフォーマンスを改善する3つのTips (3/3) - ITmedia エンタープライズ

トラックバック - http://d.hatena.ne.jp/stealthinu/20150209

2015-01-05 (Mon)

[]javaのSimpleDateFormatで「YYYY」指定した時の挙動 javaのSimpleDateFormatで「YYYY」指定した時の挙動を含むブックマーク javaのSimpleDateFormatで「YYYY」指定した時の挙動のブックマークコメント

年末に突如発生したバグがあったのだけど、理由がよくわからない、というので調べてみました。


SimpleDateFormatで現在時間から日付を得ている部分があり、そこが問題だったようなのですが、その年のフォーマット指定が「yyyy」ではなく「YYYY」になっていました。

で、実はそれだと思ったんですが、テストで走らせてみると今はちゃんと動くのです。

不思議に思って下記のようにして日付を変えてテストしてみました。

Calendar cal = Calendar.getInstance();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
Date testDate = sdf.parse("2014-12-28");

SimpleDateFormat sdf1 = new SimpleDateFormat("YYYY-MM-dd");
String date1 = sdf1.format(testDate);

SimpleDateFormat sdf2 = new SimpleDateFormat("yyyy-MM-dd");
String date2 = sdf2.format(testDate);

すると「2014-12-27」まではちゃんと「2014」を返すのですが「2014-12-28」からは「2015」を返すようになっていました。


で、なんでそんな仕様になってるの?と思ったら

と教えてもらいました。

Androidの公式アプリでもこの地雷を踏んでいたとは…


ややこしい日付の書式について - dechnostick's blog

日付フォーマット yyyy と YYYY の違い - 強火で進め


Java 7 から存在する仕様で「Y」は「暦週の基準年」を表すんだそうです。

SimpleDateFormat (Java Platform SE 7 )


これ、年末になってからはじめて発火するから、ほんと嫌がらせのようなバグになりますね。

トラックバック - http://d.hatena.ne.jp/stealthinu/20150105

2014-12-24 (Wed)

[][]CakePHPのUploadPackにPDFの画像化とサムネイル生成対応 CakePHPのUploadPackにPDFの画像化とサムネイル生成対応を含むブックマーク CakePHPのUploadPackにPDFの画像化とサムネイル生成対応のブックマークコメント

これはCakePHP Advent Calendar 2014の15日目の記事です。大変遅くなってしまってすみません…


CakePHPにはたくさんの便利なプラグインがあります。

その中に、UploadPackという簡単にファイルのアップロードを行えるプラグインがあります。

特に、画像のアップロードを行うとそのサムネイルや指定サイズにリサイズした画像を作る機能があり、便利に使えます。

ただUploadPackでサムネイル対応してくれるのは画像ファイルだけで、PDFのサムネイルや画像化の機能はありません。

以前の案件でその機能が必要だったため、UploadPackにPDFも画像化とサムネイル生成をするための機能を追加したので、公開します。

https://github.com/stealthinu/uploadpack/commits/convert_pdf_to_image


PDFから画像を生成するためには、GhostScriptを外部コマンドを呼んで行っています。

実は始めのバージョンではImageMagickで(内部でGhostScriptが呼ばれて)行っていました。

しかし、実際に稼働させてみるとCMYK(0,0,0,0)の色と透明色で色の違いが出てしまいました。

RGBではこの問題は起きず、CMYKの場合でのみ発生しました。

これを作ったのは印刷関係向けのWebサービスだったため、RGBの画像データよりもCMYKの画像データでアップロードされてきていたのでした。

最初、色ズレあるということで、ICCプロファイルの問題かと思い(ImageMagickで色味がおかしい、という話はだいたいICCプロファイルの問題に帰着するので)色々と調べたのですが、ICCプロファイルの問題ではなく、CMYK(0,0,0,0)と透明色とで色の違いが出ているということがわかりました。

また調査していく中で、GhostScriptを直接呼び出した場合はこの色ズレの問題が起こらず、変換後の画像品質も良い、ということがわかりました。

さらに色々とぐぐっていた中でGS直呼び出しよりImageMagick経由のほうがパフォーマンスがだいぶ悪くなるという話もありました。


というわけで、最終的にはImageMagickを使わずに直接gsコマンドを呼び出して使うような形になっています。

PHPでImageMagick使うこと自体がなにかと大変だったり、この案件Windowsサーバだったため、ImageMagickをWindowsのxamppに入れるのはだいぶ大変なので、そういう点からもImageMagick入れずに済むならそっちのほうが良いと思います。


CakePHPアドベントカレンダーなのに、ほぼImageMagickネタとなってしまいましたがお許しを…

[][]postscreenってどんなもの? postscreenってどんなもの?を含むブックマーク postscreenってどんなもの?のブックマークコメント

これはPostfix Advent Calendar 2014の18日目の記事です。こちらも大変遅くなってしまってすみません…


Postfixには2.8以降からpostscreenという機能があります。が、あまり知られていないと思います。

これはひとことで言うと、超軽量簡易スパムフィルタです。


Postfixにはsmtpd_*_restrictionsをはじめ、policydやfilterなど色々とスパムフィルタするための仕組みが用意されています。

にもかかわらずpostscreenが用意された理由は、postscreenは超軽量のためフィルタをすることで負荷も下げることが出来るからでしょう。

やまやさんPostfix Postscreen Howto - どさにっきで「トリアージ」と表現されているのですが、まさにそんな感じで、postscreenで怪しいメールだけをより詳しいチェックへと回してやり、大丈夫そうなメールは通常の処理で行う、という大まかなよりわけが行えるというものです。


PostfixSMTPセッション毎に一つsmtpdのプロセスが立ち上がるため、例えばtarpittingでのフィルタを掛けると、スパムによりsmtpdの同時起動数が増えてしまい、メモリ消費量などが増えてしまうという問題がありました。(そのため、接続が切れたら即smtpdプロセスが死ぬようなパッチを書いたりしました)

これに対してpostscreenでは、smtpdの前段に位置して1プロセスで処理を行うため、大量のスパムからの接続があってもプロセスの爆発が起こらずにフィルタすることが出来るようになっています。


postscreenで使えるフィルタは下記Howtoページから確認することが出来ます。

2.8.2のころから使えるフィルタは増えていないので、日本語訳の情報がそのまま使えます。


公式のPostscreen Howto

Postfix Postscreen Howto


Postfix-2.8.2のものですが、やまやさんによるPostscreen Howtoの日本語訳。

Postfix Postscreen Howto


マニュアルにpostscreenではどんなフィルタが利用できるのかが書いてありますが、どんなものかざっとわかるように短くまとめてみました。

  • Pregreet test

以前pregreet detectionでエントリーを書いたのですが、「220-server.example.com ESMTP Postfix」みたいに嘘のグリーティングメッセージを返して、答えを返しちゃったら負け、という手法

  • DNS White/blacklist test

複数の(DNSBL毎に重み付けした)DNSBLでマッチさせトータルが閾値以上になったかどうかを見る。

  • Command pipelining test

SMTPにはpipeliningをアナウンスされていなければ一応答ごとに一コマンドしか受け付けないのだが、スパムはそれを無視して連続してコマンドを送ってくる場合が多いため、それで判断する。

  • Non-SMTP command test

オープンプロキシを使って送ってくるbotだと、例えばHTTPで使われるCONNECTのようなSMTPには存在しないコマンドを使ってくることがあるため、そのようなコマンドで検知する。

  • Bare newline test

SMTPでは行が「CR LF」で終了することになっているのだが、単に「LF」だけで送ってくるものを引っ掛ける。


こうやって見るとどれも結構トリッキーなもので引っ掛けているなと感じるのではないかと思いますが、結構な確度でbotが引っ掛けられるのではと思います。


ほとんど、昔やまやさんが書かれたものをまとめただけ、というエントリーになってしまいましたが、これでpostscreenの認知度が少しでもあがればいいなと思います。


(参考)

Postfix Postscreen Howto

Postfix manual - postscreen(8)

2010年11月17日(水) Postfix Postscreen Howto - どさにっき

2011年4月8日(金) Postfix Postscreen Howto - どさにっき

Postfix Postscreen HowtoPostfix 2.8.2 に同梱の POSTSCREEN_README の翻訳)

pregreet detection - モーグルとカバとパウダーの日記

2014-12-11 (Thu)

[][]Postfixでのサブミッションスパムの簡易対策方法 Postfixでのサブミッションスパムの簡易対策方法を含むブックマーク Postfixでのサブミッションスパムの簡易対策方法のブックマークコメント

これは Postfix Advent Calendar 2014 の11日目の記事です。


サブミッションスパムという、盗んだアカウントを使って、botから送信認証を行ってスパムを出すというスパム送信手段があります。

これをされると、自分のメールサーバから大量のスパムが出されるため、各種DNSBLに登録されてしまい、このメールサーバからのメールが届かなくなったり、メールキューが爆発したり、バウンスメールが大量に届いてスプールが爆発したり、とろくなことがありません。

2年半前にこれがすごい流行った時があり、メールサーバ管理者の方には、痛い目にあった方も結構いるのではないでしょうか。


その時にサブミッションスパムについての解説を書いたエントリーです。

「サブミッションスパム」による5/15〜16のメール障害の解説と対策 - モーグルとカバとパウダーの日記


さて、2年半前に起きてその後どうなったか、というと、その後はその時のようにそこらじゅうでこれの問題が発生する、ということは起こっていません。

でも、無くなったわけじゃなく、忘れた頃に時々またやられるのです。

すると、ぶつくさ言いながら該当アカウントを停止して、DNSBLに解除申請をし、ユーザーからの問合せに対応しなければならなくなります。


この手法に対しての普遍的な対策をしようと思うとなかなか難しく、policydのようなものを使ってスロットリングするしかないかと思います。

が、このサブミッションスパムを使ってくるスパマーは限られており、その癖がだいたい決まっているので、実は小手先の手法でもそこそこ対策が可能です。

このスパマーはsasl認証が通ったら、こちらの返信を全く待たずに即送信をしてきていました。 (0秒でpipeliningで送ってくる)

なので、1秒でも遅延を掛ければ落とすことが出来ます。

が、通信遅延などで通ってしまう場合もあり、これまでの知見からは海外からであれば5秒くらい、jpドメインからなら1秒の遅延とするとだいたい良い感じになるようです。

実は先のエントリーでもこのことを書いているのですが、具体的な設定方法についてまでちゃんと提示していませんでしたので、今回は具体的な設定を書きたいと思います。(つまり… 過去エントリーの焼き直しですね。すみませんっっ _o_)


サブミッションの設定をしているところに設定を行いますので、master.cfの設定を確認します。

元々は下記のようにsubmission設定がされていたとします。

/etc/postfix/master.cf(元)

submission inet n       -       -       -       -       smtpd
    -o smtpd_etrn_restrictions=reject
    -o smtpd_sasl_auth_enable=yes
    -o smtpd_client_restrictions=permit_sasl_authenticated,reject

これに接続元逆引き名でのチェックを追加してやります。

ルールはmaster.cfだけでは書けないため、main.cfへの追記と遅延のルール用のファイルも新規で作成します。

「.jp」ドメインからなら1秒、その他からは5秒遅延を掛けます。

/etc/postfix/master.cf(変更後)

submission inet n       -       -       -       -       smtpd
    -o smtpd_etrn_restrictions=reject
    -o smtpd_sasl_auth_enable=yes
    -o smtpd_client_restrictions=$tarpit_submission_spam
    -o smtpd_recipient_restrictions=permit_sasl_authenticated,reject

/etc/postfix/main.cf(追記)

tarpit_submission_spam =
    check_client_access    regexp:$config_directory/tarpit_submission_spam

/etc/postfix/tarpit_submission_spam(新規)

/\.jp$/ sleep 1
/.*/    sleep 5

「-o」で設定を追加する場合にはパラメータを渡すことが出来ないので、main.cfにルールを書いてそれを呼び出す形にしていることに注意してください。

また、同じsmtpd_client_restrictionsで送信認証と遅延のルールを書いてしまうと意図通りにならないため、smtpd_client_restrictionsとsmtpd_recipient_restrictionsの2回に分けて行っています。

2014-11-06 (Thu)

[]JavaのFileUploadがIE10/11でだけうまく動かない JavaのFileUploadがIE10/11でだけうまく動かないを含むブックマーク JavaのFileUploadがIE10/11でだけうまく動かないのブックマークコメント

Javaでファイルアップロード用のcommonライブラリFileUploadを利用しているアップローダーが、IE10/11でだけうまく動かない、という問題が発生しました。


JavaScriptのFormDataオブジェクトを使ってjQueryajaxでデータを送信しているのですが、IEからだと受け取ったサーバ側でエラーがでていました。

エラーの応答とtomcatのログを確認すると、下記のエラーが記録されていました。

原因 javax.servlet.ServletException: org.apache.commons.fileupload.FileUploadException: Stream ended unexpectedly


どうもIEから送られるmultipart/form-dataではFileUpload側でデータ終了の検知がうまくいかないため、エラーになっているようでした。

そこでこのエラーメッセージから情報を探してみると、同様の現象がFlushクライアントからでも発生しており、そのパッチがあたっていることがわかりました。


http://commons.apache.org/proper/commons-fileupload/changes-report.html

"Stream ended unexpectedly" when posting from a Flash client Fixes FILEUPLOAD-143. Thanks to Luke Scott.


利用していた環境では1.2が利用されており、この修正は1.3で当たっているため、FileUploadを最新の1.3.1にアップデートして試してみたところ、IE11でも問題なく動くことが確認できました。

というわけで、IE10/11だけでのみFileUploadとFormData使ったアップロードがうまくいかない場合、FileUploadのバージョンが1.3より古い場合は「commons-fileupload-1.3.1.jar」など1.3以上にバージョンアップすることをおすすめします。


…と書いたのですが、うまく行ったように思ってたのが勘違いでした…

1.3.1に変更しても改善していませんでした。うああ orz


このエントリーを書こうとしてFormDataでググっていた時に出てきたエントリーがあり、これと同じ問題のようでした。


JavaScript - ハマりメモ:IE10でFormData Objectを使った$.ajax()が失敗 - Qiita

http://qiita.com/marsa746079/items/a3c69465d605a0078a6b


ここで紹介されている、この問題を解析したエントリーによると


Ajax with FormData is Broken on IE10 / IE11 in Some Conditions

http://blog.yorkxin.org/posts/2014/02/06/ajax-with-formdata-is-broken-on-ie10-ie11


  • radioやcheckboxのような入力欄がフォームの最後にある
  • それらの入力欄にチェックが入っていない
  • FormDataオブジェクトajaxで送信している
  • IE10/11で送信する

という条件だと送信データのフォーマットに下記のような壊れたゴミデータがついてしまうそうです。

-----------------------------7de3af25e0204
Content-Disposition: form-data; name="
-----------------------------7de3af25e0204--

ということで、フォームの最後

<input type="hidden" name="_dummy">

というダミーの入力欄をいれてやることで解決出来ました。

なんというバッドノウハウ。はあ…

トラックバック - http://d.hatena.ne.jp/stealthinu/20141106

2014-10-29 (Wed)

[]CentOS6でMySQL5.1→5.6へのアップデートの方法 CentOS6でMySQL5.1→5.6へのアップデートの方法を含むブックマーク CentOS6でMySQL5.1→5.6へのアップデートの方法のブックマークコメント

CentOS6のMySQLで、全文検索を行うためにMroongaを入れて試してみたかったのですが、CentOS6では標準ではMySQL5.1が入っており、バージョンを5.5以上にする必要がありました。

これが結構厄介だったのでアップデート手順をまとめました。


状況によってはmysql起動時にエラーが出たりlogfileの削除などをしなければならなくなったりするため、まずmysqldumpで全データベースバックアップを取ってから行うようにします。


必須なのは


パッケージのアップデート

CentOS5やCentOS6で標準のMySQLを5.5や5.6にするというエントリーは結構あるのですが、自分の場合は最終的にこちらのエントリーが最も参考になりました。


mysqlを5.1->5.6に再インストールする

http://blog.10rane.com/2014/07/28/reinstall-mysql56/


mysql55のパッケージを利用するものだと、一旦依存パッケージをアンインストールする必要がありました。

サービス中のサーバに適用する必要ができた場合を考え、MySQLのみをアップデートする方法を探しました。

こちらの手順では、現在インストールされているMySQL5.1に依存したパッケージを一旦削除すること無く、MySQL5.6にすることが可能でした。

5.1のアンインストールの前にMySQL-shared-compatというパッケージを入れることで、既存の依存パッケージをアンインストールすること無く、5.6をインストールすることが出来るようになります。


以下のMySQL公式ダウンロードサイトのミラーから、MySQL-5.6のMySQL-shared-compatの該当するrpmを取得します。

古いバージョンのものは無くなるため、

http://ftp.jaist.ac.jp/pub/mysql/Downloads/MySQL-5.6/

を確認して存在している自分のOSバージョンにあったもの(「el6 | el7」と「x86_64 | i386」)を選びます。

例えばCentOS6の64bit版なら「MySQL-shared-compat-5.6.21-1.el6.x86_64.rpmなどです。


MySQL-shared-compatをインストールし、5.1のMySQLアンインストールした後、MySQLの公式サイトで提供されているCentOS6用の設定を入れ、5.6を入れ直すという手順にになります。

wget ftp://ftp.jaist.ac.jp/pub/mysql//Downloads/MySQL-5.6/MySQL-shared-compat-5.6.21-1.el6.x86_64.rpm
sudo rpm -Uvh MySQL-shared-compat-5.6.21-1.el6.x86_64.rpm
sudo yum remove mysql mysql-server
sudo yum install http://dev.mysql.com/get/mysql-community-release-el6-5.noarch.rpm
sudo yum install mysql mysql-devel mysql-server

Vagrant等で割り当てメモリ不足の対応

自分はvagrant上の仮想サーバで試していたのですが、5.6に上げると下記のようなエラーが出て起動できないという状況になりました。

InnoDB: mmap(137363456 bytes) failed; errno 12

[ERROR] InnoDB: Cannot allocate memory for the buffer pool

これはメモリが足りないために起こるため、vagrantの割り当てメモリを増やして対応します。


Vagrant+VirtualBox+CentOS環境でMySQL5.6が起動しない場合の対処法 - 憂鬱な世界にネコパンチ

http://nekopunch.hatenablog.com/entry/2014/03/22/020507


Vagrantfile

config.vm.provider :virtualbox do |v|
  v.customize ["modifyvm", :id, "--memory", 1024]
end

InnoDBの設定変更によりlogfileのファイルサイズ変更によるエラー対応

メモリを増やして良くなったものの、また別のエラーが発生するようになりました。

[ERROR] InnoDB: auto-extending data file ./ibdata1 is of a different size 640 pages (rounded down to MB) than specified in the .cnf file: initial 768 pages, max 0 (relevant if non-zero) pages!

2014-10-29 08:29:38 2528 [ERROR] InnoDB: Could not open or create the system tablespace. If you tried to add new data files to the system tablespace, and it failed here, you should now edit innodb_data_file_path in my.cnf back to what it was, and remove the new ibdata files InnoDB created in this failed attempt. InnoDB only wrote those files full of zeros, but did not yet use them in any way. But be careful: do not remove old data files which contain your precious data!

これは設定変更後 ibdata1 当のファイルサイズが違ってしまったために起きるそうで、ファイルを削除して対応するしかないようです。

が、これの理由じゃない時にlogfileを削除してしまうと色々と問題が起きることがあったので、一旦バックアップとっといてからやったほうがいいと思います。


my.cnfでinnodb関連の設定後、MySQLが起動しなくなった | システム開発ブログ(システム開発のアイロベックス

http://www.ilovex.co.jp/blog/system/projectandsystemdevelopment/mycnfinnodbmysql.html

cd /var/lib/mysql
sudo mkdir logfile_backup
sudo mv ib_logfile0 ib_logfile1 ibdata1 logfile_backup/

my.cnfの設定変更

5.5以降からデフォルト文字コードの指定とslow-queryなどのlog出力の指定方法が変わっているため、設定を変更する必要があります。

下記ページ等を参考に、下記のように設定を行いました。

my.cnfの変更点のせいでMySQL5.6がなかなか起動しない件 - 文系プログラマによるTIPSブログ

http://treeapps.hatenablog.com/entry/2013/02/10/my.conf%E3%81%AE%E5%A4%89%E6%9B%B4%E7%82%B9%E3%81%AE%E3%81%9B%E3%81%84%E3%81%A7%E3%81%AA%E3%81%8B%E3%81%AA%E3%81%8BMySQL5.6%E3%81%8C%E8%B5%B7%E5%8B%95%E3%81%97%E3%81%AA%E3%81%84%E4%BB%B6

MySQL文字化けしたときの対処法 - Qiita

http://qiita.com/WizowozY/items/5d7224be92aa8364a42a

Programster: MySQL 5.6 - Enable Slow Query Logging

http://programster.blogspot.jp/2014/02/mysql-enable-slow-query-logging.html


/etc/my.cnf

[mysqld]
character-set-server=utf8
skip-character-set-client-handshake

slow_query_log=1
slow_query_log_file=/var/log/mysqld/slow-query.log
long_query_time=0.1

また、MySQL5.6にすると /etc/my.cnf の sql_mode に下記設定が加えられてしまい、これまでのSQLがcreate table時にエラーが起きる場合があるようです。

なので以下のsql_modeの行はコメントアウトします。


/etc/my.cnf

# Recommended in standard MySQL setup
sql_mode=NO_ENGINE_SUBSTITUTION,STRICT_TRANS_TABLES

データベースアップグレード

これで起動はするようになってくるのですが、一部操作が出来ない状況が発生しました。

これはログを見ると起動時に下記のようなエラーが出ているのでわかります。


/var/log/mysqld.log

[ERROR] Native table 'performance_schema'.'users' has the wrong structure


mysql_upgrade というコマンドが用意されているため、これを実行することでデータベースアップグレードが行われて解決できます。

mysqldが動いている状況で利用します。


MySQLを5.1から5.6.10に上げたらなんか壊れた話 | いちよんこーど

http://14code.com/blog/20130625_504

homeberwでMySQL5.6にupgradeしたらユーザーが作成できなくて困ったときのメモ - Qiita

http://qiita.com/shikataka/items/4783a53ac2e4b2a3141f


mysql_upgrade -u root -p

アップグレードが行われます。

mysql再起動してログにエラーが出ていないか確認して下さい。

トラックバック - http://d.hatena.ne.jp/stealthinu/20141029