MVC / REST nên trả về 403 hoặc 404 cho các tài nguyên thuộc về người dùng khác?


33

Khi làm việc với một trang web dựa trên tài nguyên (như ứng dụng MVC hoặc dịch vụ REST), chúng tôi có hai tùy chọn chính khi khách hàng cố gắng GETtruy cập tài nguyên mà họ không có quyền truy cập:

  • 403 , nói rằng khách hàng là trái phép ; hoặc là
  • 404 , nói rằng tài nguyên không tồn tại (hoặc không thể định vị được).

Sự khôn ngoan thông thường và thực tiễn chung dường như là để đáp ứng với sự thật - đó là 403. Nhưng tôi tự hỏi liệu đây có thực sự là điều đúng đắn.

Hệ thống đăng nhập an toàn không bao giờ cho bạn biết lý do thất bại khi đăng nhập. Điều đó có nghĩa là, liên quan đến máy khách, không có sự khác biệt có thể phát hiện giữa tên người dùng không tồn tại và mật khẩu không chính xác. Mục đích của việc này là không làm cho ID người dùng - hoặc tệ hơn là địa chỉ email - có thể được khám phá.

Từ quan điểm riêng tư , có vẻ an toàn hơn rất nhiều khi trả lại 404. Tôi đã nhắc nhở về sự cố trong đó có người đã phát hiện ra người chiến thắng của một chương trình thực tế (Survivor, tôi nghĩ) bằng cách xem tài nguyên nào không tồn tại trên trang web so với những gì đã làm. Tôi lo ngại về 403 có khả năng cung cấp thông tin nhạy cảm như số sê-ri hoặc số tài khoản.

Có những lý do thuyết phục để không trả lại 404? Chính sách 404 có thể có tác dụng phụ tiêu cực ở nơi khác không? Nếu không, tại sao thực tế không phổ biến hơn?


1
Lý do thuyết phục không trả lại 404: Nếu dịch vụ ngừng hoạt động hoặc có lỗi / lỗi trong xác thực thì bạn sẽ nhận được 404, nhưng khách hàng / người dùng / người kiểm tra / nhà phát triển / người hỗ trợ cố gắng chẩn đoán sự cố có thể không biết Có gì sai từ thông báo lỗi.
Steven Evers

@Snorfus: Đó là một điểm tốt - Tôi đã đưa ra câu trả lời. Mặc dù Josh đã thêm một điểm phản hồi tốt ...
Aaronaught

Một khía cạnh khác cần ghi nhớ là: 404 được xử lý như thế nào? Có CDN hoặc một số loại bộ nhớ đệm? Nếu bạn muốn có thể lưu trữ bộ đệm đó, thì có lẽ bạn không muốn "người dùng không có quyền" 404 được lưu vào bộ nhớ cache.
pc1oad1etter

Câu trả lời:


15

Có một quan niệm sai lầm chung (và sử dụng sai) liên quan đến 403 Forbidden: không nên cho đi bất cứ điều gì về những gì máy chủ nghĩ về yêu cầu. Nó được thiết kế đặc biệt để nói,

Tôi nhận được những gì bạn yêu cầu, nhưng tôi sẽ không xử lý yêu cầu, bất kể bạn thử gì. Vì vậy, hãy ngừng cố gắng.

Bất kỳ UA hoặc khách hàng nào cũng nên giải thích điều đó có nghĩa là yêu cầu sẽ không bao giờ hoạt động và đáp ứng một cách thích hợp.

Điều này có ý nghĩa đối với khách hàng xử lý các yêu cầu thay mặt cho người dùng: nếu người dùng không đăng nhập hoặc nhập sai, khách hàng xử lý yêu cầu sẽ trả lời: "Tôi xin lỗi, nhưng tôi không thể làm gì" sau lần đầu tiên nó nhận được 403và ngừng xử lý các yêu cầu trong tương lai. Rõ ràng, nếu bạn muốn người dùng vẫn có thể yêu cầu quyền truy cập vào thông tin cá nhân của họ sau khi thất bại, đây là hành vi thù địch với người dùng.

403ngược lại 401 Authorization Required, điều này cho thấy rằng máy chủ sẽ xử lý yêu cầu miễn là bạn vượt qua thông tin xác thực chính xác. Đây thường là những gì mọi người nghĩ về khi họ nghe 403.

Nó cũng trái ngược với 404 Page Not Foundđiều đó, như những người khác đã chỉ ra, được thiết kế không chỉ để nói "Tôi không thể tìm thấy trang đó" mà còn đề xuất với khách hàng rằng máy chủ không đưa ra yêu cầu thành công hay thất bại cho các yêu cầu trong tương lai.

Với 401404, máy chủ không nói gì với khách hàng hoặc UA về cách họ nên tiến hành: họ có thể tiếp tục cố gắng với hy vọng nhận được phản hồi khác.

Vì vậy, 404cách thích hợp để xử lý một trang mà bạn không muốn hiển thị cho mọi người, nhưng không muốn cho đi bất cứ điều gì về lý do tại sao bạn sẽ không hiển thị nó trong một số tình huống.

Tất nhiên, điều này giả định rằng khách hàng đưa ra yêu cầu quan tâm đến sự thất thường của RFC. Một khách hàng đủ độc hại sẽ không quan tâm đến mã trạng thái được trả về ngoại trừ theo cách ngẫu nhiên. Người ta sẽ biết đó là một trang người dùng ẩn (hoặc một trang người dùng ẩn tiềm năng) bằng cách so sánh nó với các trang người dùng đã biết khác.

Đó là, giả sử người xử lý của bạn là users/*. Nếu tôi biết users/foo, users/barusers/baazlàm việc, máy chủ trả lại một 401, 403hoặc 404cho users/quuxkhông có nghĩa là tôi sẽ không thử nó, đặc biệt là nếu tôi có lý do để tin rằng có một quuxngười dùng. Một kịch bản ví dụ tiêu chuẩn là Facebook: hồ sơ của tôi là riêng tư, nhưng nhận xét của tôi về hồ sơ công khai thì không. Một khách hàng độc hại biết tôi tồn tại ngay cả khi bạn quay lại 404trang hồ sơ của tôi.

Vì vậy, mã trạng thái không dành cho các trường hợp sử dụng độc hại, chúng dành cho các máy khách chơi theo luật. Và đối với những khách hàng đó, một 401hoặc một 404yêu cầu là phù hợp nhất.


4
Tuy nhiên, điểm tốt về 401 so với 403. Mặc dù vậy, tôi không đồng ý với tính hữu hạn của các tuyên bố của bạn trên 404. Chắc chắn, trong ví dụ của Facebook, bạn đã biết điều đó quuxtồn tại. Nhưng không phải lúc nào cũng là bằng chứng bên ngoài, đặc biệt là trên các trang web phi xã hội nơi dữ liệu khách hàng thực sự riêng tư . Một tò mò hoặc thù địch sử dụng cuối cùng có thể có thể suy ra rằng bạn đang nói dối, nhưng không nhất thiết phải tài nguyên mà bạn đang nói dối về . Tôi nghĩ rằng điểm nổi bật ở đây là thực sự, đừng bận tâm đến tài nguyên 404 trừ khi không có phương pháp khám phá nào khác.
Aaronaught

@Aaronaught Vấn đề là, bạn phải thực sự, thực sự chắc chắn rằng ai đó không thể hiểu được máy chủ đang lừa dối điều gì, hoặc không có phương pháp khám phá nào mà bạn chưa từng chống lại. Một người đủ thông minh sẽ tìm ra nó, và tại thời điểm đó, mã trạng thái là vô nghĩa.

1
Tôi vẫn chưa rõ làm thế nào một người đủ thông minh có thể tìm ra nếu không có sự chia sẻ dữ liệu giữa các hồ sơ người dùng. Tôi hiểu rằng ai đó đã xác định cuối cùng sẽ nhận ra "ồ, 404 thực sự có nghĩa là nó có thể tồn tại, nhưng tôi không thể truy cập được" - nhưng giả sử rằng máy chủ trả lại cùng một lỗi cho các tài nguyên thực sự không tồn tại, làm thế nào một Cho biết sự khác biệt giữa tài nguyên không tồn tại và tài nguyên đặc quyền?
Aaronaught

@Aaronaught điều duy nhất một người sẽ cần biết là URL đến một hồ sơ nên tồn tại. Bạn có thể chỉ cần sử dụng ID hồ sơ và tăng chúng theo kiểu giả (vì vậy một người có ID hồ sơ là 3333 không có nghĩa là có một người có ID hồ sơ là 3332), nhưng một người xác định sẽ có thể dự đoán được một số cỡ mẫu của ID hợp lệ. Không làm được điều đó, và thậm chí được cung cấp một hệ thống hoàn toàn cứng mà không rò rỉ thông tin nào về cách nó tạo URL cho các trang hồ sơ, luôn có kỹ thuật xã hội.

8

Theo RFC2616

10,4,4 403 Cấm

Máy chủ hiểu yêu cầu, nhưng từ chối thực hiện nó. Ủy quyền sẽ không giúp đỡ và yêu cầu KHÔNG NÊN lặp lại. Nếu phương thức yêu cầu không phải là CHÍNH và máy chủ muốn công khai lý do tại sao yêu cầu chưa được thực hiện, thì NÊN mô tả lý do từ chối trong thực thể. Nếu máy chủ không muốn cung cấp thông tin này cho khách hàng, mã trạng thái 404 (Không tìm thấy) có thể được sử dụng thay thế.

cũng lưu ý rằng khi truy cập tài nguyên Cấm, ủy quyền sẽ không giúp ích .


Tôi biết về RFC, mặc dù nó có chút giống với thực tế. Hầu như không có máy chủ nào giải thích lý do cho 403 ngoài câu đầu tiên đó ("Máy chủ hiểu yêu cầu, nhưng từ chối thực hiện nó.") Và hầu hết các khung MVC thậm chí có một cái gì đó tương tự như HttpUnauthorizedResultđược sử dụng cho các tài nguyên đặc quyền . Tôi cũng nhận ra (rõ ràng) rằng 404 có thể được sử dụng thay thế; Câu hỏi của tôi là có nên sử dụng hay không và nên xem xét điều gì khi đưa ra quyết định đó.
Aaronaught

@Aaronaught: RFC không chỉ cho phép bạn sử dụng 404, nó khuyên bạn nên ném 404 khi bạn không muốn thừa nhận bất cứ điều gì.
Nói dối Ryan

3
Điều đó tốt, nhưng khi nào tôi không nên thừa nhận bất cứ điều gì? Hay đúng hơn, khi nào tôi nên ? Đó thực sự là bản chất của câu hỏi.
Aaronaught

5

Bạn có nên .

Bạn tự nói điều đó, phản bội càng ít càng tốt. Nếu tôi đang tấn công một hệ thống và nhận thấy máy chủ phản hồi với 403 mã, tôi sẽ tập trung vào những hệ thống đó, thay vì tiếp tục. Tốt hơn là một cánh cửa tuyên bố nó không tồn tại sau đó tuyên bố nó bị cấm.

Nhược điểm của việc sử dụng các yêu cầu 404 là bên ngoài nó sẽ xuất hiện như thể trang không tồn tại và điều này có thể có xung đột khi so sánh với các trang được cho là tồn tại nhưng thay vào đó lại bị thiếu. Nếu bạn không lo lắng về trình thu thập dữ liệu web (hệ thống được xác thực hoàn toàn nên bị từ chối) thì bạn hoàn toàn nên đi tìm nó. Mọi API tôi xử lý truy cập trái phép theo cùng một cách chính xác và StackOverflow cũng vậy . Không thể xem trang đó? Tôi đảm bảo với bạn nó không tồn tại, mặc dù nó không tuyên bố.

Bạn nên xác nhận các yêu cầu khi tài nguyên được biết là tồn tại và quyền truy cập bị từ chối. Đăng nhập thất bại sẽ không dẫn đến một tin nhắn 404. Bạn không nên thừa nhận các yêu cầu khi sự tồn tại của chính tài nguyên cần được bảo vệ. Truy cập vào vương quốc tồn tại trong cộng đồng, nhưng các nhóm hoặc vai trò bảo mật trong đó thì không.


Lý do thuyết phục không trả lại 404: Nếu dịch vụ ngừng hoạt động hoặc có lỗi / lỗi trong xác thực thì bạn sẽ nhận được 404, nhưng khách hàng / người dùng / người kiểm tra / nhà phát triển / người hỗ trợ cố gắng chẩn đoán sự cố có thể không biết có gì sai từ thông báo lỗi

Các nhà phát triển nên có quyền truy cập vào nhật ký, điều này sẽ chỉ ra nỗ lực truy cập tài nguyên được bảo vệ. Khách hàng / Người dùng / Người kiểm tra sẽ tạo phản hồi mà cuối cùng sẽ đánh vào nhà phát triển.

Bảo mật bằng cách che khuất ... thực sự?

Đây không phải là bảo mật bởi tối nghĩa. Bạn đang sử dụng che khuất ngoài các biện pháp bảo mật thích hợp.

Mặt khác, các yêu cầu hợp lệ nhận được "404" chỉ là thêm sự phức tạp và tối nghĩa khi không cần thiết

Chúng không phải là yêu cầu hợp lệ, chúng là những yêu cầu trái phép . Bạn đang thay đổi một phần nhỏ (trả lại 404 thay vì 403) để có được lợi thế đáng kể trong bất kỳ kẻ tấn công nào.


Bảo mật bằng cách che khuất ... thực sự? Nếu ai đó đang cố gắng chọc (các) dịch vụ của bạn với mục đích xấu, họ đã biết nó ở đó. Các yêu cầu hợp lệ nhận được "404" mặt khác chỉ là thêm sự phức tạp và tối nghĩa khi không cần thiết.
Steven Evers

4
@Snorfus: Có một sự khác biệt tinh tế được thực hiện ở đây giữa bảo mậtquyền riêng tư . Quyền riêng tư, gần như theo định nghĩa, "bởi sự tối nghĩa". Điều này đặc biệt quan trọng trong bối cảnh của một hệ thống dựa trên tài nguyên , vì sự tồn tại hoặc không tồn tại của tài nguyên là thông tin quan trọng tiềm năng. Có thể có các đối số bảo mật là tốt, mặc dù tôi ít quan tâm đến chúng. Tôi muốn nghe thêm về sự phức tạp thêm này; bạn có thể đi vào chi tiết ngoài nhận xét ban đầu của bạn? (Có lẽ trong một câu trả lời toàn diện hơn? Bạn đã bị cắn bởi 404'ed 403s chưa?)
Aaronaught

2
@Snorfus: Tôi cũng muốn thêm vào, như một suy nghĩ lại, rằng phòng thủ theo chiều sâu không giống như bảo mật bởi sự tối nghĩa . Cái sau ngụ ý rằng không có phương tiện bảo vệ nào khác . Nhưng việc thêm phần tối nghĩa vào một hệ thống đã được bảo mật thường có thể là một điều tốt - miễn là nó không gây ra các vấn đề khác. Trong trường hợp này, chắc chắn rằng hệ thống đã được bảo mật, vì các 404 đang được phát ra bằng mã ủy quyền.
Aaronaught

@Aaronaught: Tôi sẽ đăng một câu trả lời sâu hơn, nhưng về vấn đề: nếu một tài nguyên là riêng tư thì lý do đằng sau việc công khai nó là gì?
Steven Evers

@Snorfus: Tài nguyên là riêng tư đối với khách hàng - hoặc có thể đối với một nhóm - không phải đối với toàn bộ thế giới.
Aaronaught

0

Nó thực sự phụ thuộc vào thông tin được cung cấp bởi mã trạng thái 403. Nếu bạn có điểm cuối API phản hồi GET /myresource/{id}với 404 khi tài nguyên không tồn tại, thì mã trạng thái được trả về bởi điểm cuối khi tài nguyên tồn tại nhưng không được ủy quyền cho người dùng hiện tại sẽ phụ thuộc vào khả năng dự đoán của idtham số và số lượng thông tin nó chứa chính nó.

  • Nếu idlà một lĩnh vực riêng tư như địa chỉ email hoặc số tài khoản ngân hàng, có lẽ nó phải luôn được ẩn đằng sau 404. Trong trường hợp địa chỉ email, nó có thể ngăn các bot spam biên dịch danh sách các địa chỉ email hợp lệ được đăng ký vào trang web của bạn.
  • Nếu idlà tên người dùng công khai, đừng bận tâm, có những cách khác để có quyền truy cập vào thông tin này (như, chỉ bằng cách duyệt trang diễn đàn của trang web của bạn).
  • Nếu idlà một định danh mờ, nhưng có thể dự đoán được (ví dụ: số nguyên tăng tự động), bạn không cung cấp bất kỳ thông tin nào cho kẻ tấn công mà anh ta không thể có được bằng các phương tiện khác. Vì vậy, theo tôi, việc trả lại mã trạng thái 403 là an toàn.
  • Nếu idlà một định danh mờ đục, không thể đoán trước (như một GUID ngẫu nhiên), câu hỏi sẽ tinh tế hơn. Cá nhân tôi nghĩ rằng không có vấn đề gì trong việc trả lại mã trạng thái 403. Thông tin này chỉ có thể được khai thác nếu có một điểm cuối bị lỗi khác trong API của bạn bằng ID này, nhưng lỗ hổng thực sự là điểm cuối khác của bạn.

Bạn có thể cho rằng an toàn hơn là xin lỗi trong mọi trường hợp và che giấu thông tin bất kể bối cảnh nào, nhưng bạn thực sự không thể dựa vào loại hành vi này để cung cấp bất kỳ hình thức bảo mật nào . Mặt khác, nó có thể cung cấp bảo mật (hoặc quyền riêng tư, như những người khác đã nói).

Một cơ chế bảo mật không chỉ là một cú hích tốc độ cho kẻ tấn công, nếu không thì nó hoàn toàn vô dụng. Trong trường hợp này, nó thậm chí có thể ngăn bạn sử dụng các tính năng khác một cách chính xác (trình thu thập thông tin, Tường lửa ứng dụng Web tìm kiếm số lượng bất thường 403 mã trạng thái để chặn người dùng ...).

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.