Yêu cầu thg 3 23, 2022 7:55 SA 1069 6 2
  • 1069 6 2
+11

Lưu JWT vào localStorage hay Cookie khi authorize requests cho Serverless server?

Chia sẻ
  • 1069 6 2

Chào mọi người ạ. Em mới đến Viblo, có sai xót gì mọi người góp ý cho em ạ. Em cảm ơn ạ.

Em là sinh viên năm 3 của Đại học FPT (hết năm là em ra trường). Hồi em đi làm intern thì em phải giao tiếp với Strapi (serverless CMS) từ một React app (client-side). Strapi có gửi một cái access token là JWT về để lưu trên React app. Em có lên google tìm hiểu xem lưu thì phải lưu vào localStorage hay Cookie.

Dưới đây là tóm tắt của article gốc bằng tiếng Anh trên blog của em, mọi người có thể lên xem bản đầy đủ: localStorage vs. Cookie for token storage

Bản gốc có context hơn, nên mọi người cân nhắc đọc bản gốc ạ.

(Em muốn note là em không muốn dùng in-memory storage vì nó phải login lại khi chuyển trang.)

Thì hồi đó em thấy rất nhiều nguồn có bảo là dùng Cookie thì tốt hơn, và em muốn hiểu tại sao. Các nguồn em tìm thì có vẻ họ không lập luận chặt chẽ. Các ý kiến của họ thường là:

  • localStorage thì bị Cross-Site Scripting, còn Cookie thì không.
  • Cookie "an toàn hơn". Dùng httpOnly SameSite=Strict Secure Cookie là ok!

Theo em (hồi đó) tìm hiểu được, và giờ là em chắc chắn, thì dùng Cookie là sẽ bị một loại attack khác, là Cross-Site Request Forgery. Và ta không bao giờ có thể chống CSRF nếu ta đang bị hổng XSS. Nếu không muốn bị XSS khi dùng Cookie, bắt buộc phải dùng httpOnly. Nhưng không thể dùng được trong trường hợp Serverless, vì:

  • httpOnly không thể sử dụng khi ta muốn chống CSRF bằng phương pháp "Double Submit Cookie", được khuyên dùng bởi OWASP để chống CSRF cho Serverless servers. Ta phải cho CSRF token vào body của request để nó so sánh với CSRF token ở trong request header, nếu để httpOnly thì không lấy được. Tham khảo tại CSRF Prevention Cheet Sheet của OWASP.
  • SameSite=Strict thì nếu server ở domain khác thì sẽ không gửi cookie đi được. Và server của em ở domain khác. Không quan trọng lắm, vì httpOnly mà đã không sử dụng được thì tấn công XSS là lấy được.

Vậy, không thể dùng httpOnly nếu muốn chống CSRF bằng Double Submit Cookie. Thế là nếu không có httpOnly thì không thể chống XSS. Vậy là Cookie trong Serverless thì cũng bị hổng XSS.

Dùng localStorage thì phải chống XSS. Còn dùng Cookie thì phải chống XSS CSRF. Chưa kể công implement Double Submit Cookie.

Em muốn lấy ý kiến từ mọi người ạ. Em không phải cái gì cũng biết, nên em viết blog và xin nhận xét của mọi người để xem em còn sơ xót chỗ nào. Còn nhận góp ý là còn học ạ. Em cảm ơn mọi người.

2 CÂU TRẢ LỜI


Đã trả lời thg 3 23, 2022 8:30 SA
+5

@xuanan2001 đầu tiên cho mình xin 👍 respect với câu hỏi rất chi tiết của bạn, và bạn cũng đã bỏ thời gian ra để nghiên cứu mấy cái này, rất đáng học hỏi 👍

Về vấn đề JWT nên được lưu ở đâu, thì JWT nên được lưu ở trong cookie vì đây là session token giúp server xác định danh tính của người sử dụng, cần được bảo vệ một cách an toàn nhất, bạn cũng có thể đọc tại đây JWT authentication: Best practices and when to use it

Việc lưu session tại localStorage thì rất dễ bị XSS chôm mất như bạn đã khẳng định. Tuy nhiên với Double Submit Cookie thì bắt buộc phải có lỗ hổng XSS trước thì mới có thể khai thác được, CSRF token ở đây được sinh ra để chống lại lỗ hổng CSRF (ví dụ khi bạn duyệt web ở trang nọ mà tự nhiên thấy redirect về trang của mình và thấy profile của mình thay đổi chẳng hạn), bạn có thể đọc thêm tại https://viblo.asia/p/tan-cong-csrf-va-cac-van-de-xung-quanh-djeZ1PGjKWz

Khi bạn bị XSS, việc đưa session token vào httpOnly sẽ tránh được cho việc attacker có thể thu thập được session token và tấn công lại bằng kiểu replay attack, nên việc sử dụng session token đưa vào cookie với cờ httpOnly là cần thiết

Chia sẻ
Avatar Hoàng Xuân An @xuanan2001
thg 3 23, 2022 8:35 SA

@minhtuan.nguy Cảm ơn anh vì góp ý ạ!

Trong bài em có nhắc đến việc em đang sử dụng serverless server ấy ạ. Serverless server thì sẽ không có session nào cả, và các request sẽ được identify bằng token JWT. Khác với Stateful server, là các server có lưu lại session và bên client cần lưu lại session_id để giữ session (Nếu em hiểu không nhầm là vậy, vì em không rành Stateful server).

Khi em phải dùng Cookie để lưu JWT, thì em phải implement "Double Submit Cookie" để chống CSRF. Mà nếu implement cái này thì sẽ không thể sử dụng được httpOnly để chống XSS, vì không có cách nào lấy CSRF token từ một cookie httpOnly để cho vào JavaScript rồi cho vào HTTP Request Body được ạ. Nên sử dụng httpOnly trong trường hợp Serverless là không thể.

Mong anh góp ý thêm ạ.

Avatar Minh Tuấn Ngụy @minhtuan.nguy
thg 3 23, 2022 8:50 SA

@xuanan2001 Vẫn cần phải lưu trong cookie để bảo vệ JWT token. Theo như mô tả của bạn thì hình như bạn gửi JWT Token đi bằng Header Authorization hoặc bằng cái nào đấy tương tự, việc sử dụng JWT là server sẽ decode và xác thực chính xác JWT đó mà server đã ký bằng key từ server, mà với kiểu này thì không bị tấn công CSRF 😄

image.png

Avatar Hoàng Xuân An @xuanan2001
thg 3 23, 2022 9:00 SA

@minhtuan.nguy Dạ vâng ạ. Em gửi JWT bằng Header Authorization, mà muốn gửi như vậy thì phải để JWT có thể đọc được ở trong JavaScript để thêm vào request header chứ ạ? Đúng là kiểu này của em không thể bị CSRF được, vì nó không phải dùng Cookie. Em có thể để JWT ở trong localStorage để lấy ra cho vào Header Authorization, và chỉ cần chống XSS.

Anh bảo là phải cho JWT vào Cookie ấy ạ. Và anh bảo cũng phải để httpOnly. Việc này làm rồi thì không có cách nào cho JWT vào Header Authorization nữa. Việc gửi JWT đi là do Browser làm. Nhưng nếu anh làm như vậy thì chắc chắn sẽ phải chống CSRF, vì nó là Cookie. Mà đã chống CSRF theo kiểu của Serverless thì sẽ không thể để httpOnly được.

Không thể nào có cách nào để JWT trong Cookie mà có httpOnly được ấy ạ. Làm như thế không thể "Double Submit Cookie" được ạ. Anh có thể tham khảo Double Submit Cookie ở OWASP ạ: https://cheatsheetseries.owasp.org/cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.html#double-submit-cookie

thg 3 23, 2022 9:06 SA

@xuanan2001 JWT của bạn để trong cookie thì sẽ được browser tự động gửi lên server chứ không cần bạn lấy nó ra để thêm vào header nữa. Cái bạn cần lấy ra để thêm vào header là cái CSRF token cơ 😃.

Avatar Minh Tuấn Ngụy @minhtuan.nguy
thg 3 23, 2022 9:11 SA

@xuanan2001 Ùm nhỉ mình quên mất cái này 😂 sorry bạn rất nhiều

Vấn đề này thì để đảm bảo an toàn thì vẫn set JWT vào Cookie đặt cờ httpOnly nhưng mà server phải xác thực bằng Cookie chứ k bằng header Authorization nữa 😂, vì mấu chốt là chỉ có server là cần đọc cái giá trị JWT token để xác thực thôi 😄

Server sẽ tự set cookie tự đọc thôi, browser sẽ k cần quan tâm đến nó nữa.

Avatar Hoàng Xuân An @xuanan2001
thg 3 23, 2022 9:13 SA

@phuongth Anh đang sử dụng một phương pháp chống CSRF ạ. Và nếu sử dụng CSRF Prevention thì OWASP có dòng này để nói ạ:

Remember that any Cross-Site Scripting (XSS) can be used to defeat all CSRF mitigation techniques!

Vậy tại sao lại không sử dụng localStorage vì nó bị XSS, trong khi CSRF Prevention của anh có thể bị failed vì XSS ạ?

Avatar Hoàng Xuân An @xuanan2001
thg 3 23, 2022 9:18 SA

@minhtuan.nguy Nếu anh đặt httpOnly mà không sử dụng CSRF Prevention để chống CSRF thì sẽ bị lỗ hổng CSRF ạ. Mà trong serverless thì OWASP recommend cách "Double Submit Cookie". Mà cách này thì lưu CSRF Token, như anh @phuongth nói, ở đâu đó mà JavaScript có thể đọc được. Vậy là XSS vẫn có thể lấy CSRF Token ra.

thg 3 23, 2022 9:19 SA

@xuanan2001 mình trả lời bạn ở comment dưới nha 😃.

Avatar Minh Tuấn Ngụy @minhtuan.nguy
thg 3 23, 2022 9:24 SA

@xuanan2001 à đương nhiên là mình vẫn cần phải sử dụng 1 lớp bảo vệ chống CSRF nữa, tuy nhiên mình thấy lợi thế hơn là lưu và Cookie vì nó có nhiều tuỳ chọn hơn như set được hết hạn session, ... httpOnly thì chống được XSS đọc được session, CSRF token thì chặn được CSRF, thế nên bạn nên sử dụng cả 2 cái để được bảo vệ tốt nhất 😄

Avatar Hoàng Xuân An @xuanan2001
thg 3 23, 2022 9:27 SA

@minhtuan.nguy Khoan hãy nói lưu Token ở đâu ạ. Nếu web của anh bị XSS thì anh có implement CSRF Prevention xịn thế nào thì cũng không thể chống được, nếu OWASP nói đúng. "Chống XSS" của anh ở đây em hiểu là "Chống cho XSS không đọc được JWT" chứ không phải website của anh đã an toàn với XSS ạ. Lúc này token không quan trọng, nó phá UI inject vài cái malware ads là đủ chán rồi ạ.

Avatar Minh Tuấn Ngụy @minhtuan.nguy
thg 3 23, 2022 9:37 SA

@xuanan2001 đúng rồi, nó là chống cho XSS k đọc được JWT token để chống tấn công replay attack đó 😄 tức là mình phòng bị website của mình khi cuộc tấn công XSS xảy ra ý

Đã trả lời thg 3 23, 2022 9:01 SA
+1

Có chỗ này mình thấy chắc hơi có chút hiểu lầm đó là cái cookie mà bạn phải set httpOnly là authorization cookie (chứa JWT) của bạn chứ không phải là cái chứa CSRF token.

Mỗi cơ chế sẽ bảo vệ bạn khỏi một kiểu tấn công khác nhau nên bạn mới cần cả 2 cơ chế để bảo vệ khỏi XSS và CSRF. Để chống XSS thì cookie của bạn phải không thể được đọc bởi code JS, nên set httpOnly cho authorization cookie sẽ đảm bảo điều kiện này. CSRF attack thì nhắm đến việc cookie của bạn được browser tự động gửi theo request nên phải thêm yêu cầu đó là token phải được submit một cách thủ công (qua form field hoặc thêm vào header bằng JS). Tất nhiên là code JS của bạn phải đọc được CSRF token ở trong cookie thì mới submit nó lên được nên đây không phải là vấn đề bảo mật. Quan trọng là nó không thể đọc được từ một domain khác. Và tất nhiên CSRF token không có tác dụng bảo vệ bạn khỏi XSS nên không thể nói là vì nó không có tác dụng khi bị XSS nên bạn sẽ không dùng nó 😄.

Untitled.png

Để cho dễ hình dung thì đây là ví dụ cho kiểu implement này. Bạn có thể thấy viblo_auth sẽ chứa JWT để authenticate nên sẽ có http_only còn CSRF_TOKEN sẽ được đọc bởi JS và submit trong header hoặc form field nên không có http_only.

Về implement Double Submit Cookie thì thật ra cũng không tốn công gì lắm. Theo mình biết thì nhiều framework phổ biến (Laravel chẳng hạn) có set sẵn cookie CSRF_TOKEN với request type application/json cho bạn rồi. Một thư viện HTTP request phổ biến như axios cũng tự động đọc cookie CSRF_TOKEN và set header x-xsrf-token cho bạn luôn. Tùy framework mà bạn sử dụng thì có thể bạn chẳng cần làm gì luôn 😄.

Ngoài ra bạn có thể chỉ sử dụng request với content-type application/json (reject mọi content-type khác) và không set header Access-Control-Allow-Origin: *. Vì browser sẽ chặn tất cả cross-origin XHR request nên sẽ không có request nào từ domain khác tới được server của bạn, thế là không còn CSRF attack nữa😄.

Chia sẻ
Avatar Hoàng Xuân An @xuanan2001
thg 3 23, 2022 9:10 SA

@phuongth Em cảm ơn trả lời của anh ạ!

Theo em thấy thì cách anh nói là đang sử dụng một cái CSRF_TOKEN để làm một CSRF Prevention. Vậy cách của anh có miễn nhiễm với XSS không ạ?

Remember that any Cross-Site Scripting (XSS) can be used to defeat all CSRF mitigation techniques!

Nếu CSRF Prevention của anh không miễn nhiễm với XSS, thì tại sao lại có ác cảm với việc sử dụng localStorage sẽ bị XSS vậy ạ?

thg 3 23, 2022 9:18 SA

@xuanan2001 mình cũng giải thích ở trên rồi ấy, CSRF token không phải để bảo vệ bạn khỏi XSS nên nó có bị ảnh hưởng bới XSS hay không cũng không quan trọng 😄. Nó là để bảo vệ bạn khỏi request tới từ một domain khác vì script từ domain khác không thể truy cập cookie ở domain của bạn.

Nếu token được lưu trong localStorage thì sẽ không có cách nào để ngăn cản script chạy trên chính domain của bạn truy cập nó (XSS). httpOnly cookie là cái bảo vệ bạn khỏi XSS (script được chạy trên chính domain của bạn, có thể truy cập được cookie từ domain của bạn). Tuy nhiên vì cookie luôn được submit theo request nên bạn sẽ bị ảnh hưởng bởi CSRF attack.

Vậy nên bạn mới cần cả 2 cơ chế để bảo vệ. Mỗi cái sẽ bảo vệ bạn khỏi một kiểu tấn công.

Avatar Hoàng Xuân An @xuanan2001
thg 3 23, 2022 9:23 SA

@phuongth Lưu JWT trên Cookie httpOnly không có nghĩa là website của anh an toàn với XSS. XSS bây giờ không đọc được JWT của anh, nhưng có thể đọc được CSRF_TOKEN của anh. Em không rõ XSS lấy được CSRF_TOKEN thì tiếp theo sẽ làm gì, nhưng theo OWASP nói thì bị XSS thì chắc chắn sẽ bị hỏng CSRF Prevention.

Vấn đề của website của anh là website anh đang bị XSS, chứ không phải là token của anh đang lưu ở Cookie httpOnly hay ở đâu đó khác ạ.

thg 3 23, 2022 9:29 SA

@xuanan2001 Bạn cần phải nhớ là CSRF_TOKEN là để bảo vệ bạn khỏi request từ một domain khác. Nếu request tới từ chính domain của bạn (XSS) thì không có cuộc tấn công CSRF nào ở đây cả nên tất nhiên là CSRF_TOKEN không có tác dụng gì hết. Vậy nên người ta mới nói là với tấn công XSS thì CSRF token chắc chắn không có tác dụng gì cả. Vì mọi người hay hiểu lầm là CSRF_TOKEN là một phần lí do bạn dùng cookie để lưu JWT token. Sự thật là ngược lại, vì bạn lưu JWT token ở cookie nên bạn mới phải thêm CSRF_TOKEN để bảo vệ bạn khỏi một kiểu tấn công khác.

Avatar Hoàng Xuân An @xuanan2001
thg 3 23, 2022 9:33 SA

@phuongth Vâng ạ. Thì cứ coi như là em dùng Cookie như anh nói đi ạ, implement đầy đủ. Nhưng web của anh bị XSS thì người ta đâu thiếu gì cách phá web anh ạ? XSS là JavaScript, là Game Over đối với web anh rồi ạ. Có thể thêm ads, xoá nội dung, inject link, làm nhiều thứ khác nữa ạ. Vậy anh đang lưu JWT trong cookie thì anh chỉ cho XSS không truy cập JWT thôi, thế anh không fix XSS ạ? Nếu anh fix XSS rồi thì cần gì quan trọng localStorage bị hổng XSS nữa ạ? Hơn nữa, theo trong bài blog của em, em argue là với phương thức làm web modern như bây giờ thì rất khó để bị XSS.

thg 3 23, 2022 9:38 SA

@xuanan2001 Việc bạn để JWT trong cookie là để bảo vệ nó khỏi XSS chứ không phải để bảo vệ toàn bộ trang web của bạn khỏi XSS. Từng cái div, form, input, button của bạn thì có liên quan gì đến cookie đâu, bạn vẫn phải dùng các phương pháp khác để bảo vệ nó chứ. Trên trang web và server của bạn có vô số chỗ để người tấn công có thể inject script vào đấy và với mỗi chỗ thì bạn đều phải có cơ chế bảo vệ khác nhau. Chứ không lẽ giờ chỉ vì SQL injection tồn tại và việc set username/password cho DB không giúp bạn tránh khỏi nó thì bạn không cần bảo vệ DB của bạn luôn 😐️

Avatar Hoàng Xuân An @xuanan2001
thg 3 23, 2022 9:45 SA

@phuongth Dạ vâng, em hiểu rồi ạ. Nghĩa là dùng Cookie là để tránh trường hợp bị XSS thì bị dùng luôn JWT để làm việc bất chính đúng không ạ?

Nhưng khi dùng framework như React, nếu em làm mọi thứ đúng, sanitize đầy đủ, thì khá khó để bị XSS ạ. Không nói là nó dễ, nhưng nếu nó dễ đến như vậy thì web bây giờ không an toàn đến như thế ạ. Đương nhiên là web bây giờ không tệ đến mức XSS nhan nhản chứ ạ?

https://stackoverflow.com/questions/33644499/what-does-it-mean-when-they-say-react-is-xss-protected

Avatar Hoàng Xuân An @xuanan2001
thg 3 23, 2022 9:55 SA

@phuongth

Việc bạn để JWT trong cookie là để bảo vệ nó khỏi XSS chứ không phải để bảo vệ toàn bộ trang web của bạn khỏi XSS.

Nói vậy cũng không đúng lắm ạ. Bị XSS rồi thì đã gọi là Game Over rồi thì họ có tất cả chứ ạ. CSRF Prevention của anh cũng không hoạt động rùi. Có XSS vẫn có khả năng bị make request bất chính chứ ạ?

Chứ không lẽ giờ chỉ vì SQL injection tồn tại và việc set username/password cho DB không giúp bạn tránh khỏi nó thì bạn không cần bảo vệ DB của bạn luôn

Em chưa liên kết được ví dụ của anh lắm. Nhưng bị XSS thì là Game Over, nghĩa là họ làm gì cũng được, CSRF Prevention cũng chịu (according to OWASP), vậy có đúng không ạ? Vậy em chỉ cần chống XSS tốt thôi là ok chứ ạ? Vậy em có quyền dùng localStorage không ạ?

Avatar Minh Tuấn Ngụy @minhtuan.nguy
thg 3 23, 2022 9:55 SA

@xuanan2001 Khá khó chứ k phải là k có bạn ạ 😂 ví dụ như postMessage cũng bị dính XSS như thường https://hackerone.com/reports/894518

Việc code ẩu, hay chính trong framework cũng có bug 0-day cũng có thể tồn tại XSS, vậy nên chính mình nên bảo vệ mình trước, đừng dựa dẫm quá 😄

Avatar Hoàng Xuân An @xuanan2001
thg 3 23, 2022 9:57 SA

@minhtuan.nguy Vâng, không phải là không có ạ. Nhưng nếu theo anh nói, dính XSS, thì anh có CSRF Prevention đến đâu thì cũng thất bại ạ. Nghĩa là anh đang bảo Chắc chắn sẽ bị dính XSS. Em cũng tiếp lời là Bị XSS thì chắc chắn CSRF Prevention là không được. Vậy có đúng không ạ?

Bị XSS thì lưu JWT trong localStorage hay Cookie thì cũng như nhau, vẫn compromised như bình thường.

Avatar Minh Tuấn Ngụy @minhtuan.nguy
thg 3 23, 2022 10:02 SA

@xuanan2001 khác chứ bạn, việc lưu trong localStorage khi bị dính XSS thì attacker hoàn toàn có thể lấy được JWT Token và replay attack (tức là có thể login với cái quyền bạn đang có ở cái website đó luôn, giúp attacker có thể khám phá ra nhiều chức năng khác => dẫn đến nhiều lỗi khác nữa). Còn việc lưu ở Cookie sẽ chặn attacker có thể lấy được JWT token, lúc này attacker chỉ có thể dùng JS để truy cập các tính năng khác, tuy nhiên user tắt tab browser đi là attacker khỏi làm gì nữa luôn. Đấy chính là phòng thủ.

Avatar Hoàng Xuân An @xuanan2001
thg 3 23, 2022 10:04 SA

@minhtuan.nguy Bị XSS -> CSRF Prevention thất bại -> Attacker chuyển sang tấn công CSRF -> User bị tấn công CSRF.

Cái này có đúng không ạ? Ẩn ý trong việc Attacker có thể tấn công CSRF là Attacker đã có được JWT Token rồi đó ạ. (Hoặc có thể sử dụng JWT Token từ Cookie tuỳ ý)

Avatar Minh Tuấn Ngụy @minhtuan.nguy
thg 3 23, 2022 10:09 SA

@xuanan2001

User bị tấn công CSRF

Đúng, tuy nhiên như mình đã nói ở trên, attacker tấn công CSRF không phải attacker có được JWT Token, mà lợi dụng JS để thực thi giúp một vài tính năng, tuy nhiên để sử dụng những tính năng đó attacker cần đọc code html, js để xem những tính năng đó sử dụng như thế nào, ra làm sao, việc này rất tốn thời gian.

Với open source thì có khả năng viết payload nhanh hơn, tuy nhiên với 1 trang private source thì cần phải recon endpoint rất nhiều để có thể tấn công tiếp.

Nếu bạn để ở localStorage và attacker lấy được JWT Token, attacker chỉ việc paste cái JWT Token đó vào browser của attacker và sử dụng tài khoản của bạn tuỳ ý, lúc đó thì attacker k cần đọc code JS hay html và code lại payload XSS làm gì nữa cho mệt người 😄 (và bạn không thể chặn được attacker đang tấn công bằng 1 cú click chuột nữa đâu)

Avatar Hoàng Xuân An @xuanan2001
thg 3 23, 2022 10:12 SA

@minhtuan.nguy Cũng như trong blog em nói đó ạ. Tốn thời gian không phải là không thể. Và vấn đề của web anh là chống XSS chứ không phải chống lấy JWT.

attacker tấn công CSRF không phải attacker có được JWT Token, mà lợi dụng JS để thực thi giúp một vài tính năng

Không đúng. Attacker hoàn toàn có thể make request y hệt như cách mà Attacker tấn công khi biết JWT. Cứ craft một HTTP POST request, và gửi lên server. Attacker không cần biết JWT, browser gửi cho attacker. HTTP POST request đó vẫn được duyệt.

Avatar Minh Tuấn Ngụy @minhtuan.nguy
thg 3 23, 2022 10:14 SA

@xuanan2001 Đúng rồi, nhưng mà việc đấy là do browser của người bị tấn công request, nhưng mà nó k xịn bằng việc bạn có JWT token của người bị tấn công, đúng không? Và cái việc make request đó tốn thời gian và không chắc nó đã chạy được với các endpoint mà bạn không biết

Avatar Hoàng Xuân An @xuanan2001
thg 3 23, 2022 10:14 SA

@minhtuan.nguy Argument này của anh có thể áp dụng tương tự với việc JWT ở localStorage bị compromise ạ. Có JWT thì anh cũng chưa chắc make được cái request ạ.

Avatar Minh Tuấn Ngụy @minhtuan.nguy
thg 3 23, 2022 10:17 SA

@xuanan2001 nó giống cái việc 1 tên trộm có chìa khoá vào nhà của bạn, tên trộm đó muốn làm gì trong nhà của bạn cũng được, nhưng mà việc tên trộm không vào được nhà của bạn và sai 1 em bé được vào nhà của bạn và hành động giống những gì tên trộm đó sai bảo sẽ khó khăn hơn. Cái này chắc để bạn đánh giá thôi 😄

thg 3 23, 2022 10:18 SA

@xuanan2001 Vì bạn hỏi tại sao lại phải bảo vệ JWT trong khi có một vấn đề to hơn là XSS nên mình lấy một ví dụ tương tự thôi. Cả 2 lỗi XSS/SQL injection đều là game over, để lộ JWT/DB authentication cũng là game over, thế đâu có nghĩa là bạn chỉ cần bảo vệ một cái vì đằng nào cũng là game over. Tất nhiên là nếu bạn có những cơ chế khác để bảo vệ JWT và không cần không quan tâm đến việc người ta có thể lấy trộm JWT và đem đi request thoải mái sau này kể cả khi bạn đã fix song XSS thì bạn không cần quan tâm đến việc bảo vệ nó khỏi XSS. Ví dụ như token của bạn có timeout là 30 phút thôi chẳng hạn. Vấn đề vẫn là bạn phải bảo vệ được JWT của bạn, chứ không phải là bỏ qua không cần quan tâm vì đằng nào cũng bị XSS.

Các framework hiện đại thì có rất nhiều cơ chế để giúp bạn bảo mật, nhưng cũng không có nghĩa là không bao giờ có. Chỉ riêng với lỗi XSS bạn có thể xem Vue đã bị dính tới 3 lần ở bản 2.x https://snyk.io/vuln/npm:vue. Nếu bạn xem trên npm thì những phiên bản này vẫn có vài chục nghìn lượt tải mỗi tuần, vậy bạn có thể tự suy ra xem các trang web bị XSS liệu có nhan nhản hay không. Và kể cả khi các thư viện mà bạn trực tiếp sử dụng không có lỗi gì thì những vụ tấn công supply chain vẫn nhan nhản ra đấy với vài tháng lại một vụ hoặc đôi khi là vài vụ một tháng. Thế nên tự bảo vệ mình khỏi những tai họa có thể xảy ra trong tương lai chẳng bao giờ là thừa cả.

Avatar Hoàng Xuân An @xuanan2001
thg 3 23, 2022 10:18 SA

@minhtuan.nguy Vâng, khó khăn không phải là không làm được ạ. Vấn đề trong ví dụ của anh là tên trộm lại có thể bảo em bé làm những việc tên trộm muốn.

Avatar Minh Tuấn Ngụy @minhtuan.nguy
thg 3 23, 2022 10:21 SA

@xuanan2001 nhưng mà tên trộm k biết nhà bạn có cái gì, đi như thế nào, phải chờ em bé quay ra nói mới biết, nó mất thời gian, và khi em bé đấy k có quyền vào nhà bạn nữa thì bạn bó tay đúng k

Avatar Hoàng Xuân An @xuanan2001
thg 3 23, 2022 10:24 SA

@phuongth Lại quay lại với ví dụ JWT ạ. localStorage thì bị XSS, còn Cookie thì bị XSS + CSRF. Và anh có chống CSRF thế nào đi nữa mà bị XSS thì anh cũng failed. Anh failed rồi thì còn gì để nói đâu ạ? "Khó hơn để hack" không phải là cách để giải quyết vấn đề ạ. Nếu anh là Facebook hay Google gì đó thì không bao giờ là "Khó hơn" cả ạ. Cách của anh làm thì vẫn có attacker attack được thôi ạ.

Avatar Hoàng Xuân An @xuanan2001
thg 3 23, 2022 10:24 SA

@minhtuan.nguy Analogy này không hợp lệ ạ. Trong trường hợp anh hack được JWT từ localStorage, anh có biết được endpoint em đang sử dụng có những gì không ạ?

Avatar Minh Tuấn Ngụy @minhtuan.nguy
thg 3 23, 2022 10:27 SA

@xuanan2001 NHƯ MÌNH ĐÃ NÓI Ở BÊN TRÊN

Sử dụng replay attack và truyền JWT token đã lấy được vào localStorage, load lại trang thì đã vào được acc của victim rồi 😐

thg 3 23, 2022 10:29 SA

@xuanan2001 Để mình sửa lại nhé. Lưu vào localStorage thì có thể bị lấy cắp bởi XSS, còn lưu vào cookie thì không bị lấy cắp bởi XSS nhưng có thể bị CSRF, và CSRF có thể tránh được với CSRF token. Vấn đề không phải là làm nó khó hơn để hack mà nó là một lỗi hoàn toàn khác. Khi hacker có được JWT mà bạn không có cơ chế bảo vệ nào khác (timeout như mình đã nói ở trên chẳng hạn) thì kể cả bạn có fix xong XSS thì hacker vẫn có thể dùng JWT để thực hiện request như thường. 2 lỗi khác nhau hoàn toàn, script injection authentication chứ không phải là một. Vậy nên mình mới đưa ra cho bạn ví dụ về SQL injection và để lộ authentication của DB đó.

Avatar Hoàng Xuân An @xuanan2001
thg 3 23, 2022 10:29 SA

@minhtuan.nguy Em có thể dành 1 năm để nghiên cứu xem các endpoint của Facebook có thể làm là gì. Sau đó viết script.

Anh login vào account của user thì làm gì ạ? Anh bấm nút thì có phải là gọi endpoint giống y hệt acc của em không ạ?

Em đang dùng client-side app. XSS là thấy hết endpoint ạ.

Avatar Minh Tuấn Ngụy @minhtuan.nguy
thg 3 23, 2022 10:31 SA

@xuanan2001 ừ đấy là bạn có 1 năm, mình k có thời gian làm việc đó 😂

Anh login vào account của user thì làm gì ạ? Anh bấm nút thì có phải là gọi endpoint giống y hệt acc của em không ạ?

Bạn chưa nghĩ đến việc mình chôm được acc của admin hay sao, đương nhiên có những endpoint mà bạn không biết rồi

Nó là một cách phòng thủ để làm khó attacker, còn nếu bạn muốn thì bạn có thể sử dụng, không thì thôi, không ai ép bạn phải sử dụng làm gì cả 😄

Avatar Hoàng Xuân An @xuanan2001
thg 3 23, 2022 10:32 SA

@phuongth

Để mình sửa lại nhé. Lưu vào localStorage thì bị XSS, còn lưu vào cookie thì không bị XSS nhưng có thể bị CSRF, và CSRF có thể tránh được với CSRF token.

Câu này chưa đủ và chưa đúng ạ. Lưu vào Cookie thì web anh vẫn bị XSS như bình thường, chỉ là không thấy JWT đâu cả. Mà đã XSS rồi thì không thể tránh được với CSRF token.

Avatar Hoàng Xuân An @xuanan2001
thg 3 23, 2022 10:35 SA

@minhtuan.nguy App em là app Client-side chứ không phải là check role Admin rồi gửi trang web về cho React hiện ạ.

Hack ngân hàng hay Google account thì 2 năm hay 3 năm cũng không lâu đâu ạ.

Anh có thể argue là em nên làm như kiểu có role admin thì gửi web về có các endpoint. Em nghĩ architecture này hơi lạ với em ạ.

Em hack CSRF, em có thể dùng JWT mà không cần biết JWT. Giờ em HTTP GET để crawl các kiểu. Tính đến đây đã ạ, vì anh biết web anh đang bị rất nhiều vấn đề khi bị exploit đến đây chưa ạ?

Avatar Minh Tuấn Ngụy @minhtuan.nguy
thg 3 23, 2022 10:37 SA

@xuanan2001 ùm nhưng với việc victim k tắt browser đi, còn nếu victim tắt browser đi thì sao bạn, bạn làm gì còn gì nữa đâu mà khóc với sầu 😂

Avatar Hoàng Xuân An @xuanan2001
thg 3 23, 2022 10:37 SA

@minhtuan.nguy Còn việc em cân nhắc nên dùng hay không thì em cũng đang xem xét ạ. Em thấy chưa đủ thuyết phục, vì Cookie thì vẫn bị attack thôi.

thg 3 23, 2022 10:37 SA

@xuanan2001 Mình nói rõ hơn chút nhé. Lưu vào localStorage thì có thể bị lấy cắp bởi XSS, còn lưu vào cookie thì không thể bị lấy cắp bởi XSS. Và đây là một lỗi hoàn toàn khác chứ không phải là cùng một lỗi với XSS. JWT token bạn dùng để authenticate tương đương với username/password của user. Khi bị XSS mà bạn không để lộ JWT thì bạn fix XSS là xong. Nhưng nếu bạn bị lộ JWT mà không có cơ chế bảo vệ nào khác thì hacker đã có trong tay toàn bộ thông tin login của user.

Mình nói rõ thêm lần nữa là CSRF không liên quan gì đến XSS cả, nó dùng để bảo vệ bạn khỏi một kiểu tấn công khác. Khi bạn bị XSS thì CSRF không có vai trò gì ở đây hết.

Avatar Minh Tuấn Ngụy @minhtuan.nguy
thg 3 23, 2022 10:38 SA

@xuanan2001 Như mình đã nói ở trên

Nó là một cách phòng thủ để làm khó attacker, còn nếu bạn muốn thì bạn có thể sử dụng, không thì thôi, không ai ép bạn phải sử dụng làm gì cả

Có 2 lớp phòng thủ nó vẫn xịn hơn là 1, mình nghĩ thế.

Avatar Hoàng Xuân An @xuanan2001
thg 3 23, 2022 10:39 SA

@phuongth

Mình nói rõ thêm lần nữa là CSRF không liên quan gì đến XSS cả, nó dùng để bảo vệ bạn khỏi một kiểu tấn công khác. Khi bạn bị XSS thì CSRF không có vai trò gì ở đây hết.

Anh đã đọc cái em gửi chưa ạ?

Remember that any Cross-Site Scripting (XSS) can be used to defeat all CSRF mitigation techniques!

Em không cần biết JWT của user. Browser nó tự gửi cho em, vì em đang CSRF ạ.

Avatar Hoàng Xuân An @xuanan2001
thg 3 23, 2022 10:43 SA

@minhtuan.nguy

Có 2 lớp phòng thủ nó vẫn xịn hơn là 1, mình nghĩ thế.

Vâng. Argument này thì em có thể hiểu được. Em vẫn giữ quan điểm là cái gốc rễ vẫn ở XSS. Em có thể lưu JWT vào localStorage và sống khá bình thường, vì em biết em mà có bị attack XSS thì các site khác dùng Cookie cũng bị XSS như em thôi (và sẽ có ngày bị exploit CSRF), nếu cả hai team làm ra 2 web đều biết mình đang làm gì.

Em nghĩ so với việc implement Cookie thì em sẽ chọn localStorage và stay up to date với các lỗ hổng XSS hơn là dùng Cookie, nó thêm một tầng phức tạp, em không thích.

thg 3 23, 2022 10:47 SA

@xuanan2001 Bạn có hiểu CSRF là gì chưa ạ. Nó là một kiểu tấn công hoàn toàn không cần inject bất cứ một script nào vào trang web của bạn, và nó được thực hiện từ một domain khác. Khi bạn bị XSS thì bạn bị tấn công từ chính domain của bạn nên nó không phải là cuộc tấn công CSRF. Tất nhiên CSRF chẳng bảo vệ bạn khỏi cái gì khi bạn bị XSS cả.

Remember that any Cross-Site Scripting (XSS) can be used to defeat all CSRF mitigation techniques!

Đây chính là cái reminder to tướng mà mình nhắc đi nhắc lại với bạn từ nãy đấy. Khi bạn bị XSS thì CSRF chẳng giúp gì cho bạn cả. Vì nó là để bảo vệ bạn khỏi kiểu tấn công khác.

Bạn đọc đoạn mình giải thích về việc tại sao lại phải bảo vệ JWT của bạn chưa

Mình nói rõ hơn chút nhé. Lưu vào localStorage thì có thể bị lấy cắp bởi XSS, còn lưu vào cookie thì không thể bị lấy cắp bởi XSS. Và đây là một lỗi hoàn toàn khác chứ không phải là cùng một lỗi với XSS. JWT token bạn dùng để authenticate tương đương với username/password của user. Khi bị XSS mà bạn không để lộ JWT thì bạn fix XSS là xong. Nhưng nếu bạn bị lộ JWT mà không có cơ chế bảo vệ nào khác thì hacker đã có trong tay toàn bộ thông tin login của user.

Bởi vì nó là một lỗi hoàn toàn khác. Bạn đã để mất toàn bộ thông tin login của user. Kể cả bạn có fix xong XSS thì lỗi này vẫn còn ở đó và nó không liên quan gì đến nhau. XSS chỉ là một phương pháp để hacker khai thác lỗ hổng này thôi.

Avatar Hoàng Xuân An @xuanan2001
thg 3 23, 2022 10:54 SA

@phuongth Đầu tiên em trả lời argument của anh về việc này trước:

JWT token bạn dùng để authenticate tương đương với username/password của user. Khi bị XSS mà bạn không để lộ JWT thì bạn fix XSS là xong. Nhưng nếu bạn bị lộ JWT mà không có cơ chế bảo vệ nào khác thì hacker đã có trong tay toàn bộ thông tin login của user.

  • Em có thể blacklist JWT nếu JWT của user bị compromised.
  • Em không có JWT không có nghĩa là em không sử dụng JWT của user được. Bằng XSS, em có thể make request và gửi đi, và browser sẽ attach Cookie cho em, đó chính là username/password của người dùng. Anh có giấu JWT vào cookie, thì em cũng dùng được thôi ạ. httpOnly cũng không cản được, SameSite cũng không cản được.

Bạn có hiểu CSRF là gì chưa ạ. Nó là một kiểu tấn công hoàn toàn không cần inject bất cứ một script nào vào trang web của bạn, và nó được thực hiện từ một domain khác. Khi bạn bị XSS thì bạn bị tấn công từ chính domain của bạn nên nó không phải là cuộc tấn công CSRF. Tất nhiên CSRF chẳng bảo vệ bạn khỏi cái gì khi bạn bị XSS cả.

Mong anh biết là em đã đọc cái này rất nhiều và không cần anh nhắc lại định nghĩa ạ.

Khi em bị tấn công XSS, em có thể phá tất cả các loại CSRF Prevention của anh. Sau đó, em thực hiện tấn công CSRF. Nghĩa là từ XSS, em chuyển sang tấn công CSRF.

Đây chính là cái reminder to tướng mà mình nhắc đi nhắc lại với bạn từ nãy đấy. Khi bạn bị XSS thì CSRF chẳng giúp gì cho bạn cả. Vì nó là để bảo vệ bạn khỏi kiểu tấn công khác.

Vâng. Mong anh sử dụng CSRFCSRF Prevention để đỡ hiểu nhầm. CSRF Prevention của anh bảo vệ anh khỏi CSRF. Nhưng nếu em tấn công XSS anh, em có thể vô hiệu hoá các CSRF Preventions của anh, và tấn công CSRF. Như vậy có rõ ràng không ạ?

Avatar Hoàng Xuân An @xuanan2001
thg 3 23, 2022 10:59 SA

Để làm rõ hơn việc chuyển từ tấn công XSS sang tấn công CSRF, em có thể ví dụ thế này:

Em lấy CSRF Token của anh trong localStorage về (Cookie mà không httpOnly thì cũng lấy được). Sau đó, XSS của em thực hiện một malicious HTTP POST có kèm CSRF Token này (Bởi vì nếu không có CSRF Token thì sẽ không make request được). Ở đây em không cần từ một domain khác, em vẫn có thể make request được. CSRF là chống khi em gửi request ở domain khác (social engineeering) thì cookie sẽ gửi kèm, nên nó gọi là "Cross-Site". Em đang thực hiện request "Cùng site" từ XSS, nhưng em vẫn cần CSRF Token để thực hiện request.

thg 3 23, 2022 11:38 SA

@xuanan2001 Khi bạn XSS được rồi mà bạn còn phải cho user đi sang trang khác để CSRF nữa sao 🤣. Quan trọng là bạn tập trung vào điểm này nè. JWT của bạn không bị lấy cắp khi bị XSS nếu bạn để trong httpOnly cookie. Kể cả khi bạn tấn công CSRF sau khi đã XSS thì vẫn không lấy nó ra được. Nếu hacker lấy được JWT thì nó lại là một lỗi hoàn toàn khác. Và nó có thể được sử dụng cho các cuộc tấn công sau. Khi XSS thì bạn đã game over rồi. Nhưng nếu để lộ token thì game sau bạn cũng game over luôn.

Em có thể blacklist JWT nếu JWT của user bị compromised.

Đây chính là mất bò mới lo làm chuồng bạn ạ. Như mình đã nói bạn có thể có các phương pháp khác để bảo vệ JWT như set expire time ngắn, hoặc khi nào biết bị mất thì mới revoke như bạn chẳng hạn. Ở trường hợp này thì bạn mới có thể xem nó là 2 lớp bảo mật cho cùng một lỗ hổng. Nhưng nếu lớp kia bạn không kiểm soát được thì sao. Nếu token bạn sử dụng không nằm trong tầm kiểm soát của bạn mà do bên thứ ba cung cấp thì sao. Nếu API bạn sử dụng không cho phép revoke mà chỉ check expire time của JWT mà trước đó để code cho tiện bạn đã lỡ set expire time lên đến 1 năm thì sao. Vậy nên mới đẻ ra cái lớp bảo vệ mà bạn có thể hoàn toàn kiểm soát được kia, nên nó mới được recommend. Tất nhiên như mình đã nói, nếu bạn chắc chắn với 1 lớp bảo vệ kia rồi thì bạn có thể không cần quan tâm nữa, tùy theo security measure của bạn thôi. Quan trọng là bạn phải biết về nguy cơ để lộ JWT và việc bị XSS là hai thứ hoàn toàn khác nhau. Để lộ JWT nếu bạn không bảo vệ nó là một hậu quả của việc bạn bị XSS và bạn phải xử lý hậu quả đó.

Avatar Hoàng Xuân An @xuanan2001
thg 3 23, 2022 11:51 SA

@phuongth Scenario trên không cần chuyển trang khác anh ạ. Em bảo "lấy về" là "lấy về script" ạ. Em xin lỗi vì làm anh hiểu nhầm. Và em không cần lấy nó ra ạ. Mong anh đọc lại câu trả lời của em.

Em có thể blacklist JWT nếu JWT của user bị compromised.

Em đồng ý cách của em không tốt. Em có thể expire các thứ như anh nói, ok ạ.

Avatar Hoàng Xuân An @xuanan2001
thg 3 23, 2022 11:55 SA

@phuongth Anh đã đọc scenario của em chưa ạ? Anh có thể phân tích theo cái scenario trên đó ạ. Em nghĩ đến đây thì nó cũng lòng vòng và hơi dài rồi ạ.

Để làm rõ hơn việc chuyển từ tấn công XSS sang tấn công CSRF, em có thể ví dụ thế này:

Em lấy CSRF Token của anh trong localStorage về (Cookie mà không httpOnly thì cũng lấy được). Sau đó, XSS của em thực hiện một malicious HTTP POST có kèm CSRF Token này (Bởi vì nếu không có CSRF Token thì sẽ không make request được). Ở đây em không cần từ một domain khác, em vẫn có thể make request được. CSRF là chống khi em gửi request ở domain khác (social engineeering) thì cookie sẽ gửi kèm, nên nó gọi là "Cross-Site". Em đang thực hiện request "Cùng site" từ XSS, nhưng em vẫn cần CSRF Token để thực hiện request.

Avatar Hoàng Xuân An @xuanan2001
thg 3 23, 2022 12:00 CH

@phuongth Đây là thứ em muốn nói ạ: https://portswigger.net/web-security/cross-site-scripting/exploiting/lab-perform-csrf

Nếu anh rảnh có thể xem qua và phân tích cách làm này ạ. Em thấy khá giống thứ em muốn nói.

thg 3 23, 2022 12:03 CH

@xuanan2001 Mình túm lại nhé 😂

  • Việc bạn để JWT vào cookie chính xác là để hacker không lấy được nó ra. Nó là để bảo vệ bạn khi cuộc tấn công XSS đã xảy ra rồi, không phải là để bảo vệ bạn khỏi cuộc tấn công XSS. Khi bạn bị XSS thì tất nhiên hacker sẽ sử dụng được cookie của bạn rồi, nó là mục đích của XSS mà.
  • CSRF không liên quan gì đến việc này, nó là để bảo vệ khi bạn bị CSRF attack, nếu bạn cảm thấy bạn không bị CSRF attack hoặc không quan tâm đến việc bị CSRF attack thì bạn bỏ qua nó cũng không ảnh hưởng gì đến mục đích của việc lưu JWT trong cookie.
  • Việc bạn bị mất JWT lại là một lỗ hổng khác và nó có thể được khai thác bởi XSS chứ không phải chỉ là side-effect như bạn nghĩ. Như mình nói thì bạn có thể có những lớp bảo mật khác cho JWT và lưu nó trong httpOnly cookie là một trong số những lớp bảo mật đấy. Tùy security measure của bạn mà bạn lựa chọn những lớp bảo mật nào. Mình cũng ví dụ trường hợp nào bạn cần lớp bảo mật này rồi.
thg 3 23, 2022 12:11 CH

@xuanan2001 mình hiểu scenario của bạn. Nhưng bản chất nó là cuộc tấn công XSS thôi. Csrf bảo vệ được bạn vì form request từ domain khác không thể lấy csrf token từ cookie ra và submit lên được. Khi nó chạy từ chính domain của bạn thì nó không gọi là csrf attack vì script hoàn toàn truy cập được csrf token trong cookie. Việc lấy nó ra và gửi lên chỉ là một bước yêu cầu thôi. Từ cái tên thì bạn cũng thấy đây không phải là csrf attack rồi vì nó đến từ chính domain của bạn.

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí