2017-03-29 9 views
0

私は、特定のメッセージに関するすべての情報を含むチャットプログラム用のクラスメッセージを作成しました。メッセージのインスタンスは、サーバーとクライアントの間で前後に送信されます。私はこれらのメッセージを交換するためにシリアル化(ObjectInputStream/ObjectOutputStream)を使用しています。シリアライゼーションの使用は深刻な問題ですか?

私は、シリアライズとデシリアライズのプロセスを制御できません。私にとって最大の問題は、何人かの攻撃者が本当に重いメッセージ(数ギガバイトなど)を送信したい場合、それを避ける方法がなく、深刻な記憶上の問題が生じる可能性があるということです。これはサービス拒否のために使用され、深刻なものです。

シリアライゼーションとそのセキュリティに関するさまざまな話題を取り上げましたが、この些細な問題を回避する方法については誰も言及していません。バッファを使用してデータをバイト配列として取得して、いつでも読み取りを停止できるようにしたいと考えています。しかし、私はシリアル化でこれを行う方法を見つけることができませんでした。 質問:どうすればいいですか?

シリアル化のセキュリティ上の問題についてのコメントも歓迎します。シリアライズ可能なクラスのインスタンスに悪意のあるコードを挿入できると聞いたことがありますが、クラスの定義がクライアントとサーバーで同じでなければならないため、これはどのように可能ですか?

ありがとうございました!

+0

あなたがセキュリティについてどの程度深刻に依存します。 – Kayaman

+0

JSONを使用するだけですか?ハードDDOSを防ぐ方法はありませんが、Javaのシリアル化を使用することにはいくつかの欠点があります。 – chrylis

+1

あなたの質問は本当にシリアライゼーションではないようです。大量のメッセージを送信する人が気になる場合は、最大メッセージサイズを文書化して、クライアントAPIとメッセージを送信するサーバーに適用する必要があります。 –

答えて

0

FilterInputStream(http://docs.oracle.com/javase/6/docs/api/java/io/FilterInputStream.html)を書き込んで、その基本ストリームからXバイト以上のデータを読み取ると例外がスローされるのはなぜですか?

このページのreadObjectへの呼び出しを置き換えるために使用できる方法があります:

https://www.contrastsecurity.com/security-influencers/java-serialization-vulnerability-threatens-millions-of-applications

/** 
* A method to replace the unsafe ObjectInputStream.readObject() method built into Java. This method 
* checks to be sure the classes referenced are safe, the number of objects is limited to something sane, 
* and the number of bytes is limited to a reasonable number. The returned Object is also cast to the 
* specified type. 
* 
* @param type Class representing the object type expected to be returned 
* @param safeClasses List of Classes allowed in serialized object being read 
* @param maxObjects long representing the maximum number of objects allowed inside the serialized object being read 
* @param maxBytes long representing the maximum number of bytes allowed to be read from the InputStream 
* @param in InputStream containing an untrusted serialized object 
* @return Object read from the stream (cast to the Class of the type parameter) 
* @throws IOException 
* @throws ClassNotFoundException 
*/ 

@SuppressWarnings("unchecked") 
public static T safeReadObject(Class<?> type, List<Class<?>> safeClasses, long maxObjects, long maxBytes, InputStream in) throws IOException, ClassNotFoundException { 
    // create an input stream limited to a certain number of bytes 
    InputStream lis = new FilterInputStream(in) { 
     private long len = 0; 
     public int read() throws IOException { 
      int val = super.read(); 
      if (val != -1) { 
       len++; 
       checkLength(); 
      } 
      return val; 
     } 
     public int read(byte[] b, int off, int len) throws IOException { 
      int val = super.read(b, off, len); 
      if (val > 0) { 
       len += val; 
       checkLength(); 
      } 
      return val; 
     } 
     private void checkLength() throws IOException { 
      if (len > maxBytes) { 
       throw new SecurityException("Security violation: attempt to deserialize too many bytes from stream. Limit is " + maxBytes); 
      } 
     } 
    }; 
    // create an object input stream that checks classes and limits the number of objects to read 
    ObjectInputStream ois = new ObjectInputStream(lis) { 
     private int objCount = 0; 
     boolean b = enableResolveObject(true); 
     protected Object resolveObject(Object obj) throws IOException { 
      if (objCount++ > maxObjects) throw new SecurityException("Security violation: attempt to deserialize too many objects from stream. Limit is " + maxObjects); 
      Object object = super.resolveObject(obj); 
      return object; 
     } 
     protected Class<?> resolveClass(ObjectStreamClass osc) throws IOException, ClassNotFoundException { 
      Class<?> clazz = super.resolveClass(osc); 
      if (
       clazz.isArray() || 
       clazz.equals(type) || 
       clazz.equals(String.class) || 
       Number.class.isAssignableFrom(clazz) || 
       safeClasses.contains(clazz) 
      ) return clazz; 
      throw new SecurityException("Security violation: attempt to deserialize unauthorized " + clazz); 
     } 
    }; 
    // use the protected ObjectInputStream to read object safely and cast to T 
    return (T)ois.readObject(); 
} 
+0

しかし、ObjectInputStreamを使用しているので、readObjectメソッドを使用する必要があるため、バイト数を数えることはできません。 –

+0

このアプローチの問題は、メッセージを繰り返し受信する必要があることです。その関数を毎回呼び出すと、新しいOISが繰り返し生成され、ストリームヘッダーエラーが発生します。この問題を解決するためにFilterInputStreamとObjectInputStreamをサブクラス化しようとしましたが、バイトは数えられません。私は任意の大きなメッセージを送ることができます。単に機能しません。 –

関連する問題