2011-11-21 17 views
11

Tôi đang thiết kế API cho một nhóm trang web. Các trang web là rất giống nhau (loại giống như StackOverflow, SuperUser và ServerFault), và nó làm cho tinh thần cho họ để có một phụ trợ được chia sẻ. Do đó, chúng tôi đã quyết định thử và có một API REST tốt đẹp như một phụ trợ, và một loạt các giao diện rất giống nhau nhưng khác nhau tiêu thụ API nói trên. Các giao diện tốt nhất nên là tất cả các tĩnh, nhưng đó không phải là một yêu cầu khó khăn nếu nó hóa ra là đường biên giới không thể.Làm thế nào để bạn bảo mật API RESTful được một trình duyệt từ các cuộc tấn công CSRF tiêu thụ?

Tôi đang thiết kế API đó ngay bây giờ và tôi lo lắng về các tác động bảo mật, đặc biệt là CSRF. Từ hiểu biết cơ bản về tấn công CSRF của tôi, chúng bao gồm hai thành phần quan trọng:

  1. Có thể đặt tên cho tài nguyên và phần yêu cầu.

  2. Lừa người dùng/trình duyệt vào sử dụng auth môi trường xung quanh (như phiên) để thực hiện yêu cầu tới tài nguyên đó được xác thực.

Rất nhiều cách tiếp cận cổ điển để khắc phục các cuộc tấn công CSRF dựa trên phiên. Vì API REST của tôi không thực sự thực hiện các phiên, cả hai đều ngăn chặn rất nhiều vectơ và cũng có khá nhiều cách để khắc phục chúng. Ví dụ: việc gửi hai lần không có ý nghĩa vì không có gì để gửi đôi.

Cách tiếp cận ban đầu của tôi liên quan đến tấn công phần 2 của cuộc tấn công CSRF. Nếu tôi xác thực tất cả các yêu cầu (nói bằng cách sử dụng xác thực cơ bản HTTP) và trình duyệt không lưu trữ các thông tin đăng nhập đó (ví dụ như một số JS đã thực hiện yêu cầu), chỉ JS có thông tin xác thực mới có thể thực hiện yêu cầu và chúng tôi đã hoàn tất . Nhược điểm rõ ràng là ứng dụng cần biết thông tin đăng nhập của người dùng. Nhược điểm khác ít rõ ràng hơn là nếu tôi muốn lưu trữ thông tin đăng nhập một cách an toàn vào cuối API, thì việc xác minh mật khẩu sẽ mất một khoảng thời gian cố định, không nhỏ. Nếu xác minh mật khẩu một cách an toàn mất 100ms, sau đó mọi yêu cầu khác sẽ mất ít nhất 100ms + eps, và nó sẽ mất một số thủ thuật khách hàng thông minh darn để làm cho rằng không cảm thấy chậm. Tôi có thể nhớ cache (vì thông tin đăng nhập sẽ luôn giống nhau) và nếu tôi rất cẩn thận, tôi có thể quản lý để làm điều đó mà không đưa ra lỗ hổng thời gian, nhưng âm thanh giống như tổ của hornet.

OAuth 2.0 có vẻ hơi hơn trên đầu, nhưng tôi đoán nó có thể là giải pháp tốt nhất sau tất cả, vì sợ rằng tôi sẽ thực hiện nó kém. Tôi cho rằng tôi có thể thực hiện điều xác thực cơ bản HTTP ngay bây giờ và chuyển sang OAuth khi chúng tôi có nhà phát triển ứng dụng bên thứ ba.

Có một chút trở kháng không khớp với OAuth. OAuth thực sự muốn giúp các ứng dụng truy cập nội dung trên ứng dụng khác, về cơ bản. Tôi muốn người dùng đăng ký trên một trong các giao diện người dùng, trước khi một tài khoản như vậy tồn tại.

Tôi cũng đã xem xét điểm tấn công 1 bằng cách tạo các URL ngẫu nhiên - nghĩa là thêm mã thông báo vào chuỗi truy vấn. Điều này chắc chắn sẽ hoạt động và nó rất gần với cách mã thông báo ngẫu nhiên truyền thống trong một biểu mẫu hoạt động, và cho HATEOAS nó thậm chí còn khá yên tĩnh, mặc dù điều này đặt ra hai câu hỏi: 1) bạn bắt đầu từ đâu? Có một điểm bắt đầu API bắt buộc khi bạn đăng nhập bằng HTTP Basic Auth không? 2) Làm thế nào nó có thể làm cho các nhà phát triển ứng dụng hạnh phúc nếu họ không thể dự đoán một URL lên phía trước, HATEOAS được damned?

Tôi đã xem How to prevent CSRF in a RESTful application?, nhưng tôi không đồng ý với tiền đề rằng các URI ngẫu nhiên nhất thiết là không ổn định. Ngoài ra, câu hỏi đó không thực sự có bất kỳ câu trả lời thỏa đáng nào và không đề cập đến OAuth. Ngoài ra, giải pháp gửi đôi phiên không hợp lệ, như tôi đã đề cập ở trên (miền khác cho giao diện người dùng tĩnh hơn điểm cuối API).

Tôi nhận ra rằng những gì tôi về cơ bản cố gắng làm ở đây là cố gắng cho phép các yêu cầu chéo từ một miền và không cho phép chúng từ miền khác và điều đó không dễ dàng. Chắc chắn phải có một số giải pháp hợp lý?

+0

Vấn đề, như bạn nói, là bạn muốn cả hai ngăn chặn và cho phép yêu cầu qua nhiều trang web. Hãy hỏi Schrödinger. –

+0

Điều đó không có nghĩa là không có cách nào để giải quyết vấn đề. Tôi thậm chí còn cung cấp một cái có thể, mặc dù hơi chậm. – lvh

Trả lời

0

Câu trả lời tùy thuộc vào những gì bạn cần hỗ trợ. Nếu chúng tôi giả định rằng bạn muốn hỗ trợ ứng dụng web mà sử dụng dịch vụ REST và sử dụng cùng một dịch vụ REST cho API khác với một ứng dụng web xảy ra là RESTFUL (bạn có thể quyết định rằng 'phiên' là dành cho bạn!).

Hiện tại (/ tôi khá mệt mỏi) Tôi nghĩ cách bạn đã đề xuất sử dụng javascript với Xác thực cơ bản HTTP là một khởi đầu tốt.

+0

Xác thực cơ bản HTTP dễ bị tấn công bởi CSRF. – rook

+0

Bạn có thể quan tâm để xây dựng? Tôi nhận ra rằng các trình duyệt cache HTTP Basic Auth, nhưng chúng tôi không yêu cầu trình duyệt thực hiện nó; chúng tôi đang đề xuất có một số JS xây dựng tiêu đề Xác thực cơ bản HTTP. Do đó các thông tin đăng nhập không bao giờ kết thúc trong nhóm xác thực xung quanh của trình duyệt và hệ thống trở nên miễn dịch CSRF. Chính xác? – lvh

3

Mã thông báo CSRF theo định nghĩa "theo trạng thái người dùng" và do đó không phải là RESTful. Hầu hết các API đều phá vỡ các yêu cầu "cho mỗi trạng thái người dùng" của chúng cho mục đích bảo mật và yêu cầu mã thông báo CSRF được truyền dưới dạng thông số tiêu đề HTTP.

Có các cách khác của preventing CSRF. Việc kiểm tra tham chiếu không mạnh bằng mã thông báo CSRF, nhưng nó là RESTful và VERY không thể bị làm suy yếu. Hãy nhớ rằng việc thiếu một người giới thiệu nên được coi là một yêu cầu thất bại.

XSS có thể được sử dụng để bỏ qua cả ngăn chặn CSRF dựa trên mã thông báo và phòng ngừa CSRF dựa trên tham chiếu.

+0

Nhận xét giống như trong trả lời của tôi cho bình luận của bạn. Bạn có thể giải thích tại sao HTTP Basic Authentication không ngăn CSRF khi bạn thêm tiêu đề xác thực bằng JS? Ngoài ra, OAuth không ngăn chặn CSRF như thế nào? Phần mã thông báo một lần của OAuth có đảm bảo rằng không? – lvh

+0

@lvh tên người dùng và mật khẩu là trạng thái cho mỗi người dùng đang được gửi cùng với yêu cầu. Một Nonce mã hóa được sử dụng như một mã thông báo CSRF cũng được gửi cho mỗi trạng thái người dùng với mọi yêu cầu, nhưng nó an toàn hơn vì nó phải là một giá trị động gắn liền với một phiên. Thông thường các giao thức RESTful dựa vào một nocne mã hóa tĩnh hoặc "api key", là trạng thái cho mỗi người dùng và cũng dừng CSRF. Gửi nó trong tiêu đề HTTP không kỳ diệu làm cho nó yên tĩnh, nhưng nó có thể mở cửa để tấn công nếu các yêu cầu khác được gửi bởi trình duyệt đó chứa giá trị này. – rook

+0

Nhưng đó là quan điểm của tôi. Vector tấn công là gì nếu nó không trở thành auth trình duyệt môi trường xung quanh? Cho dù đó là nonce hay thông tin xác thực thực sự không quan trọng cho các mục đích của CSRF: trình duyệt không * biết *, vậy làm thế nào nó có thể bị lừa khi cung cấp nó? – lvh

0

Tôi có một giải pháp tiềm năng khác, vì vậy tôi liệt kê giải pháp đó là câu trả lời. Vui lòng giải phóng nó ra :)

auth.platform.com có xác thực và đặt cookie. Nếu auth.site.com là CNAME cho số auth.platform.com, yêu cầu gửi số auth.site.com (kết thúc tại số auth.platform.com sau khi giải quyết) có thể đặt cookie cho site.com không? Bằng cách đó tôi có thể gửi hai lần cookie phiên.

Tất nhiên, auth.platform.com sẽ chỉ đặt cookie cho một vài miền thuộc danh sách cho phép.

EDIT: Ngoại trừ tất nhiên điều này sẽ không có tác dụng gì cả, bởi vì bạn phải sử dụng HTTPS để thực hiện xác thực một cách an toàn và HTTPS sẽ nhìn thấy ngay thông qua sự lừa đảo của bạn.

0

Thiết kế API của bạn như một RESTful đúng, ngăn chặn các vectơ CSRF phổ biến nhất:

  • tránh cookie ngăn chặn chúng được "đánh cắp",
  • sử dụng GET cho các hoạt động "an toàn" ngăn imgiframes để kích hoạt các hành động không an toàn mà không có sự tương tác của người dùng.

Sau đó, bạn nên triển khai CORS để cho phép trình duyệt của người dùng chặn yêu cầu từ nguồn gốc mà bạn không tin tưởng.

+1

-1 Không có điều này liên quan đến CSRF, ngoại trừ nhận xét về CORS. CORS nguy hiểm và có thể được sử dụng để đọc mã thông báo CSRF hoặc thông tin nhạy cảm khác. CORS không thể được sử dụng để ngăn chặn CSRF. – rook

Các vấn đề liên quan