tokuhirom's blog

Yosemite にしたら AppleScriptEngine.jar がどやこやで Eclipse でコンパイルできなくなった。

http://support.apple.com/kb/dl1572 から Java for OS X 2014-001 を入れたら治った。よかった。

Created: 2014-10-25 23:28:04
Updated: 2014-10-25 23:28:04

[java] webscrew に basic auth header のパーサーつけた

表題の通りです。

avans で Authorization header をパースするのがダルいので、一応そのへんの機能をつけた。

(webscrew とは web application を作るときに必要な部品を集めたライブラリで、Perl でいうところの Plack に相当するものです。)

Created: 2014-10-23 20:21:46
Updated: 2014-10-23 20:21:46

avans 0.34.0 出した

avans の 0.34.0 を出した。 クエリパラメータが足りていない場合などに例外をあげていたのだが、例外的な状況じゃないので、エラーレスポンスを真面目に返すようにした。

Created: 2014-10-10 13:05:57
Updated: 2014-10-10 13:05:57

[java] SecureRandom のアルゴリズムの選択について

前提

Java SE 8 + Linux 前提です。

Java で暗号的に安全な乱数をえる

Java で暗号的に安全な乱数を得るには SecureRandom クラスを利用します。 SecureRandom ではいくつかの乱数生成アルゴリズムをサポートしています。

各プラットフォームでもっとも安全な SecureRandom の実装は ${JAVA_HOME}/jre/lib/security/java.security の securerandom.strongAlgorithms という項目に書いてあります。 SecureRandom#getInstanceStrong() で取得できるのはこれです。

インスタンスの取得方法

  • new SecureRandom() でデフォルト実装が得られます
    • OSX や linux では NativeBlocking です(SHA1PRNGの場合もある)
  • SecureRandom#getInstance(name) で名前を指定して実装を得られます
  • SecureRandom#getInstanceStrong() で、プラットフォームでもっとも強力な実装が得られます
    • OSX や linux では NativePRNGBlocking です
    • /dev/random を利用します

各アルゴリズムの詳細

実装は以下のようになっています。

SHA1PRNG (Initial seeding is currently done via a combination of system attributes and the java.security entropy gathering device)
NativePRNG (nextBytes() uses /dev/urandom, generateSeed() uses /dev/random)
NativePRNGBlocking (nextBytes() and generateSeed() use /dev/random)
NativePRNGNonBlocking (nextBytes() and generateSeed() use /dev/urandom)

http://docs.oracle.com/javase/jp/8/technotes/guides/security/SunProviders.html

NativePRNGBlocking は /dev/random から取得するので、遅いです。 あまり利用されていない開発サーバーなどでは 30 秒ぐらいかかります。 鍵の生成などにはこれを利用するべきですが、ちょっとしたトークンの生成などに利用すると、めっちゃ遅くてなけます。

トークンの生成等には NativePRNG または NativePRNGNonBlocking を利用すれば十分かと。

ちなみに、NativePRNGBlocking と NativePRNGNonBlocking は最近導入されたようです。

For UNIX-like platforms, two new implementations were introduced which provide blocking and non-blocking behavior: NativePRNGBlocking and NativePRNGNonBlocking. http://docs.oracle.com/javase/8/docs/technotes/guides/security/enhancements-8.html

securerandom.source の変更について

インターネットを見ていると、securerandom.source を変更して /dev/urandom を見るようにしろ、という記述を見かけますが、これは Java 8 の世界では間違ったやり方だと私は思います。

NativePRNGNonBlocking を利用するように実装を変更するのが正しいアプローチだと私は考えます。

tips

/dev/random がどんどん出てくるかどうかは head -n 1 /dev/random で調べることができる。

まとめ

とりあえず弱いよりは強い方がいいだろってことで SecureRandom#getInstanceStrong() を呼んだりしてるとサービスが刺さる。

参考文献

Created: 2014-10-09 12:50:50
Updated: 2014-10-09 12:50:50

[ruby] スクリプトの実行結果をログファイルに書く

Ruby で書いたスクリプトの実行結果をログファイルに残したい。しかし tee とかでトルのもめんどくさい。 そんな時は ruby の STDOUT/STDERR をロガーのパイプに置き換えてしまえばよろしい。 ついでに、どの行がいつ出たかがわかりやすいようにタイムスタンプもつけて欲しい。

そんな時ってありますよね。そんな時に使えるスニペットが以下になります。

logfile = Time.now.strftime("#{LOG_BASE}/%Y-%m-%d.%H%M%S.log")
log_fh = open("| /usr/local/bin/tai64n | tee -a '#{logfile}' | /usr/local/bin/tai64nlocal", 'a') 
log_fh.sync = true
$stderr.reopen(log_fh)
$stdout.reopen(log_fh)

本当は、もっと ruby らしい解法があると思うけど、

  • 標準ライブラリでできる
  • 行数が少ない

という条件を満たすために、UNIX 的解法で済ませた。

Created: 2014-10-03 11:43:58
Updated: 2014-10-03 11:43:58

[ruby] readline がなくて後から入れたい時

readline ライブラリは ruby の標準ライブラリなはずだけど入ってない環境もあるので

gem install rb-readline

しておく必要がある。

Created: 2014-10-02 17:28:03
Updated: 2014-10-02 17:28:03

LL から Java に移行した人がはまりがちなこと

こんにちは。Java 初心者です。

Java 初心者、得に LL から Java に来た人にありがちな問題について社内向けに書いたものをオープンアンドシェアさせていただきます。

前提として、我々は Java 8 でガンガン攻めているということをご承知おきください。

また、自分がこの数ヶ月で「うわー。こうしとくべきだったのかー」と気づいたやつをドヤ顔で語っているということにもご注意ください。

【追記】 対象は中規模 B2C の場合です(中規模というのは facebook より小さいという程度の意味です)

例外を握りつぶさないようにしよう

Eclipse が生成する以下のようなコードをそのまま残しているケース。 これは言うまでもなく良くないですね。デバッグが困難になります。

try {
} catch (IOException e) {
    e.printStackTrace();
}

Perl でいうと eval { ... }; warn $@ if $@; みたいなもんですからね。。

賞味、ウェブアプリケーションを書いている場合、何も考えたくない時は以下のように RuntimeException でくるんで rethrow してあげるのがいいです。 try { ... } catch (IOException e) { throw new RuntimeException(e); }

フレームワークがなんか適当にエラーページ出してくれます。

基本的に、ウェブアプリケーションではリカバリ可能な例外というものがほぼ無いんで、何も考えずに RuntimeException にしちゃって問題ないです。たいがいの場合は。(バッチ処理やワーカーの処理の場合はこの限りではありません)

null を return しないようにしよう

Java 8 で書いている場合、基本的に null を返してはいけませんね。Optional 使いましょう。

Optional 型は、null か null じゃないものかが入っているコンテナです。Java でメソッドを書いている場合、基本的にいつでも null を返せるわけですが、null にたいしてメソッドを呼び出すと NullPointerException が発生します。

毎回 null かどうかをチェックするのはめんどくさいし、まあ意味が無いケースも多いわけです。 そういうわけで、null を返したいケースでは Optional 型を利用して、null が返る可能性を明示して、それ以外のときには基本的に null を返さないようにする、ということが肝要となってまいります。

ライブラリから null が返ってくるケースはままあるわけですが、それをアプリケーションコード内のメソッドから返却してはいけません。

@NonNull を活用しよう

lombok を使ってる場合、@NonNull というアノテーションいれるだけで、引数に対する null check が簡単にできるんで、気が向いた時に入れておくと、どこから null が混入したかがわかりやすくなって便利だったりします。

リソースを明示的にクローズしましょう!

Perl では Reference Count GC が全面的に採用されており、リソースはその変数が参照されなくなった時点で即座にリリースされます。 ファイルも $fh がスコープから外れたらすぐにクローズされます。

しかし、Java の場合にはそうではない!!ちゃんと明示的に閉じて上げる必要があります。 しかし、明示的に .close メソッド呼ぶとかだるいので、try-with-resources を使いましょう。

try-with-resources を使いまくろう

Java 7 で導入された try-with-resources 構文はめちゃんこ便利なので必ず覚える必要がある。

以下のように書くと、try を抜けるタイミングで、自動的に br.close() が呼ばれます。

static String readFirstLineFromFile(String path) throws IOException {
  try (BufferedReader br = new BufferedReader(new FileReader(path))) {
    return br.readLine();
  }
}

昔の Java の本や、インターネッツにのってるコードだと以下のようなコードがよくありますが、今ではずっと簡潔に書くことができるのです。

static String readFirstLineFromFileWithFinallyBlock(String path) throws IOException {
  BufferedReader br = new BufferedReader(new FileReader(path));
  try {
    return br.readLine();
  } finally {
    if (br != null) br.close();
  }
}

try-with-resources を使っていて、ウェブアプリケーションを書いている限り、基本的に finally block を書くことはほとんどありません。finally を書きたいなーと思ったら、一度立ち止まってよく考えてみるか、誰かに相談してみるといいと思います。

(Note. try-with-resources は、Guard の代わりにも使えますね)

Object 型をできるだけ避けよう

どうせ Perl だったら返り値なんか Object 型相当なんだし、Object 型をたまには返してもいいよね?と思う向きもあると思いますが、実際にはアプリケーションコードで Object 型を返却しなければいけないケースは現在ではほぼありません。だいたいはジェネリクスにより、うまいことなんとかなります。

なんとかならないケースがあったら、たぶんだいたいはよく調べたらなんとかなるので、誰かに聞いてください。

FindBugs を使おう

FindBugs は Perl でいうと Perl::Critic に対応するもの、JS でいうと jshint に相当するものです。 ありがちなコーディングミスをひと通り教えてくれます。

人間によるコードレビューを受ける前にひと通り findbugs でチェックしておきましょう。

findbugs の利用は maven を使っている場合は

mvn clean compile findbugs:check

とするか、pom.xml に以下のように書いて、mvn site && open target/site/index.html するのがいいかと思います。

<reporting>
    <plugins>
        <plugin>
            <groupId>org.codehaus.mojo</groupId>
            <artifactId>findbugs-maven-plugin</artifactId>
            <version>3.0.0</version>
        </plugin>
    </plugins>
</reporting>

Effective Java を読もう

Effective Java って、なんか Java 6 対応!! とか書いてあるし、めっちゃ内容古そうに見えますが、実際まあ、よく出来ている書籍で、ハマりどころをひと通り教えてくれます。 (実際は訳注で Java7 に関するフォローも入っています)

Effective Java は Effective Perl というよりは Perl Best Practices に近い書籍なんで、ひと通り読んでおくといいと思います。

というか、読んでなくてダメなコードを書いていると後ろ指さされる感じあるので、読んだほうがいいです。

マルチスレッドで動いていることを意識してコーディングしよう

Perl の場合には基本的にアプリケーション・サーバーは pre-fork モデルで実行するのが普通です。 pre-fork の場合は、各プロセスの間ではデータは共有されません。

しかし!! Java の場合は multi-thread モデルで、各リクエストごとに thread が割り当てられます。 他のスレッドと変数を共有することが可能となっているのです。

これはつまり、スレッド間での競合が起きるとまじひどい目にあうということです。 ですから、基本的に、スレッド間でのデータ共有をできるだけ避けてコーディングするようにしたほうがいいです。

明示的にスレッドセーフであると宣言されているライブラリ以外はスレッドセーフではないと考えよう

たまに、「何回か動かして問題ないからスレッドセーフだろ。。」みたいな考え方をする人がいるのですが、そういうことではないです!

ごくたまに起きるスレッド競合とかあるとまじ最悪な感じになりますので、「このライブラリはスレッドセーフです!」と明示的にマークされているもの以外は、スレッド間で共有しないようにしましょう。

JSON を文字列で書かずに Jackson で生成しよう

なぜか知らないけど、Java で書くときになると JSON を手で書いて文字列でハードコードしたくなる人がいます。

これは、invalid な JSON をハイて、ひどい目にあうリスクがあるんで、基本的に Jackson などにお任せしましょう。

printf デバッグの代わりにロガーを使おう

System.err.println() とか System.out.println() でデバッグするのはやめましょう。 かわりに slf4j のロガーに出しましょう。

あと、そもそも printf デバッグを避けて debugger を使うようにしていきましょう。

jax-rs でクラスとメソッドに分けて Path 定義するのを避けよう

クラスに @Path("/blog") してメソッドに @Path("/{id}") つける、みたいなコーディングが jax-rs だと可能なんですが、こういうふうに書くのは grep-ability が低くなってよくないので、@Path("/blog/{id}") みたいに書くのが僕は好きです。

ここは好みの面もあると思いますけど、メソッド側にまとめて書いたほうがメンテナンス性が高いと、僕は思います。

Diamond inference を使おう

Java7 以後では Diamond inference で簡潔に書けるので、簡潔に書いたらいいです。

List<Foo> foo = new ArrayList<Foo>();

List<Foo> foo = new ArrayList<>();

Javadoc を書こう

クラス/メソッドにコメント書きましょう。Java の場合、メソッド補完するときに javadoc のコメントが見えるんで、書いといたほうが開発効率が後々よくなってきます。

Hibernate はインメモリキャッシュを勝手にやるので注意

Data::ObjectDriver 的なメモリキャッシュを持ってくれるので、気をつけよう!

デフォルトだと、セッションの間でだけ有効なインメモリキャッシュが有効になっているはず。 一部で、「よっしゃここは SQL で高速化やでー」といって hibernate バイパスして SQL 直接ぶっこんだりするとひどい目にあう気がしている。

警告をなくそう!

warnings が出ているのひと通り治しましょう。警告出たままにしておくと、重要な警告を見落とす結果になってしまいます。 引き継ぎした案件で warnings 出まくってると、めっちゃなえます。

Java の警告、そもそもなんでそんなに怒ってるのかわからないというケースもままあると思うんで、そういうときはスクショをとって他のひとに聞くとよいです。

Jackson で constructCollectionType じゃなくて TypeReference を使おう

Jackson は以下のように constructCollectionType とか使えますが、可読性が低いと感じるのが僕です。

JavaType type = mapper.getTypeFactory().
  constructCollectionType(List.class, Foo.class)

↓↓こっちのほうが好き。

List<Foo> list = mapper.readValue(jsonString, new TypeReference<List<Foo>>() { });

後者のほうが、読みやすいが、無名クラスを一個つくることになるというデメリットはあります。 ただまあ、そんなデメリットでもないんで、別によいのでは。

(これは好みの問題でもあるんで、どっちでもいいっちゃいいです)

自分で考えすぎないで人に頼ろう

社内の hipchat に Java っていう名前のチャットルームがあるので、入って聞いたらいいです。 だいたいすぐに誰か答えてくれると思います。

基本的に自分でがんばって考えても無駄なんで、どんどん人に聞くのがよいと思います。

【追記】 Reflection をさける

アプリケーションコードで Reflection を使いたくなったら、それはたぶん何かが間違ってる可能性があるというか、Java っぽくないコードを書こうとしているケースな可能性が極めて高いので、だれかに相談してください。

Created: 2014-10-01 09:00:07
Updated: 2014-10-01 09:00:07

Content-Security-Policy と nonce の話

Content-Security-Policy の nonce を利用すると、XSS の脅威をかなり軽減できます。

そこで、Web Application Framework ではデフォルトで対応したほうがよいのではないか、という旨を @hasegawayosuke さんから教えて頂いたので、実装について考えてみました。

とりあえず CSP の nonce はどういうものなのかを考慮するために、コード例を探していたのですが、実際に動くサンプルというものが nonce 関連のもので見当たりませんでした。

そこで、実際に動くサンプルを用意しました。

https://github.com/tokuhirom/csp-nonce-sample

以下は Sinatra で書かれたサンプルコードです。

require 'sinatra'
require 'securerandom'

get '/' do
    @nonce = SecureRandom.base64()
    headers 'Content-Security-Policy' => "unsafe-inline; script-src 'nonce-#{@nonce}'"
    erb :index
end

テンプレートファイルは以下のようになります。

<!doctype html>
<html>
    <body>
        <h1>CSP の nonce のサンプルです。</h1>

        <script type="text/javascript" nonce="<%= @nonce %>">
            alert("これは信用されてる");
        </script>
        <script type="text/javascript">
            alert("こんにちは!こんにちは!");
        </script>
        ↑これは、攻撃者が送り込んだメッセージだと思ってください。これは実際にはサポートされているブラウザでは実行されません。
    </body>
</html>

"Content-Security-Policy: unsafe-inline; script-src 'nonce-${nonce}'" 形式で書いたら、${nonce} の部分を script タグの属性にいれないと実行されなくなります。

nonce の値は、リクエストごとにランダムな文字列が生成されるので、クライアント側からは想像もつかず、攻撃することが困難になります。

これはもう、どんどん nonce 使って行った方がいいのでしょうかね!

Web application framework でのサポートについて

Web Application Framework でこの機能をがっつりサポートするのはどうなのでしょうか?

現実的には HTML をパースして nonce を埋め込むアプローチも考えられますが、それでは攻撃者が送ってきた script タグに nonce をつけてしまう可能性もあって効果が薄れます。

理想的には、やはり手作業で一つ一つ nonce 値を埋めていって上げるのがよいでしょう。

Web Application Framework では csp header の送出とテンプレートエンジンへの nonce 値の受け渡しだけを担当し、HTML の書き換えはユーザーに任せたほうがよいように思います。

(追記) unsafe-inline をつけよう

ということなので、unsafe-inline もつけたほうがよいようです。

(追記) nonce つけても XSS される場合。

<script nonce="...">document.write(location.hashref)</script>

のような場合、ダメとのこと。

Created: 2014-09-26 09:57:58
Updated: 2014-09-26 09:57:58

[java]インターフェースにArrayを露出させた場合の話

Java の世界ではプリミティブな配列が存在している。 プリミティブな配列は速度が List などと比べると圧倒的に速いのでついつい使いたくなる。

しかし、Java 言語では immutable な配列を作ることができないので、内部で配列を保持している場合、それをそのまま返却することはできない。

つまり、以下のようなクラスはよくない。Foo(o).getO() で取得された配列を操作すると、Foo を作成した時点で作成された o を変更してしまうからだ。

public class Foo {
    private final Object[] o;
    public Foo(Object[] o) {
        this.o = o;
    }
    public Object[] getO() {
        return this.o;
    }
}

よって、汎用的なライブラリでは以下のようにしたほうがベター。

public class Foo {
    private final Object[] o;
    public Foo(Object[] o) {
        this.o = o;
    }
    public Object[] getO() {
        return this.o.clone();
    }
}

しかしこれでは、配列のコピーが発生してしまって、データが大きい場合に問題になる。 そこで、配列をあきらめて List を使う。

public class Foo {
    private final List<Object> o;
    public Foo(final List<Object> o) {
        this.o = Collections.unmodifieableList(o);
    }
    public List<Object> getO() {
        return this.o;
    }
}

これで、安全になった。 Collections.unmodifieableList を通していることにより、内部データを操作される心配はもはやない(Reflection とか使われたらアレだけど、それは自己責任)。

まとめ

Java ではオブジェクトの外部とのやりとりに配列を使うのはできるだけ避けたほうがよいケースがある。 (内部ではパフォーマンスを出すために使ったほうがいいケースも多々ある)

Created: 2014-09-22 10:34:56
Updated: 2014-09-22 10:34:56

Java なウェブアプリのテストをするための mech というライブラリを書いていた

https://github.com/tokuhirom/mech

@Test
public void testGoogle() throws Exception {
    try (Mech mech = new Mech("http://google.com/")) {
        try (MechResponse res = mech.get("/").execute()) {
            assertEquals(200, res.getStatusCode());
        }
    }
}

こんな感じで使える。この使い方は本筋じゃなくて本当にやりたいのはこっち。

class MyServlet extends HttpServlet {
    protected void service(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException, IOException {
        resp.getWriter().write("Hello");
    }

}

public class ServletTest {
    @Test
    public void test() throws Exception {
        try (MechJettyServlet mech = new MechJettyServlet(new MyServlet())) {
            try (MechResponse res = mech.get("/").execute()) {
                assertEquals(200, res.getStatusCode());
                assertEquals("Hello", res.getContentString());
            }
        }
    }
}

適当につくったサーブレットを、ささっとテストできる。裏のスレッドで Jetty たてて、それベースでテストしてくれる。 便利~。

なかなか便利に使えるようになったんで、オープン&シェアさせていただきます。

JSON をポストしたい

try (MechResponse res = mech.postJSON("/json", form).execute()) {
    assertEquals(200, res.getStatusCode());
    assertEquals("+++{\n"
            + "  \"name\" : \"hoge\"\n"
            + "}+++", res.getContentString());
}

JSON を受け取ったのを読み込みたい

Form form = res.readJSON(new TypeReference<Form>() {
});

Jackson でいい感じに処理できます。

POST したい

try (MechResponse res = mech.post("/postForm").param("name", "pp太郎")
        .execute()) {
    assertEquals(200, res.getStatusCode());
    assertEquals("pp太郎", res.getContentString());
}

multipart/form-data でテストしたい

try (MechResponse res = mech.postMultipart("/postMultipart")
        .param("name", "pp太郎").file("file", new File("pom.xml"))
        .execute()) {
    assertEquals(200, res.getStatusCode());
    assertEquals("pp太郎XXXpom.xml", res.getContentString());
}

リクエストとレスポンスの具合を表示したい

mech.addRequestListener(new PrintRequestListener(ps));

うまいこと、全部経過を表示できる。これでテストした結果を、ドキュメントに貼ったりしてる。

Installation

<repositories>
    <repository>
        <id>tokuhirom</id>
        <url>https://tokuhirom.github.io/maven/releases/</url>
    </repository>
</repositories>
<dependencies>
    <dependency>
        <groupId>me.geso</groupId>
        <artifactId>mech</artifactId>
        <version>0.7.1</version>
    </dependency>
</dependencies>

pom.xml にこういう感じで書いてくだされ。

javadoc

http://tokuhirom.github.io/maven/javadoc/me/geso/mech/0.7.1/apidocs/index.html

このへんにおいてあります。

Created: 2014-09-21 18:59:13
Updated: 2014-09-21 18:59:13