Mã thông báo CSRF cần thiết khi sử dụng Xác thực không trạng thái (= Không phiên)?


125

Có cần thiết phải sử dụng Bảo vệ CSRF khi ứng dụng dựa vào xác thực không trạng thái (sử dụng thứ gì đó như HMAC) không?

Thí dụ:

  • Chúng tôi đã có một ứng dụng trang duy nhất (nếu không chúng ta phải thêm mã thông báo mỗi liên kết: <a href="...?token=xyz">...</a>.

  • Người dùng tự xác thực bằng cách sử dụng POST /auth. Khi xác thực thành công, máy chủ sẽ trả về một số mã thông báo.

  • Mã thông báo sẽ được lưu trữ qua JavaScript trong một số biến bên trong ứng dụng trang đơn.

  • Mã thông báo này sẽ được sử dụng để truy cập các URL bị hạn chế như /admin.

  • Mã thông báo sẽ luôn được truyền bên trong Tiêu đề HTTP.

  • KHÔNG CÓ Phiên Http và KHÔNG CÓ Cookie.

Theo như tôi hiểu, không nên (?!) Không có khả năng sử dụng các cuộc tấn công chéo trang web, bởi vì trình duyệt sẽ không lưu trữ mã thông báo và do đó nó không thể tự động gửi nó đến máy chủ (đó là điều sẽ xảy ra khi sử dụng Cookie / Phiên).

Tui bỏ lỡ điều gì vậy?


6
Hãy cẩn thận về Basic Auth. Nhiều trình duyệt sẽ tự động gửi các tiêu đề xác thực cơ bản cho phần còn lại của phiên. Điều này có thể làm cho auth cơ bản dễ bị CSRF tấn công như auth cookie.
phylae

Câu trả lời:


159

Tôi đã tìm thấy một số thông tin về CSRF + không sử dụng cookie để xác thực:

  1. https://auth0.com/blog/2014/01/07/angularjs-authentication-with-cookies-vs-token/
    "vì bạn không dựa vào cookie, bạn không cần phải bảo vệ khỏi các yêu cầu trang web chéo"

  2. http://angular-tips.com/blog/2014/05/json-web-tokens-introduction/
    "Nếu chúng tôi sử dụng cookie, bạn thực sự cần thực hiện CSRF để tránh các yêu cầu trên nhiều trang web. Đó là điều chúng tôi có thể quên khi sử dụng JWT như bạn sẽ thấy. "
    (JWT = Json Web Token, xác thực dựa trên Token cho các ứng dụng không trạng thái)

  3. http://www.jamesward.com/2013/05/13/securing-single-page-apps-and-rest-services
    "Cách dễ nhất để xác thực mà không gặp rủi ro về lỗ hổng CSRF là chỉ cần tránh sử dụng cookie để xác định người dùng "

  4. http://sitr.us/2011/08/26/cookies-are-bad-for-you.html
    "Vấn đề lớn nhất với CSRF là cookie hoàn toàn không có khả năng bảo vệ chống lại kiểu tấn công này. Nếu bạn đang sử dụng xác thực cookie bạn cũng phải sử dụng các biện pháp bổ sung để bảo vệ khỏi CSRF. Biện pháp phòng ngừa cơ bản nhất mà bạn có thể thực hiện là đảm bảo rằng ứng dụng của bạn không bao giờ thực hiện bất kỳ tác dụng phụ nào theo yêu cầu GET. "

Có rất nhiều trang khác, trong đó nói rằng bạn không cần bất kỳ bảo vệ CSRF nào, nếu bạn không sử dụng cookie để xác thực. Tất nhiên bạn vẫn có thể sử dụng cookie cho mọi thứ khác, nhưng tránh lưu trữ bất cứ thứ gì như session_idbên trong nó.


Nếu bạn cần ghi nhớ người dùng, có 2 lựa chọn:

  1. localStorage: Kho lưu trữ khóa-giá trị trong trình duyệt. Dữ liệu được lưu trữ sẽ khả dụng ngay cả sau khi người dùng đóng cửa sổ trình duyệt. Các trang web khác không thể truy cập dữ liệu vì mỗi trang web đều có bộ nhớ riêng.

  2. sessionStorage: Cũng là một kho dữ liệu trong trình duyệt. Sự khác biệt là: Dữ liệu bị xóa khi người dùng đóng cửa sổ trình duyệt. Nhưng nó vẫn hữu ích, nếu ứng dụng web của bạn bao gồm nhiều trang. Vì vậy, bạn có thể làm như sau:

    • Người dùng đăng nhập, sau đó bạn lưu trữ mã thông báo vào sessionStorage
    • Người dùng nhấp vào một liên kết sẽ tải một trang mới (= một liên kết thực và không có nội dung javascript thay thế)
    • Bạn vẫn có thể truy cập mã thông báo từ sessionStorage
    • Để đăng xuất, bạn có thể xóa thủ công mã thông báo khỏi sessionStoragehoặc đợi người dùng đóng cửa sổ trình duyệt, thao tác này sẽ xóa tất cả dữ liệu được lưu trữ.

(cho cả hai, hãy xem tại đây: http://www.w3schools.com/html/html5_webstorage.asp )


Có bất kỳ tiêu chuẩn chính thức nào cho xác thực mã thông báo không?

JWT (Json Web Token): Tôi nghĩ nó vẫn là một bản nháp, nhưng nó đã được nhiều người sử dụng và khái niệm này trông đơn giản và an toàn. (IETF: http://tools.ietf.org/html/draft-ietf-oauth-json-web-token-25 )
Cũng có sẵn các thư viện cho rất nhiều khuôn khổ. Chỉ cần google cho nó!


37
Tóm tắt tuyệt vời về CSRF! Tôi sẽ lưu ý rằng việc lưu trữ mã thông báo của bạn trong localStorage hoặc sessionStorage dễ bị tấn công XSS và dữ liệu có thể được xem bởi các tập lệnh trên trang - vì vậy nếu bạn có một tập lệnh bị xâm phạm được phân phát từ CDN hoặc nếu có mã độc hại trong một trong các Thư viện JS, chúng có thể lấy cắp mã thông báo từ những nơi lưu trữ đó. Xem: stormpath.com/blog/… Tôi nghĩ cách tiếp cận an toàn nhất là lưu trữ mã thông báo JWT + CSRF trong cookie, sau đó đặt JWT được tính toán của bạn với mã thông báo CSRF bên trong nó trong tiêu đề yêu cầu.
Aaron Grey

Về việc: "Biện pháp phòng ngừa cơ bản nhất mà bạn có thể thực hiện là đảm bảo rằng ứng dụng của bạn không bao giờ thực hiện bất kỳ tác dụng phụ nào theo yêu cầu GET." Một cuộc tấn công CSRF có thể giả mạo một yêu cầu POST không?
Costa

Tùy thuộc vào Ứng dụng phía máy chủ, nó CÓ THỂ. Có những khung công tác web, sử dụng một cái gì đó như http://.../someRestResource?method=POST. Vì vậy, về cơ bản nó là một GETyêu cầu, nhưng Ứng dụng máy chủ hiểu nó là một POSTyêu cầu, vì nó đã được định cấu hình để sử dụng methodtham số thay vì tiêu đề HTTP. ...Đối với các trình duyệt web phổ biến, chúng thực thi Chính sách cùng nguồn gốc và sẽ chỉ thực hiện GETcác yêu cầu đến các máy chủ nước ngoài. Mặc dù thể thực hiện POSTcác yêu cầu nếu trình duyệt web không áp dụng các tiêu chuẩn web đó (lỗi, phần mềm độc hại).
Benjamin M

1
Bổ sung cho Server Side App: Vẫn không thể gửi Nội dung yêu cầu vì các trình duyệt phổ biến sẽ không cho phép điều này. Tuy nhiên, nếu Ứng dụng máy chủ cho phép method=POST, nó cũng có thể cho phép body={someJson}ghi đè nội dung yêu cầu mặc định. Đó là thiết kế API thực sự tồi và cực kỳ rủi ro. Mặc dù nếu Ứng dụng máy chủ của bạn cho phép, http://...?method=POST&body={someJson}bạn thực sự nên suy nghĩ kỹ về những gì bạn đã làm ở đó, tại sao và nếu nó cần thiết. (Tôi muốn nói trong 99,9999% trường hợp là không cần thiết). Ngoài ra, các trình duyệt chỉ có thể gửi một vài kilobyte theo cách này.
Benjamin M

@BenjaminM lưu ý rằng Same Origin Policy chỉ ngăn mã javaScript truy cập vào kết quả, vì vậy trong khi yêu cầu bị "chặn", nó thực sự đến được máy chủ - jsbin.com/mewaxikuqo/edit?html,js,output Tôi chỉ thử nghiệm điều này trên firefox, nhưng bạn có thể mở các công cụ dành cho nhà phát triển và thấy rằng ngay cả khi bạn nhận được "Yêu cầu đa nguồn gốc bị chặn", máy chủ từ xa thực sự thấy toàn bộ yêu cầu. đó là lý do tại sao bạn phải có mã thông báo hoặc tiêu đề tùy chỉnh (và nếu có thể cả hai) cho tất cả các yêu cầu ĐĂNG của bạn
Yoni Jah

59

TL; DR

JWT, nếu được sử dụng mà không có Cookie, sẽ phủ nhận sự cần thiết phải có mã thông báo CSRF - NHƯNG! bằng cách lưu trữ JWT trong session / localStorage, bạn sẽ tiết lộ JWT và danh tính người dùng nếu trang web của bạn có lỗ hổng XSS (khá phổ biến). Tốt hơn là thêm một csrfTokenkhóa vào JWT và lưu trữ JWT trong một cookie với securehttp-onlythuộc tính được đặt.

Đọc bài viết này với mô tả tốt để biết thêm thông tin https://stormpath.com/blog/where-to-store-your-jwts-cookies-vs-html5-web-storage

Bạn có thể làm cho bảo vệ CSRF này không có trạng thái bằng cách bao gồm một yêu cầu JWT xsrfToken:

{ "iss": "http://galaxies.com", "exp": 1300819380, "scopes": ["explorer", "solar-harvester", "seller"], "sub": "tom@andromeda.com", "xsrfToken": "d9b9714c-7ac0-42e0-8696-2dae95dbc33e" }

Vì vậy, bạn sẽ cần lưu trữ csrfToken trong localStorage / sessionStorage cũng như trong chính JWT (được lưu trữ trong một cookie chỉ http và an toàn). Sau đó, để bảo vệ csrf, hãy xác minh rằng mã thông báo csrf trong JWT khớp với tiêu đề mã thông báo csrf đã gửi.


2
Có nên miễn sử dụng mã thông báo csrf trong quá trình xác thực api của người dùng không?
user805981

3
Cần chỉ ra (như những người khác cũng đã đề cập trong các nhận xét trên liên kết nguồn) rằng bất kỳ giảm thiểu CSRF nào sử dụng a) cookie, không phải chỉ http hoặc b) lưu trữ mã thông báo CSRF trong bộ nhớ cục bộ đều dễ bị XSS. Điều này có nghĩa là cách tiếp cận được trình bày có thể giúp giữ bí mật JWT khỏi kẻ tấn công bằng XSS, nhưng kẻ tấn công vẫn có thể thực hiện một yêu cầu độc hại trên API của bạn vì anh ta có thể cung cấp JWT hợp lệ (thông qua cookie, cảm ơn trình duyệt của bạn) và mã thông báo CSRF (đọc qua JS được đưa vào từ bộ nhớ cục bộ / cookie).
Johannes Rudolph

1
Trên thực tế, ngay cả mã thông báo CSRF cũng không thể bảo vệ bạn ở cấp XSS này, vì bạn đang giả định rằng kẻ tấn công có thể truy cập localStorage, cách duy nhất để truy cập hiện tại là có quyền truy cập cấp tập lệnh, họ vẫn có thể xem mã thông báo CSRF .
itnotvalid

1
Đó không phải là những gì @JohannesRudolph đang nói sao? Ngay khi bạn lưu trữ Mã thông báo CSRF trong Lưu trữ web / cookie không phải chỉ http, bạn đang gia tăng dấu vết của cuộc tấn công XSS vì chúng có thể truy cập được thông qua JS.
adam-beck,

1
Ở đây không phải là một chuyên gia tổng thể, nhưng nếu bạn vẫn tiếp xúc với XSS như lúc ban đầu, tôi không chắc phần Tốt hơn là nên thêm ... thực sự nắm giữ. Có thể kẻ tấn công sẽ phức tạp hơn một chút (?) Để nắm giữ mã thông báo CSRF, nhưng cuối cùng thì hắn vẫn có thể thực hiện yêu cầu thay mặt bạn, ngay cả khi thực sự không biết mã thông báo JWT. Đúng không? Cảm ơn
superjos
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.