2008-09-27 29 views
15

Django đi kèm với CSRF protection middleware, tạo mã thông báo mỗi phiên duy nhất để sử dụng trong biểu mẫu. Nó quét tất cả các yêu cầu đến POST mã thông báo chính xác và từ chối yêu cầu nếu mã thông báo bị thiếu hoặc không hợp lệ.Việc hiển thị mã thông báo bảo vệ CSRF của phiên có an toàn không?

Tôi muốn sử dụng AJAX cho một số yêu cầu POST, nhưng các yêu cầu đã nói không có availabnle mã thông báo CSRF. Các trang không có các yếu tố <form> để móc vào và tôi không muốn làm mờ việc đánh dấu chèn mã thông báo dưới dạng giá trị ẩn. Tôi tìm một cách tốt để làm điều này là để lộ ra một vew như /get-csrf-token/ để trả lại mã thông báo của người dùng, dựa trên các quy tắc tập lệnh cross-site của trình duyệt để ngăn các trang web thù địch yêu cầu nó.

Đây có phải là một ý tưởng hay không? Có cách nào tốt hơn để bảo vệ chống lại các cuộc tấn công CSRF trong khi vẫn cho phép các yêu cầu AJAX?

Trả lời

11

Nếu bạn biết mình cần mã thông báo CSRF cho các yêu cầu AJAX, bạn luôn có thể nhúng mã HTML vào HTML ở đâu đó; thì bạn có thể tìm thấy nó thông qua Javascript bằng cách duyệt qua DOM. Bằng cách này, bạn sẽ vẫn có quyền truy cập vào mã thông báo, nhưng bạn không hiển thị mã thông báo qua API.

Để đặt theo cách khác: thực hiện thông qua các mẫu của Django - không thông qua trình điều phối URL. Nó an toàn hơn nhiều theo cách này.

+1

Thẻ CSRF sẽ thay đổi với mọi thao tác. Bạn có đề xuất rằng mỗi thao tác cập nhật mã thông báo? Điều đó không có nghĩa là các hoạt động của người dùng sẽ phải trở thành đồng bộ (thứ hai không thể bắt đầu cho đến khi lần đầu tiên quay trở lại và đưa ra mã thông báo csrf mới). – Mystic

+0

Đây không phải là câu trả lời hay nhất. Như Carl Meyer nói trong câu trả lời của ông: không cần phải bảo vệ các yêu cầu AJAX từ CSRF bằng cách sử dụng một mã thông báo * trong Django *, như Django đã bảo vệ các yêu cầu AJAX theo một cách khác. Điều này cũng loại bỏ mối quan tâm Mystics. – hopla

+1

có thể điều này sẽ giúp, ngay cả khi tôi không sắp xếp câu chuyện này về ajax & CSRF http://docs.djangoproject.com/en/dev/ref/contrib/csrf/#ajax – amirouche

0

Huỷ điều đó, tôi đã sai. (Xem ý kiến.) Bạn có thể ngăn chặn việc khai thác bằng cách đảm bảo JSON của bạn tuân theo đặc tả: Luôn đảm bảo bạn trả lại một đối tượng theo nghĩa đen là đối tượng cấp cao nhất. (Tôi không thể đảm bảo sẽ không còn khai thác nữa. Hãy tưởng tượng một trình duyệt cung cấp quyền truy cập vào mã không thành công trong các sự kiện window.onerror của nó!)

Bạn không thể dựa vào các quy tắc cross-site-scripting để giữ AJAX phản hồi riêng tư. Ví dụ: nếu bạn trả lại mã thông báo CSRF dưới dạng JSON, một trang web độc hại có thể redefine the String or Array constructor và yêu cầu tài nguyên.

bigmattyh là chính xác: Bạn cần phải nhúng mã thông báo ở đâu đó trong đánh dấu. Ngoài ra, bạn có thể từ chối mọi POST mà làm có một tham chiếu rằng không phù hợp với. Bằng cách đó, chỉ những người có tường lửa phần mềm quá mức mới có thể dễ bị tấn công bởi CSRF.

+0

Ugh, liên kết đó một lần nữa. Ít nhất tác giả đã thêm một lưu ý vào cuối rằng anh ta sai. JSON thực tế không dễ bị định nghĩa lại các nhà xây dựng, bởi vì trình phân tích cú pháp Javascript sẽ đưa ra một ngoại lệ khi bạn cố gắng phân tích cú pháp JSON chưa được trình bày. –

16

CẬP NHẬT: Điều sau đây là đúng và phải đúng nếu tất cả trình duyệt và plugin được triển khai đúng cách. Thật không may, bây giờ chúng ta biết rằng họ không phải là, và rằng một số kết hợp của trình duyệt bổ sung và chuyển hướng có thể cho phép kẻ tấn công để cung cấp các tiêu đề tùy ý trên một yêu cầu tên miền chéo. Thật không may, điều này có nghĩa là ngay cả các yêu cầu AJAX với tiêu đề "X-Requested-With: XMLHttpRequest" bây giờ phải được bảo vệ bởi CSRF. Kết quả là, Django no longer exempts Ajax requests from CSRF protection.

gốc trả lời

Đó là đáng nói đến là bảo vệ yêu cầu AJAX từ CSRF là không cần thiết, vì các trình duyệt không cho phép cross-site yêu cầu AJAX. Trên thực tế, phần mềm trung gian CSRF của Django bây giờ là automatically exempts AJAX requests from CSRF token scanning.

Điều này chỉ hợp lệ nếu bạn đang thực sự kiểm tra phía máy chủ tiêu đề X-Requested-With với giá trị "XMLHttpRequest" (mà Django thực hiện) và chỉ miễn các yêu cầu AJAX thực từ quét CSRF.

+0

Điều này không đúng. Một yêu cầu ajax rõ ràng là giao tiếp với một máy chủ (của bạn). Là kẻ tấn công, tôi vẫn có thể tạo yêu cầu đăng bài giống nhau từ bất kỳ nơi nào khác thông qua một số phương pháp khác nhau và không có bảo vệ CSRF, tôi sẽ thành công nếu người dùng đăng nhập. – Nathan

+2

@Nathan Bạn không thể tạo yêu cầu bài đăng giống nhau từ bất kỳ đâu khác thông qua một số phương pháp khác nhau ", bởi vì trình duyệt sẽ từ chối thực hiện yêu cầu đăng bài đó (trừ khi bạn có thể nhận miền của tôi để phục vụ JS của bạn, trong trường hợp này tôi rõ ràng có một lỗ khác). Bạn sẽ phải bỏ qua các hạn chế cùng tên miền hoặc lừa trình duyệt của người dùng thực hiện yêu cầu không phải AJAX và giả mạo tiêu đề X-Requested-With. Dù bằng cách nào, nếu bạn có thể làm điều đó đó là một lỗi trình duyệt. Làm việc demo chào đón. –

+0

@Carl Meyer: Tôi vẫn không đồng ý. Tôi có thể (ví dụ) thu hút một người sử dụng đến một trang web dưới sự kiểm soát của tôi mà làm cho một bài đăng đến máy chủ theo cùng một cách mà yêu cầu AJAX không - không tiêm javascript vào trang web của bạn cần thiết. Không có giới hạn tên miền giống nhau trên một bài đăng http bình thường - tôi có thể đăng bài với bất kỳ biểu mẫu nào tới bất kỳ miền nào. Các cookie được gửi cùng với yêu cầu - không phải với trang. Điều này vẫn thuộc danh mục Cross-Site-Request-Forgery. – Nathan

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