satakesatakeの日記

|

2015-12-10

Javaで初めてリフレクション使った

| 17:06

普段スクリプト言語とか使ってると、リフレクションとか意識せずにこんな風にやっちゃったりします。

use SampleClass;

my $class = new SampleClass();
my $field = "fooBarBaz";
my $value = $class->$field; # get
$class->$field(42); # set

あれ、Perlってこんなんだっけ。まあいいや。ようするに、ここでは、SampleClassのインスタンスが持つ、fooBarBazというフィールドにアクセスしたいっていう例(これはSampleClassがClass::Accessor::Fastとかを使っているという前提)。スクリプト言語だとこんな感じでできちゃうけど、Javaじゃこういうわけにはいかない。

ちょっとはまったのは、フィールドへの書き込みだった。

import java.lang.reflect.Field;

public class ReflectionTarget {
  String foo;
}

public class ReflectionSample {
  public void main() {
    ReflectionTarget target = new ReflectionTarget();
    this.reflectionTest(target, "foo");
  }

  public void reflectionTest(ReflectionTarget target, String fieldName) {
    try {
      Field field = target.getClass().getDeclaredField(fieldName);
      
      //read
      String foo = field.get(target);

      //write
      field.setAccessible(true);
      field.set(target, "TEST");
      
    } catch (NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException e) {
      e.printStackTrace();
    }
  }
}

これがコードの例。

「field.setAccessible(true);」

この一行がないと怒られてシュンとなる。

まあ、これだけなんですけど。Javaに慣れてる技術者なら何をいまさら的な内容ですが、備忘録として。

未確認事項

Accessibleはpublicメンバ以外の場合にtrueにするみたいな話もあるようだが、自分が書いたコードでは間違いなく、publicなメンバでもtrueにせよ、と怒られた。

ただ、ここにはこう書いてある→http://docs.oracle.com/javase/8/docs/api/java/lang/reflect/AccessibleObject.html

By default, a reflected object is not accessible.

これはどう読んでも、setAccessibleでtrueにせよ、としか読めないんだが。(というか、上のコードではアクセス指定子がprivateでもpublicでもなく、デフォルトだからなのかな?)

2015-12-08

TLS handshake failed で、特定の宛先にメールが届かない!

| 11:55

先日、以下のようなエラーメールが届いた(抜粋)。

   ----- Transcript of session follows -----
<to@example.com>... Deferred: 403 4.7.0 TLS handshake failed.
Warning: message still undelivered after 4 hours
Will keep trying until message is 5 days old

TLSハンドシェイクが失敗して、宛先で暗号化された通信が復号化できないというものだ。

maillogには以下が記録されていた(from@example.netからto@example.comに送信した際の例)。

Dec  8 11:20:19 mail sendmail[7102]: STARTTLS=client, error: connect failed=-1, SSL_error=1, errno=0, retry=-1
Dec  8 11:20:19  sendmail[7102]: STARTTLS=client: 7102:error:14082174:SSL routines:SSL3_CHECK_CERT_AND_ALGORITHM:dh key too small:s3_clnt.c:2429:
Dec  8 11:20:19 mail sendmail[7102]: ruleset=tls_server, arg1=SOFTWARE, relay=example.com, reject=403 4.7.0 TLS handshake failed.
Dec  8 11:20:19 mail sendmail[7102]: tB82KJiX007100: to=<to@example.com>, ctladdr=<from@example.net> (631/631), delay=00:00:00, xdelay=00:00:00, mailer=esmtp, pri=121093, relay=example.com. [XXX.XXX.XXX.XXX], dsn=4.0.0, stat=Deferred: 403 4.7.0 TLS handshake failed.

また例のDH keyが小さすぎるというやつだ。

ただ、これは送信サーバに原因はなく、宛先サーバメンテナンス不足で発生する問題だ。

先の、Logjam Attack問題を解消するために、DH Keyのビット数を大きくしたことが災いしたというか、宛先サーバがクソというか(以下略

対処法としては、次の二点が挙げられる。

  1. 宛先サーバ無能な管理者をぶちのめし、Logjam Attack対策を取らせる(DH Keyのビット数を大きくする)
  2. 宛先サーバに対して、TLSでの暗号化を取りやめる

さすがに、1.は難しいため、2.の対策をとることにした。

/etc/mail/access ファイルに次の行を追加して宛先サーバへのTLS通信無効化。次いでこの設定を反映させる。

Try_TLS:example.com                      NO

ちなみに、Try_TLS: NOでも良いようだが、こちらは全体に対してTLSを試みなくなるので、あまりよろしくない気がする。

ただ、前述のエラーメールが届くたびに、ホワイトリストを更新するというのも面倒な話だ。かといって、TLS暗号化しないのはもっと微妙である。

2015-11-17

mailmanで新規メーリングリストを作ったのに、メールを送ったらUser knownとか言われて拒否られる

| 17:23

なぜか。

久しぶりにメーリングリストを作ったので、運用方法を忘れている。

http://nextstageone.g.hatena.ne.jp/satakesatake/20101221/1292927892

上記URLの内容にもあるように、以下のことに原因がある。

なんと、mailmansendmailで運用している場合は、新しくMLを作成してもエイリアスに新しいアドレスが追加されないため、手動で追加してやる必要がある。

要するに/etc/aliasesや関連するsendmailエイリアスが正しく設定されていないのだ。

sendmail.mcを確認するとこのような記述*1

define(`ALIAS_FILE', `/etc/aliases, /etc/aliases.mailman')dnl

/etc/aliasesに加え、/etc/aliases.mailmanエイリアスのファイルとして設定されている。確認してみたら、これが古いままだった。

/etc/mailman/aliasesには正しいリストが出来上がっていたので、それをターゲットに、/etc/aliases.mailmanシンボリックリンクにし、sendmail再起動したが、うまく認識されていないようだ。弊社環境では、sendmail再起動するたび、エイリアスコンパイルし、dbファイルを再生成するのだが、シンボリックリンクではそれがうまく動作しないらしい。

仕方がないので、正しいリストをコピーして、sendmail再起動

今度はうまくいったようだ。

なぜ、エイリアスが正しく設定されていなかったのか。最近、弊社はウェブサイトwixというCMSで管理する方法に変更した。だが、wixhttpsをサポートしていないため、メールフォームなどは旧環境のサーバで動作させている。

wix版と旧環境を両立させるため、htttpsのURLが変更された。というか、した。これが仇となり、mailman管理サイトで新規MLを作った際に、ページ遷移でエラーが出るようになってしまった。おそらくページ遷移先で最終処理を行うと、うまくエイリアスが設定されるのかもしれない。

それは全く関係なく、常に手動で行う必要があったのかもしれない。本来ならば、新規作成をトリガーにし、エイリアスが更新されなければならないのだが・・・。

*1:これは弊社独自の設定なので、当てはまらない環境もあるだろう

2015-11-16

送信時に"dh key too small"エラー

| 19:34

Thunderbird 38.3.0にて、メール送信エラーが発生した。なお、宛先にはメールは到着していない。

maillogにはこんな記録が残っていた。TLSのハンドシェイク時のdh keyがtoo smallだというエラーだ。なお、この宛先のサーバは、自分が管理しているのだが、過去1年間、業務で使われなかったため、半分放置されていた。

Nov 16 18:06:53 ns-1 sendmail[11116]: STARTTLS=client, error: connect failed=-1, SSL_error=1, errno=0, retry=-1
Nov 16 18:06:53 ns-1 sendmail[11116]: STARTTLS=client: 11116:error:14082174:SSL routines:SSL3_CHECK_CERT_AND_ALGORITHM:dh key too small:s3_clnt.c:2429:
Nov 16 18:06:53 ns-1 sendmail[11116]: ruleset=tls_server, arg1=SOFTWARE, relay=example.com, reject=403 4.7.0 TLS handshake failed.
Nov 16 18:06:53 ns-1 sendmail[11116]: tAG96rbm011114: to=<to@example.com>, ctladdr=<from@example.net> (625/625), delay=00:00:00, xdelay=00:00:00, mailer=esmtp, pri=120777, relay=example.com. [XXX.XXX.XXX.XXX], dsn=4.0.0, stat=Deferred: 403 4.7.0 TLS handshake failed.

これは先に発生した、メール受信時のエラーと同様の現象である。*1参照→http://nextstageone.g.hatena.ne.jp/satakesatake/20150724/1437725683

SMTP(-AUTH) + STARTTLSを使用して(今度は)送信した際に、送信先サーバdh key(DH PARAMETER、DHパラメータ)のビット数が低いことが原因などとは思いもよらなかった。

送信先サーバにも上記URLと同様の対策を施してやれば解決するはず。各所でこれは問題にならないのだろうか? それともうちだけ?

サーバ管理者の仕事(セキュリティ対策)と言えば、そうなので、あまり表に現れない問題なのかもしれない。

ただ、Tunderbirdの問題だとすると、宛先サーバDHパラメータ低ビット問題で、送信できない宛先がまだこの世に存在する可能性も否定できない。ちょっと嫌な感じだ。

右記も参照のこと。ただし、これは消極的な対応策である。→https://support.mozilla.org/ja/kb/thunderbird-and-logjam

アドオンの使用は長期的な解決策にはならず、サーバの問題を修正する代替にもなりません。これを使用することは、中間者攻撃の危険性がありますが、メールの利用を優先して、サーバ管理者がより安全な鍵ペア生成してサーバインストールするまでの息継ぎにはなるでしょう。

*1:エラー発生時、Thunderbird以外のメーラーでは検証していないので、他メーラーで同様のエラーが出るかどうかは不明

2015-11-05

selinuxとうまく付き合いたい

| 18:34

最近、SELinuxを停めるのは負けたような気がしているので、きちんとSELinuxを停めない運用をするように心がけている。

で、サーバyum updateして、selinuxバージョンアップされたせいなのか、kernelアップデートされたせいなのか、皆目見当がつかないが、突然、samba共有がアクセス拒否しやがるんですよ。

# setenforce 0

とかして、一時的にSELinuxをPermissiveして試すと、アクセスできる。これはなんだか、ディレクトリのコンテンツタイプというのがアップデートで更新されてしまったのかもしれない。

確認してみると、こんな感じだ。ちなみにこのディレクトリは仮名だが、httpdのドキュメントルートでもある。そのため、httpd_sys_rw_content_tが設定されている。

# ls -Z /var/share
drwxr-xr-x. share share system_u:object_r:httpd_sys_rw_content_t:s0 share

そして、SELinuxをEnfocingに戻す。

# setenforce 1

対象のディレクトリのタイプを変更する。※これは一時的な設定らしい

# chcon -t -R -t public_content_rw_t /var/share

今度は、アクセス拒否されなかった。だが、ブラウザからhttpdを通してphpの動くURLにアクセスしてみると、パーミッションエラーでログが書き込めないとか言いやがる。

おそらく、httpd_sys_rw_content_tが外されたからだ。複数のタイプを与えられればすごくうれしいんだが、やり方がわからないので、ちょっと調べてみる。

|