2016-04-07 51 views
13

私たちは、Jbossサーバー6.1内で動作する3つのWebアプリケーション(標準のSpring MVC-Hibernate)を持っています。 3つのアプリケーションはすべて共通の認証方法を共有します。これはJARとしてコンパイルされ、各WARファイルに含まれています。当社の認証方式は、ユーザのパスワードをハッシュするorg.springframework.security.crypto.bcrypt.BCryptを使用して、下記を参照してください。BCryptパフォーマンス低下

hashedPassword.equals(BCrypt.hashpw(plainTextPassword, salt)); 

JBOSS起動オプション

set "JAVA_OPTS=-Xms2048m -Xmx4096m -XX:PermSize=256m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -verbosegc -XX:+PrintGCTimeStamps -XX:+PrintGCDetails -Xloggc:gc.txt -XX:+UseParallelOldGC

問題: それが表示されます。サーバーが再起動されると、Bcrypt.hashpwはパスワードを解読するのに100msかかります。しかし、しばらくして(パターンがない)突然Bcrypt.hashpwのパフォーマンスが100msから10秒に急上昇します。これには明らかな理由はありません。

詳細情報:

  • 休止バージョン:4.2.4.Final
  • 春バージョン:4.0.5.RELEASE春
  • Securityバージョン:3.2.4.RELEASE

誰もこの問題を以前に見たことがありますか?

+1

プロファイラを取り付けて、どの部分が長くかかるかを把握します。 –

+0

Hello @ m-deinum、私たちはすでにこれを行っており、問題はライブラリ自体であることがわかりました。これは、ライブラリがしばらくの間うまく動作してから、10秒以上になる(とそのようにとどまる)理由を説明していません。 –

+0

どのライブラリとライブラリのどの部分... *ライブラリ*であるかということは明確ではないので、ライブラリのどの部分がより具体的であるかを知りたいかもしれません。メソッドなど –

答えて

2

SeedGeneratorSecureRandomの場合、遅延が発生する可能性があります。

スプリングスbcryptの順番に順番ブロック/dev/randomを使用することができSeedGeneratorを使用して実装usesSecureRandomHereは、これらのクラスの優れた説明です。

また、bugreportは、BCryptのパフォーマンスの問題を報告し、それらをシードジェネレータに戻して、完全なスタックトレースを表示します。 BCryptの実装は異なりますが、SecureRandom以下のスタックトレースはバネ実装と同一でなければなりません。彼らの解決策は、BCryptの再シード頻度を減らすことでした。

+0

あなたのお返事ありがとうございます。しかし、私たちのシナリオは異なります。つまり、Bcrypt.gensalt()を使用していません。 ユーザーを認証する際に塩を生成しません。その代わりに、私たちは既にsaltにdbを格納し、hashpwメソッドを使用する前にそれを取得します。 –

7

問題:サーバーを再起動すると、Bcrypt.hashpwはパスワードを解読するのに を100msかかります。しかし、しばらくして(パターンがありません) 突然Bcrypt.hashpwのパフォーマンスが100msから10秒に急上昇します。 これには明らかな理由はありません。

問題は/dev/random時々ブロックであり、それがない場合には、ランダムに表示されます:)より多くの混乱を招くことは、それがしようとしながら、あなたがオブザーバー効果すなわちぶつかるだろうどのように動作するかをテストしようとしたときに、ということですあなたがエントロピーを生成しているランダムな振る舞いを観察すると、これは混乱のトンにつながります。つまり、私の結果はあなたのものと同じではありません。これはパターンがないように見える理由です。

私はデモンストレーションします問題を分析し、自分のサーバー上で(理由のもとで)再作成する方法を示して、ソリューションをテストできるようにします。私は試して、いくつかの修正を提供します。これはLinux上にあることに注意してください。しかし、エントロピーが乱数を生成して使い果たされるシステムでも同じ問題が起こります。

Linuxの場合/dev/randomはランダムなバイトのストリームです。 ストリームから読み込むと、利用可能なエントロピーが枯渇します。ある点に達すると は/dev/randomブロックから読み込みます。あなたは、次のbashスクリプトを実行してもentropy_availを監視する場合は、bashスクリプトは、それを消費するエントロピーが大幅に落ち込むこと 通知がよ

cat /proc/sys/kernel/random/entropy_avail 

このコマンドを使用して、使用可能なエントロピーを見ることができます。

while : 
do 
    cat /dev/random > /dev/null 
done 

また、これはあなたに利用できるエントロピーを減らすために上記のbashスクリプトを実行し、問題が現れますつまり、あなたのサーバー上でこの問題を再作成する方法についてのヒントを与える必要があります。

お使いのシステムは、あなたが あなたはそれが効果を持って実行しているpvを残す場合、すなわち

pv /dev/random 

、それはランダムなストリームを消費するのITを測定するためにpvを使用することができます作成​​された毎秒どれだけ多くのバイト数を表示する場合他のサービスがブロックし始める可能性があることを意味します。 pvも出力されているので、システム上で利用可能なエントロイが増加している可能性があります:)。

エントロピーがほとんどまたは全くないシステムでは、pv /dev/randomを使用すると氷河が遅く見えます。私は、VMが時々エントロピーを生成することに大きな問題を抱えていることも経験しました。

次クラスを使用して作成し、問題を再現する...

import java.security.SecureRandom; 
import org.mindrot.jbcrypt.BCrypt; 
public class RandTest { 
    public static void main(String[] args) { 
     SecureRandom sr = new SecureRandom(); 
     int out = 0; 
     String password = "very-strong-password-1729"; 
     String hashed; 
     for (int i = 0; i < 200000 ; i++) { 
      hashed = BCrypt.hashpw(password, BCrypt.gensalt()); 
      //If we print, we're generating entroy :) System.out.println(hashed); 
     } 
    } 
} 

私はローカルディレクトリにbcryptのをダウンロードしました。 RandTestをrunnngながら、あなたが以前からbashスクリプトを実行し、システムがより多くのエントロピーを待ってブロックしている大規模なポーズが表示されます場合は

javac -cp ./jBCrypt-0.4/src/ RandTest.java 
java -cp ./jBCrypt-0.4/src/:. RandTest 

を次のように私はそれをコンパイルして実行しました。あなたがstraceを実行する場合は、以下を参照してくださいよ...

1067 [pid 22481] open("/dev/random", O_RDONLY|O_LARGEFILE) = 12 
11068 [pid 22481] fstat64(12, {st_mode=S_IFCHR|0666, st_rdev=makedev(1, 8), ...}) = 0 
11069 [pid 22481] fcntl64(12, F_GETFD)  = 0 
11070 [pid 22481] fcntl64(12, F_SETFD, FD_CLOEXEC) = 0 
..... 
11510 [pid 22481] read(12, "\320\244\317RB\370", 8) = 6 

プログラムは/dev/randomから読んでいます。エントロピーテストの問題は です。それをテストしようとしている間に、オブザーバーエフェクトなどを生成している可能性があります。

修正

最初の修正は/dev/urandomすなわち

time java -Djava.security.egd=file:///dev/./urandom -cp ./jBCrypt-0.4/src/:. RandTest 

別の修正が/dev/urandomデバイスとして/dev/randomデバイスを再作成するに/dev/randomを使用してから変更することです。これを行うには、manページを作成する代わりに、manページを作成する方法があります。

mknod -m 644 /dev/random c 1 8 
mknod -m 644 /dev/urandom c 1 9 
chown root:root /dev/random /dev/urandom 

我々はそれがすなわち

rm /dev/random 
mknod -m 644 /dev/random c 1 9 
chown root:root /dev/random 

/dev/random覚えておくべき重要なことは、あなたがテストしている システムからentroyを必要とし、ランダムなデータをテストして、実際に今/dev/urandom

で1と偽物を削除Observer Effectのためにonは難しいです。

+2

あなたのお返事ありがとうございます。しかし、私たちのシナリオは異なります。つまり、Bcrypt.gensalt()を使用していません。 ユーザーを認証する際に塩を生成しません。その代わりに、私たちは既にsaltにdbを格納し、hashpwメソッドを使用する前にそれを取得します。 –

関連する問題