Các hạn chế bảo mật có khiến dịch vụ trả về null hoặc ném ngoại lệ không? [đóng cửa]


11

Tôi có một chút bất đồng với một nhà phát triển có kinh nghiệm hơn về vấn đề này và tự hỏi người khác nghĩ gì về nó; môi trường của chúng tôi là Java, EJB 3, dịch vụ, v.v.

Mã tôi đã viết gọi một dịch vụ để có được mọi thứ và để tạo ra mọi thứ. Vấn đề tôi gặp phải là tôi có ngoại lệ con trỏ null không có ý nghĩa. Ví dụ, khi tôi yêu cầu dịch vụ tạo một đối tượng, tôi sẽ nhận lại null; Khi tôi cố gắng tìm kiếm một đối tượng có ID hợp lệ đã biết, tôi sẽ nhận được null. Tôi đã dành một chút thời gian để cố gắng tìm ra những gì sai trong mã của tôi; Vì tôi ít kinh nghiệm hơn nên tôi thường cho rằng mình đã làm sai điều gì đó, nhưng hóa ra lý do trả về null là bảo mật. Nếu hiệu trưởng người dùng sử dụng dịch vụ của tôi không có quyền phù hợp cho dịch vụ đích, thì đơn giản là nó sẽ trả về null. Hầu hết các dịch vụ khác ở đây cũng không được ghi chép lại rất tốt, vì vậy rõ ràng đây chỉ là điều bạn phải biết.

Điều này khá khó hiểu khi một nhà phát triển viết mã tương tác với dịch vụ. Nó sẽ có ý nghĩa hơn đối với tôi nếu dịch vụ là một ngoại lệ sẽ cho tôi biết rằng người dùng không có quyền thích hợp để tải thứ này hoặc tạo ra thứ đó; Sau đó tôi sẽ biết ngay tại sao dịch vụ của tôi không hoạt động như mong đợi.

Nhà phát triển có kinh nghiệm hơn đã viết dịch vụ này lập luận rằng việc yêu cầu dữ liệu không phải là một điều kiện lỗi và các ngoại lệ chỉ nên được đưa ra trong một điều kiện lỗi, không phải khi người dùng không có quyền truy cập vào dữ liệu. Dữ liệu này thường được tra cứu trong GUI và đối với những người dùng không có quyền phù hợp, những điều này chỉ đơn giản là "không tồn tại". Vì vậy, trong ngắn hạn: hỏi không sai, do đó không có ngoại lệ. Nhận các phương thức trả về null vì với những người dùng đó những thứ "không tồn tại". Tạo phương thức trả về null khi người dùng không được phép tạo thứ đó.

Đây có phải là bình thường và / hoặc thực hành tốt? Tôi thích sử dụng các ngoại lệ vì tôi thấy dễ dàng hơn nhiều để biết những gì đang xảy ra. Vì vậy, ví dụ tôi cũng thích ném NotFoundException nếu bạn yêu cầu một đối tượng có ID không hợp lệ, thay vì trả về null.



@ChrisF: 1) là về những người tham khảo null, mà tôi không biết. Trong nhiều trường hợp chúng là phù hợp, tôi chỉ không nghĩ rằng chúng nằm trong cái này. 2) là về việc kiểm tra các tham số, và sẽ không phải là một loại kết quả khẳng định giống như ném một ngoại lệ? 3) ngoại lệ so với mã lỗi cũng là một vấn đề khác vì cả hai đều là cách "hiển thị" những gì đã sai. Mã lỗi là phù hợp nếu ví dụ bạn cần thông báo cho một hệ thống không hỗ trợ ngoại lệ hoặc nếu bạn không muốn người dùng cuối nhìn thấy bất cứ điều gì khác ngoài mã.
Svish

Vấn đề tôi hỏi ở đây là về việc "giả vờ một cái gì đó không tồn tại hoặc không xảy ra" vs "nói tại sao một cái gì đó không tồn tại hoặc không xảy ra".
Svish

3
Tôi không đề nghị họ là bản sao - chỉ là họ có thể có thông tin hữu ích cho bạn.
ChrisF

Đúng, xin lỗi về điều đó! Lấy nó như một bình luận "có thể trùng lặp" vì một số lý do ... có lẽ vì thiếu ngủ, hehe.
Svish

Câu trả lời:


20

Các ngoại lệ chỉ nên được ném khi có lỗi và yêu cầu một điều không phải là lỗi.

Yêu cầu một điều có thể không phải là một lỗi, nhưng không có quyền đối với một cái gì đó bạn yêu cầu chắc chắn là một loại lỗi. Các ngoại lệ là một cách khác để báo cáo các điều kiện ngoại lệ, được sử dụng thay cho các giá trị trả về đặc biệt (như null, như bạn đã viết, hoàn toàn không có ích gì nếu có> 1 lý do có thể khiến mọi thứ trở nên tồi tệ (ngay cả khi có chính xác là 1 lý do có thể có ngay bây giờ, có thể có 2 lý do có thể có trong phiên bản tiếp theo, vì vậy sử dụng nulllàm giá trị trả về cho thấy thất bại sẽ khiến bạn bị cuốn vào góc)). Nếu dịch vụ không báo cáo theo bất kỳ cách nào tại sao nó sẽ không làm những gì bạn yêu cầu, thì đó chắc chắn là thiết kế tồi.

Cho dù sử dụng giá trị trả về đặc biệt (ví dụ: số nguyên âm có hữu ích cho các hàm thường trả về số nguyên không âm) hay không, ngoại lệ, trình xử lý lỗi toàn cục hoặc logger, v.v., cuối cùng là một chi tiết triển khai. Sự lựa chọn phụ thuộc vào ngôn ngữ, tình huống, quy ước và cũng là một câu hỏi về hương vị. Điểm chính là cần có một số cách trực tiếp để tìm hiểu lý do tại sao một cái gì đó không hoạt động. Mặt khác, lựa chọn duy nhất của bạn là dọn rác xung quanh với các tùy chọn khác nhau và bất cứ điều gì để tìm hiểu xem điều gì có liên quan đến hành vi của hộp đen và thật lãng phí thời gian.

String.substring()ném một IndexOutOfBoundsExceptionnếu chỉ số nằm ngoài giới hạn. nullThay vào đó, tôi không thể nghĩ đến bất kỳ lợi thế nào để trở về , mặc dù - về mặt triết học - người ta có thể lập luận rằng Stringkhông chứa bất cứ thứ gì ngoài giới hạn của nó, vì vậy nullsẽ là một giá trị trả về hợp lý sau đó. Có logic-triết học và thực tế rõ ràng là hai động vật khác nhau.


Nếu chuỗi con () sẽ trả về một giá trị cho các chỉ mục ngoài giới hạn, nó sẽ trả về một phần của chuỗi giữa các chỉ mục, có thể trống. Điều đó có thể lưu một bài kiểm tra trong một số mã gọi.
kevin cline

2
Vâng, có "giá trị trống" không bao giờ kết thúc này so với null -discussion: chuỗi con cho các chỉ mục ngoài giới hạn là null hay một chuỗi rỗng? Tôi không biết, cả hai đều thực sự "không có gì" (tốt, có lẽ null là "không có gì" hơn một chuỗi trống?), Nhưng không cung cấp lượng thông tin mà một ngoại lệ thực hiện.
Joonas Pulakka

@kevincline: Trừ khi một người đang sử dụng một khung trong đó tham chiếu null là một phương tiện thành ngữ để chỉ ra một chuỗi rỗng, tôi không thấy bất kỳ cơ sở nào substringđể trả về một tham chiếu null. IMHO, cần có hai chức năng riêng biệt - một trong số đó hứa hẹn sẽ trả về số lượng ký tự được yêu cầu hoặc ném ngoại lệ, và một trong số đó trả về càng nhiều càng tốt. Mỗi phương pháp sẽ vượt trội hơn hẳn so với phương pháp khác trong một số bối cảnh.
supercat

@supercat: Tôi không nói gì về việc trả về null. Tôi nói 'trở về ... phần ... có thể trống rỗng'. Một chuỗi rỗng không rỗng, ngoại trừ Oracle.
kevin cline

@JoonasPulakka: Tôi nên ping bạn đến nhận xét trước đây của tôi.
supercat

5

Nó đi xuống những gì hợp đồng là. Nếu hợp đồng của bạn nói rằng bạn có thể yêu cầu một cái gì đó không tồn tại, thì nó sẽ nói điều gì xảy ra (đối tượng null hoặc null).

Mặt khác, nếu hợp đồng của bạn nói rằng bạn nên gọi một phương thức khác trước ( DoesSomethingExist()) và sau đó gọi Getphương thức đó, thì hợp đồng của bạn có thể nói rằng bạn chỉ có thể có được những thứ tồn tại và ném ngoại lệ nếu chúng không có. Thông báo ngoại lệ có thể nói điều gì đó như "Hãy chắc chắn gọi DoesSomethingExist()trước", đây là một thông báo lỗi hữu ích.


Trong trường hợp này tôi sẽ nói rằng không bình thường khi yêu cầu thứ gì đó không tồn tại, vì có lẽ bạn sẽ không yêu cầu một id không tồn tại. Thông thường trước tiên bạn sẽ nhận được một danh sách các thứ và sau đó tìm kiếm một trong những thứ cụ thể để biết thêm chi tiết. Vì vậy, nếu có một findAllThingsphương thức, thì tôi sẽ nói là phù hợp để trả về một danh sách trống hoặc một tập hợp con nếu có một số hoặc tất cả những thứ bạn không được phép xem. Theo cùng một cách tôi có thể trên một blog chỉ liệt kê các bài đăng để chỉnh sửa thuộc về người dùng hiện tại. Nhưng nếu người dùng đó đã cố gắng chỉnh url và chỉnh sửa một bài đăng khác ...
Svish

4

Không có câu trả lời nào phù hợp cho tất cả các câu hỏi. Việc sử dụng ngoại lệ hay trả về null tùy thuộc vào tình huống.

Thay vì nhìn vào điều này hoàn toàn từ quan điểm giáo điều, hãy xem giao diện như một giao diện người dùng . Giao diện người dùng nên được sử dụng . Vì vậy, bất kể ý kiến ​​của bạn về cách "đúng" để làm điều gì đó, hãy chọn phương pháp có thể sử dụng nhiều nhất theo quan điểm của ai đó sử dụng giao diện của bạn.

Nếu người gọi cần biết lý do tại sao một đối tượng không được trả lại, một ngoại lệ là phù hợp. Tuy nhiên, nếu khái niệm chung là "nếu bạn không có quyền, thì nó không tồn tại", null là chấp nhận được.

Cụ thể trong trường hợp của bạn, tôi muốn nói null hoàn toàn chấp nhận được khi tìm kiếm một mục nếu người gọi được yêu cầu đăng nhập hoặc kết nối với máy chủ trước tiên. Đó là khi bạn sẽ được thông báo rằng bạn làm hoặc không được phép. Khi bạn vượt qua cổng, thật hợp lý khi bạn tìm kiếm thứ gì đó mà bạn không được phép xem (hoặc thậm chí biết nó tồn tại), bạn sẽ nhận được một giá trị rỗng.

Mặt khác, nếu bạn không có kết nối ban đầu hoặc bước đăng nhập, một ngoại lệ có ý nghĩa. Nếu người gọi biết một vật phẩm tồn tại và họ không nhận lại được, API sẽ không hữu ích khi chỉ trả về null.

Tuy nhiên, để tạo một mục, đó là một câu chuyện khác. Có lẽ có rất nhiều lý do để thất bại - không có quyền, tham số xấu, máy chủ hết bộ nhớ, v.v. Nếu nhà phát triển được cung cấp null cho tất cả các điều kiện đó, họ không có cách nào để xác định một hành động phù hợp .

Vì vậy, để trả lời câu hỏi, hãy tự hỏi mình giải pháp hữu dụng nhất là gì từ quan điểm của một người sử dụng dịch vụ. Nó có thể là cách bạn đang sử dụng nó là không điển hình, và trong trường hợp phổ biến nhất, null là câu trả lời đúng.

Vì vậy, đừng tham gia vào một cuộc chiến tôn giáo về vấn đề này, hãy quyết định xem điều gì đúng cho vấn đề đặc biệt này.


Không có kế hoạch đưa vào thiết bị chiến đấu về điều này, hehe. Chỉ tò mò muốn biết liệu tôi có hoàn toàn sai lầm khi nghĩ tôi đang nghĩ gì hay không. Tôi muốn học, nhưng tôi không muốn nhảy vào một cái gì đó chỉ vì một người nói như vậy. Và đặc biệt là không nếu nó đi ngược lại kinh nghiệm và logic của riêng tôi (dù nhỏ đến đâu). Dù sao, tôi hoàn toàn đồng ý rằng nếu đây là giao diện người dùng cuối thì điều đó thực sự có thể có ý nghĩa. Tuy nhiên, vì đây là một bean mà theo như tôi biết, chỉ có thể được truy cập bằng mã, tôi sẽ nói rằng tôi, với tư cách là một nhà phát triển, người dùng.
Svish

1
Và là một nhà phát triển, tôi quan tâm đến việc tại sao có điều gì đó không ổn, bất kể người dùng cuối nên biết gì về nó.
Svish

Hoàn toàn đồng ý với Bryan. Ngay cả những người phát ngôn là người dùng, tức là tiêu thụ một số mã nhà phát triển khác. Mô tả ném hoặc null là một loại giao diện / gui sẽ hữu ích cho các nhiệm vụ cụ thể. Không chỉ bằng thuật ngữ chung của logic hoặc triết học.
Độc lập

3

Tôi chắc chắn nghĩ rằng đó là một thiết kế xấu . Null-con trỏ không phải là một câu trả lời hợp lệ đối với tôi và nó có thể khó quản lý.

Nếu người dùng cố gắng kết nối một dịch vụ mà không có thông tin xác thực, tôi nên trả lời bằng một câu trả lời rõ ràng và súc tích. Câu trả lời có thể là một ngoại lệ hoặc một đối tượng đặc biệt nhưng không phải là null.

Bạn nên để lại câu trả lời không khi liên kết mạng bị hỏng hoặc sự cố nghiêm trọng không mong muốn khác.

Hơn nữa, thời gian bạn dành để hiểu lý do tại sao bạn có một null là một đối số mạnh mẽ. Bất kỳ đoạn mã nào cũng phải dễ hiểu và dễ sử dụng. Có một giá trị null không phải là trường hợp.


Theo câu cuối cùng của bạn, bạn có nghĩa là "Bạn chỉ nên trả về null khi liên kết mạng bị hỏng, v.v." hoặc "Bạn nên dừng trả về null khi liên kết mạng bị hỏng, v.v." ?
Péter Török

@ Péter Török: Tôi không khuyến nghị sử dụng rõ ràng "return null;". Tuy nhiên, khi sự cố lớn xảy ra, một số dịch vụ có thể trả về null.
Amin

Sẽ không có ngoại lệ thích hợp hơn nếu xảy ra sự cố nghiêm trọng không mong muốn?
Svish

2
@Amine: Tôi muốn nói rằng đó là trường hợp ít thích hợp nhất để trả về null.
Michael Borgwardt

@Svish: nếu bạn có thể phát hiện ra sự cố lớn, tất nhiên một ngoại lệ sẽ rất tuyệt.
Amin

3

Mang thiết kế phần mềm tốt trong tâm trí, bạn nên nghĩ về cuộc sống của dự án của bạn.
Bằng cách trả lại null, như đã nói, bạn không cung cấp bất kỳ thông tin nào cho khách hàng. Hãy nhìn những gì xảy ra với bạn, lúc đầu bạn không nhận ra vấn đề ở đâu. Hơn nữa, nếu không có tài liệu nào được đưa ra, đây là một mớ hỗn độn.

Bằng cách ném một ngoại lệ, bạn có thể nói những gì đã sai. Bạn thậm chí có thể tùy chỉnh văn bản được hiển thị để cụ thể hơn nếu bạn muốn.

Mặt khác, bằng cách quay lại, nullbạn làm cho khách hàng điều tra những gì nó đang diễn ra.

Hơn nữa, bạn nhận ra rằng có một vấn đề bởi vì bạn đã đi nơi khác a NullPointerException. Bây giờ hãy tưởng tượng bạn không lưu trữ sự trở lại của chức năng đó ... Bạn sẽ bị buộc phải bao quanh mỗi cuộc gọi đến chức năng đó bằng một if elsekhối ...

Theo quan điểm của tôi, trở về nulllà một thực tế xấu.


2

Nhà phát triển có kinh nghiệm hơn đã viết dịch vụ này lập luận rằng việc yêu cầu dữ liệu không phải là một điều kiện lỗi và các ngoại lệ chỉ nên được đưa ra trong một điều kiện lỗi, không phải khi người dùng không có quyền truy cập vào dữ liệu.

Theo quan điểm của tôi, điều này không có ý nghĩa.

Truy vấn dữ liệu mà không có sự cho phép sẽ dẫn đến một ngoại lệ, bởi vì đó là một kết quả không mong muốn - không có kết quả - mà không có quyền truy cập thích hợp.

Tương tự : Mã phản hồi cho việc GETkhông có ủy quyền không thực 200 oksự không có dữ liệu 401 Unauthorized.


1

Trả lại null không phải là tuyệt vời. Nó không nói gì với bạn. Lấy ví dụ của bạn, nếu một ứng dụng đang cố gắng tìm kiếm thứ gì đó và phản hồi là null cho cả hai vấn đề bảo mật và nếu mục đó không tồn tại, vậy làm thế nào để bạn biết sự khác biệt giữa hai?

Một phản hồi có ý nghĩa có thể cho phép ứng dụng đưa ra các lựa chọn hợp lý về những việc cần làm tiếp theo hoặc cách giải quyết vấn đề.


Bạn hỏi làm thế nào để bạn biết sự khác biệt giữa một đối tượng không có ở đó và bạn thiếu sự cho phép để nhìn thấy nó. Có thể thiết kế của hệ thống yêu cầu bạn không biết. Tôi không nghĩ rằng chúng ta có đủ thông tin để trả lời trong trường hợp cụ thể này và không có câu trả lời nào hoạt động trong mọi trường hợp. Có những trường hợp sử dụng hoàn toàn hợp lệ trong đó, nếu bạn không thể thấy nó thì thực sự không có ở đó. Và, có những trường hợp sử dụng nếu bạn không thể nhìn thấy nó, bạn nên đưa ra một ngoại lệ để nói tại sao bạn không thể.
Bryan Oakley

Bạn có ý nghĩa gì bởi "thiết kế của hệ thống yêu cầu bạn không biết"? Những loại thiết kế có thể được?
Svish

2
Nếu chính sách bảo mật nói rằng bạn không được phép nhìn thấy nó, thì trong hầu hết các trường hợp, bạn cũng không thể biết rằng nó tồn tại. Điều đó làm cho việc trả lại "không tìm thấy" hoàn toàn chấp nhận được.
Blrfl

1

Nếu nguyên nhân gốc là người dùng không được xác thực thì tôi thích phản hồi HTTP 401 cứng hơn có lẽ là chuyển hướng đến một trang thông báo đẹp (và thông báo cho ai đó quan tâm). Nguyên nhân liên quan đến ủy quyền là nhiều trường hợp cụ thể hơn; có các đối số để trả về các lỗi HTTP (403, giả sử) và các đối số để trả về các mã / thông báo được tạo tốt đặc biệt trong phản hồi dịch vụ.

Các trường hợp ngoại lệ chỉ nên được sử dụng trong các trường hợp đặc biệt và có nghĩa là đã xảy ra sự cố. Tôi không đồng ý rằng họ nên bị quá tải có nghĩa là "không được phép". (Điều tương tự cũng đúng với giá trị trả về null: Tôi không đồng ý rằng nó nên được sử dụng để có nghĩa là "không được phép".)


Chà, trong GUI bạn có thể làm điều này, nhưng đối với bean triển khai dịch vụ thực hiện những điều phía sau hậu trường, bạn chỉ có ngoại lệ và các giá trị trả về đặc biệt theo ý của bạn. Tất nhiên tôi không có nghĩa là người dùng nên có ngoại lệ, nhưng ví dụ ngoại lệ có thể bị bắt trong dịch vụ web / servlet / bất cứ điều gì và sau đó làm những gì phù hợp. Chuyển hướng đến một nơi nào đó, trang http 4xx cứng hoặc một cái gì đó khác.
Svish

Điểm tốt, nhưng bạn có thể sử dụng một mô hình như AOP để nắm bắt những trường hợp này. Các khía cạnh có thể kiểm tra đặc quyền để gọi một hoạt động nhất định và chuyển hướng / cho phép xử lý để tiếp tục khi thích hợp.
Đánh dấu

0

Để chơi quỷ ủng hộ tôi sẽ cố gắng để trở về null.

Theo tôi, chỉ có một tình huống mà loại phản ứng này gần như có thể chấp nhận được và đó là, như trong trường hợp này, khi có bảo mật.

Rất dễ dàng để vô tình cung cấp thông tin chi tiết về hệ thống của bạn mà những người không được ủy quyền không nên biết. Điều này nên tránh.

Lấy ví dụ, một tên người dùng và kiểm tra mật khẩu. Trả lại lỗi "Không tìm thấy tên người dùng" và lỗi "Mật khẩu sai" vì các mã lỗi riêng biệt rõ ràng sẽ mở ra cho bạn các vấn đề bảo mật nghiêm trọng vì trước tiên ai đó có thể tìm tên người dùng hợp lệ và sau đó tìm mật khẩu. Trả lại một "tên người dùng / mật khẩu không hợp lệ" chung sẽ là một lựa chọn tốt hơn.

Vì vậy, trong trường hợp cụ thể này, tôi sẽ nói rằng việc quay trở lại gần như ổn nullnhưng tôi đồng ý, sẽ rất khó chịu khi làm việc cùng.


Vâng, tôi sẽ không đồng ý. Theo tôi, phản hồi thích hợp sẽ là một ngoại lệ, nhưng cùng một trường hợp cho cả tên người dùng không tìm thấy và mật khẩu sai. FailsToLogin, UnlimitedCredentials, bất cứ điều gì.
Svish

@Svish - Nhưng nếu bạn đang cố gắng không đưa ra gợi ý nào về lý do cho sự thất bại thì việc trở lại nullchính xác là phản ứng ít hữu ích nhất. Hầu như bất cứ điều gì khác có khả năng có thể được sử dụng để khám phá một cái gì đó về hệ thống. Lý do OP phàn nàn là vì việc nulltrả lại không chỉ giải thích điều gì mà thậm chí còn vô ích. Đó là mục đích có chủ ý ... để nói hoàn toàn không có gì không có ích. Nhiệm vụ hoàn thành trong quan điểm của tôi.
OldCurmudgeon

Chà, có thể là như vậy, nhưng tôi vẫn nói rằng làm điều đó thật tệ. Ít nhất là bên trong một hệ thống. Trên các cạnh mà người dùng cuối nhìn thấy mọi thứ, thì chắc chắn, tôi có thể đồng ý. Nhưng bên trong hệ thống, các nhà phát triển của chúng tôi là những người dùng và tại sao trên thế giới chúng tôi muốn làm cho mọi thứ trở nên khó hiểu hơn? Như thể việc phát triển phần mềm chưa đủ khó ...
Svish 30/11/11

1
Và với ví dụ đăng nhập, tôi nói rằng thật tệ cho trải nghiệm người dùng khi không ít nhất nói điều gì đó về lý do tại sao dường như không có gì xảy ra khi họ (nghĩ rằng họ) nhập thông tin đăng nhập của họ. Nếu trang chỉ làm mới và có vẻ như nó đã bỏ qua nỗ lực đăng nhập của tôi, tôi sẽ cho rằng có gì đó không ổn với hệ thống, không phải những gì tôi nhập là sai.
Svish

-2

Tôi nghĩ return null là không thân thiện, khi máy khách gọi phương thức này và trả về null, máy khách không biết điều gì đã xảy ra và tại sao nó trả về null. Vì vậy, chúng ta nên ném sự thực thi có ý nghĩa và cung cấp một tài liệu để mô tả sự thực thi này.

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.