web-dev-qa-db-ja.com

プライベートメソッドは本当に安全ですか?

Javaでは、privateアクセス修飾子はクラスの外からは見えないため、安全であると見なされます。その場合、外の世界もそのメソッドについて知りません。

しかし、私はJavaリフレクションがこのルールを破るために使用できると考えました。以下のケースを検討してください:

public class ProtectedPrivacy{

  private String getInfo(){
     return "confidential"; 
  }

}  

次に、別のクラスから情報を取得します。

public class BreakPrivacy{

   public static void main(String[] args) throws Exception {
       ProtectedPrivacy protectedPrivacy = new ProtectedPrivacy();
       Method method = protectedPrivacy.getClass().getDeclaredMethod("getInfo", null);
       method.setAccessible(true);
       Object result = method.invoke(protectedPrivacy);
       System.out.println(result.toString());
   }
} 

上記のようなことをするためにはメソッド名を知らなければならないので、現時点では私はまだプライベートメソッドを安全であると考えました。しかし、他の誰かが書いたプライベートメソッドを含むクラスの場合、それらの可視性はありません。

しかし、コード行の下なので、私のポイントは無効になります。

Method method[] = new ProtectedPrivacy().getClass().getDeclaredMethods();

今これmethod[]には、上記の処理に必要なすべてのものが含まれています。私の質問は、Javaリフレクションを使用してこのようなことを回避する方法はありますか?

Java Documentation からいくつかのポイントを引用して、私の質問を明確にします。

アクセスレベルの選択に関するヒント:

他のプログラマがクラスを使用する場合、誤用によるエラーが発生しないようにする必要があります。アクセスレベルは、これを行うのに役立ちます。特定のメンバーにとって意味のある最も制限されたアクセスレベルを使用します。正当な理由がない限り、プライベートを使用してください。

それはあなたが「安全」とはどういう意味かによる。この種のことを許可するセキュリティマネージャーを使用している場合は、そうです。反射であらゆる種類の厄介なことを行うことができます。しかし、そのような環境では、ライブラリを変更してメソッドをパブリックにすることができます。

そのような環境では、アクセス制御は事実上「助言」であり、コードが適切に機能することを事実上信頼しています。 しないでください実行しているコードを信頼する場合は、より制限の厳しいセキュリティマネージャを使用する必要があります。

95
Jon Skeet

アクセス修飾子はセキュリティとは何の関係もありません。実際には、アクセス修飾子をセキュリティの逆と見なすことができます。これは、データやアルゴリズムを保護するためではなく、データやアルゴリズムについて知る必要から人々を保護するためです。これがデフォルトの修飾子がパッケージである理由です-彼らがパッケージで作業している場合、おそらくすでに知っておく必要があります。

データとコードのメソッドの知識に加えて、いつどのように使用するかを知る責任が伴います。 inItメソッドにプライベートを設定しないでください。誰かがそれを見つけられないようにするためです。それは、(a)fooの後でのみ呼び出されることを知らないため、bar = 3.1415および(b)の場合に限られるためです。それは彼らがそれについて知るのは良くないからです。

アクセス修飾子は、「TMI、おい、I soはそれを知る必要はなかった」という簡単なフレーズで要約できます。

40
jmoreno

「安全」とは、あなた自身または他の開発者を保護していることを意味します。開発者はAPIを使用して、プライベートメソッドを呼び出すことでオブジェクトに害を与えません。しかし、あなたまたは彼らが本当にこのメソッドを呼び出す必要がある場合、彼らはReflectionでそれを行うことができます。

7
Arsen Alexanyan

問題はあなたが誰にしようとしているのかsaveそれからだ。私の意見では、あなたのコードのそのようなクライアントはここで途方に暮れているものです。

上記のクラスのprivateメンバーにアクセスしようとするコード(あなたや他の人が書いたもの)は、本質的に独自の墓を掘っています。 privateメンバーはpublic APIの一部ではなく、予告なく変更される場合があります。クライアントが上記の方法でそのようなプライベートメンバーの1つをたまたま使用した場合、プライベートメンバーが変更されたAPIの新しいバージョンにアップグレードすると、クライアントは壊れます。

6
Regnidorhcs

privateはセキュリティのためではなく、コードをクリーンに保ち、ミスを防ぐためのものです。これにより、ユーザーはコード(およびその開発方法)をモジュール化することができますall他のモジュールの詳細について心配する必要はありません

コードをリリースすると、人々はそれがどのように機能するかを理解できます。最終的にコードをコンピューターで実行したい場合は、ロジックを「隠す」方法はありません。バイナリにコンパイルすることも、難読化のレベルです。

したがって、他の人に呼び出されたくない特別なことを実行するようにAPIを設定する方法はありません。 Web APIの場合、制御したいメソッドをサーバー側に置くことができます。

5
Manishearth

施設には責任があります。あなたができないすることと、あなたができるすることと、あなたがすべきではないすることとがあります。

プライベート修飾子は、最も制限された方法で提供/使用されます。クラスの外部に表示されるべきではないメンバーは、プライベートとして定義されます。しかし、これは、私たちが見るようにリフレクションで破られる可能性があります。しかし、これはプライベートを使用すべきではないという意味ではありません-またはそれらは安全ではありません。それはあなたが物事を賢明にまたは建設的な方法で(反射のように)使用することについてです。

5
Raúl

APIのクライアントプログラマーを信頼していると仮定すると、別の見方は、特定の関数を使用することの安全性です。

公開されている関数は、明確で十分に文書化され、ほとんど変更されないインターフェイスをコードに提供する必要があります。プライベート関数は実装の詳細と見なすことができ、時間とともに変化する可能性があるため、直接使用するのは安全ではありません。

クライアントプログラマーがこれらの抽象化を回避しようとする場合、彼らは、自分が何をしているのかを知っていると宣言していることになります。さらに重要なのは、サポートされていないため、将来のバージョンのコードでは機能しなくなる可能性があることを理解してもらうことです。

5
robbie_c