Các phương pháp vùng kín có thực sự an toàn?


92

Trong Java, công cụ privatesửa đổi truy cập được coi là an toàn vì nó không hiển thị bên ngoài lớp. Thế giới bên ngoài cũng không biết về phương pháp đó.

Nhưng tôi nghĩ rằng phản xạ Java có thể sử dụng để phá vỡ quy tắc này. Hãy xem xét trường hợp sau:

public class ProtectedPrivacy{

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

}  

Bây giờ từ một lớp khác, tôi sẽ nhận được Thông tin:

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());
   }
} 

Lúc này tôi chỉ nghĩ phương thức private vẫn an toàn vì để làm một số việc như trên chúng ta phải biết tên phương thức. Nhưng nếu lớp có chứa phương thức private được viết bởi một số người khác, chúng ta không có khả năng hiển thị chúng.

Nhưng quan điểm của tôi trở nên không hợp lệ kể từ dòng mã bên dưới.

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

Bây giờ nó method[]chứa tất cả những thứ cần làm ở trên. Câu hỏi của tôi là, có cách nào để tránh những việc này khi sử dụng phản chiếu Java không?

Tôi trích dẫn một số điểm từ Tài liệu Java để làm rõ câu hỏi của tôi.

Mẹo chọn Cấp độ Truy cập:

Nếu các lập trình viên khác sử dụng lớp của bạn, bạn muốn đảm bảo rằng các lỗi do sử dụng sai không thể xảy ra. Các cấp độ truy cập có thể giúp bạn làm điều này. Sử dụng cấp độ truy cập hạn chế nhất phù hợp với một thành viên cụ thể. Sử dụng chế độ riêng tư trừ khi bạn có lý do chính đáng.


1
Sử dụng obfuscator có thể hữu ích, vì getDeclaredMethodsnó sẽ trả về các tên trông giống như rác.
dasblinkenlight

213
Riêng tư, công cộng được bảo vệ, v.v. không phải để bảo mật, nó là để tránh mọi người mắc lỗi. Không sử dụng nó như là một biện pháp an ninh
Richard Tingle

20
Mã Java dù sao cũng có thể dịch ngược được. 'Kẻ tấn công' chỉ có thể tải xuống trình dịch ngược Java và đọc mã của bạn hoặc thay đổi 'riêng tư' thành 'công khai'.
11684

7
Để giải thích những gì @RichardTingle đã nhận xét (+1 btw). Có một sự khác biệt lớn và quan trọng giữa bảo mật và an toàn. Trường hợp sau là vấn đề được giảm thiểu với các công cụ sửa đổi truy cập; để không làm hỏng
người dùng

3
Tất cả điều này khá rõ ràng đối với các lập trình viên khi các công cụ sửa đổi quyền truy cập không tồn tại, như trong Python. Trong các ngôn ngữ này, private / public được phân biệt đơn giản bằng một quy ước trong tên (trong python bất kỳ thứ gì bắt đầu bằng một dấu gạch dưới đều được coi là private). Điều này làm cho nó khá rõ ràng rằng việc đánh dấu một cái gì đó là "riêng tư" không thêm bất kỳ bảo mật nào, mà đó chỉ là một cách đơn giản để nói những gì mọi người nên sử dụng API của bạn. Tôi nghi ngờ rằng việc kiểm tra trình biên dịch cho những thứ này sẽ giúp ích gì cả vì thật dễ dàng để tuân theo quy ước mà không cần sự trợ giúp "bên ngoài".
Bakuriu

Câu trả lời:


95

Nó phụ thuộc vào những gì bạn có nghĩa là "an toàn". Nếu bạn đang chạy với một trình quản lý bảo mật cho phép điều này, thì vâng, bạn có thể làm tất cả những điều khó chịu với sự phản chiếu. Nhưng sau đó trong loại môi trường đó, thư viện có thể chỉ được sửa đổi để công khai phương thức.

Kiểm soát truy cập là "tư vấn" hiệu quả trong một môi trường như vậy - bạn đang tin tưởng vào mã để chơi một cách độc đáo. Nếu bạn không tin tưởng mã bạn đang chạy, bạn nên sử dụng trình quản lý bảo mật hạn chế hơn.


3
Tiếp tuyến, tôi biết, nhưng bạn có thể giải thích một chút về một người quản lý hạn chế hơn theo nghĩa này không?
Xám

12
@Gray: Về cơ bản, một phiên bản của SecurityManager đưa ra các ngoại lệ cho các check*lệnh gọi liên quan .
Jon Skeet

40

Công cụ sửa đổi quyền truy cập không liên quan gì đến bảo mật. Trên thực tế, bạn có thể và nên xem các công cụ sửa đổi quyền truy cập là mặt trái của bảo mật - nó không phải để bảo vệ dữ liệu hoặc mật khẩu của bạn, mà là để bảo vệ mọi người khỏi yêu cầu phải biết về dữ liệu và mật mã của bạn. Đây là lý do tại sao công cụ sửa đổi mặc định là gói - nếu họ đang làm việc trên gói thì có lẽ họ đã cần biết.

Cùng với kiến ​​thức về dữ liệu và các phương pháp mã của bạn, đi kèm với khả năng tương ứng để biết khi nào và cách sử dụng nó. Bạn không đặt chế độ riêng tư trên phương thức inIt của mình để ngăn ai đó tìm hiểu về nó, bạn làm như vậy vì (a) họ sẽ không biết rằng bạn chỉ gọi nó sau foo và chỉ khi bar = 3,1415 và (b) bởi vì họ không hay biết về nó.

Modifers truy cập có thể được tóm gọn trong một câu đơn giản "TMI, dude, tôi nên không cần phải biết điều đó".


3
Câu trả lời tuyệt vời, nhưng tôi cần phải google để tìm ra rằng TMI có nghĩa là Quá nhiều thông tin. Tôi đoán tôi cần dành nhiều thời gian hơn ở thung lũng :-)
mikelong

7

Bằng cách nói 'an toàn', bạn đang bảo vệ bạn hoặc các nhà phát triển khác đang sử dụng API của bạn để không làm hại đối tượng bằng cách gọi phương thức riêng tư của bạn. Nhưng nếu bạn hoặc họ thực sự cần gọi phương thức này, họ có thể thực hiện với Reflection.


6

Câu hỏi là bạn đang cố gắng cứu nó khỏi ai. Theo ý kiến ​​của tôi, một khách hàng như vậy của mã của bạn là người bị thiệt hại ở đây.

Bất kỳ đoạn mã nào (do bạn hoặc người khác viết) cố gắng truy cập vào một privatethành viên của lớp trên về cơ bản là đào mồ chôn chính nó. privatecác thành viên không tạo một phần của API công khai và có thể thay đổi mà không cần thông báo. Nếu một khách hàng tình cờ sử dụng một trong những thành viên private như vậy theo cách đã nêu ở trên, nó sẽ bị hỏng nếu nó nâng cấp lên phiên bản API mới hơn mà thành viên private đã được sửa đổi.


5

Có cơ sở, có trách nhiệm. Có những điều bạn không thể làm và những điều bạn có thể làm nhưng không nên làm.

Công cụ sửa đổi riêng được cung cấp / sử dụng như / theo cách hạn chế nhất. Các thành viên không được nhìn thấy bên ngoài lớp sẽ được định nghĩa là riêng tư. Nhưng điều này có thể bị phá vỡ với Reflection như chúng ta thấy. Nhưng điều này không có nghĩa là bạn không nên sử dụng private - hoặc chúng không an toàn. Đó là về việc bạn sẽ sử dụng mọi thứ một cách thận trọng hoặc theo cách xây dựng (như phản ánh).


5

Giả sử bạn tin tưởng người lập trình máy khách của API của mình, thì một cách khác để xem xét mức độ 'an toàn' đối với họ khi sử dụng các chức năng cụ thể đó.

Các chức năng có sẵn công khai của bạn phải cung cấp một giao diện rõ ràng, được ghi chép đầy đủ, hiếm khi thay đổi vào mã của bạn. Các chức năng riêng tư của bạn có thể được coi là một chi tiết triển khai và có thể thay đổi theo thời gian, vì vậy không an toàn khi sử dụng trực tiếp.

Nếu một lập trình viên khách hàng cố gắng phá vỡ những điều trừu tượng này, họ đang tuyên bố rằng họ biết những gì họ đang làm. Quan trọng hơn, họ hiểu rằng nó không được hỗ trợ và có thể ngừng hoạt động với các phiên bản mã của bạn trong tương lai.


5

privatekhông phải để bảo mật, nó là để giữ cho mã sạch và để ngăn chặn sai lầm. Nó cho phép người dùng mô-đun hóa mã (và cách nó được phát triển) mà không phải lo lắng về tất cả các chi tiết của các mô-đun khác

Sau khi bạn phát hành mã của mình, mọi người có thể tìm ra cách nó hoạt động. Không có cách nào để "ẩn" logic nếu cuối cùng bạn muốn mã chạy trên máy tính. Ngay cả việc biên dịch sang hệ nhị phân cũng là một mức độ khó hiểu.

Vì vậy, không có cách nào để bạn có thể thiết lập API của mình để thực hiện những điều đặc biệt mà bạn không muốn người khác gọi. Trong trường hợp của API web, bạn có thể đặt các phương thức bạn muốn kiểm soát ở phía máy chủ.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.