Làm thế nào dễ dàng để hack JavaScript (trong một trình duyệt)?


37

Câu hỏi của tôi phải làm với bảo mật JavaScript.

Hãy tưởng tượng một hệ thống xác thực trong đó bạn đang sử dụng khung JavaScript như Backbone hoặc AngularJS và bạn cần các điểm cuối an toàn. Đó không phải là vấn đề, vì máy chủ luôn có từ cuối cùng và sẽ kiểm tra xem bạn có được phép làm những gì bạn muốn không.

Nhưng nếu bạn cần một chút bảo mật mà không liên quan đến máy chủ thì sao? Điều đó có thể không?

Ví dụ: giả sử bạn có hệ thống định tuyến phía máy khách và bạn muốn một tuyến đường cụ thể được bảo vệ cho người dùng đăng nhập. Vì vậy, bạn ping máy chủ hỏi xem bạn có được phép truy cập các tuyến được bảo vệ không và bạn tiếp tục. Vấn đề là khi bạn ping máy chủ, bạn lưu trữ phản hồi trong một biến, vì vậy lần sau khi bạn đi đến một tuyến riêng, nó sẽ kiểm tra xem bạn đã đăng nhập chưa (không ping đến máy chủ) và tùy thuộc vào về phản ứng nó sẽ đi hay không.

Làm thế nào dễ dàng cho người dùng để sửa đổi biến đó và có được quyền truy cập?

Kiến thức bảo mật (và JavaScript) của tôi không tốt. Nhưng nếu một biến không nằm trong phạm vi toàn cầu và nằm trong phần riêng của mẫu mô-đun chỉ có getters chứ không có setters, ngay cả trong trường hợp đó, bạn có thể hack thứ đó không?


29
Tất cả những câu trả lời dài. Nói tóm lại, để trả lời bạn tiêu đề, "rất hack". Để trả lời 2 câu hỏi đầu tiên của bạn với nhau, "không có máy chủ, bạn sẽ mất bảo mật" && "Không". Để trả lời câu 3, "Rất dễ" và cuối cùng, "Có, dễ dàng". Có bạn đi. Tất cả các câu hỏi đã được trả lời. : P
SpYk3HH

Ví dụ chính, hãy xem bài đăng trên blog của tôi về việc thêm jQuery vào bất kỳ trang web nào. spyk3lc.blogspot.com/2013/05/ Bây giờ, padawan trẻ, đi ra ngoài và thử nó. Hãy xem việc thêm jQuery vào bất kỳ trang web nào chưa có nó dễ dàng như thế nào, sau đó sử dụng jquery để dễ dàng thao tác bất kỳ phần nào của tầm nhìn mà không cần dòng javascript dài. Bùng nổ!
SpYk3HH

7
Một lần, khi đăng ký một tên miền, số điện thoại là một trường bắt buộc, nhưng điều đó chỉ được thi hành trong javascript - không phải phía máy chủ. Vì vậy, tôi đã vô hiệu hóa nó bằng cách xác định lại một chức năng (sử dụng Fireorms) và voilà! Họ không có số điện thoại của tôi.
Izkata

8
manipulate any part of the sight without long lines trang web và tầm nhìn
mplungjan

8
Lập trình viên web chuyên nghiệp cần phải có được điều đó ngay. Xin vui lòng. Thật đáng xấu hổ hơn một thứ ngữ pháp nazi :) plus.google.com/u/0/+MonaNomura/posts/h9ywDhfEYxT
mplungjan

Câu trả lời:


26

Vui lòng đọc câu trả lời của Joachim trước khi đọc bài này. Ông bao gồm các lý do chung đằng sau lỗ hổng phía khách hàng. Bây giờ, cho một gợi ý về cách bạn có thể khắc phục vấn đề này ...

Một lược đồ an toàn cho giao tiếp máy khách-máy chủ mà không phải xác thực với máy chủ theo cách thủ công trên mỗi yêu cầu:

Bạn vẫn để máy chủ có tiếng nói cuối cùng và máy chủ vẫn phải xác thực mọi thứ khách hàng nói, nhưng nó diễn ra trong suốt.

Giả sử giao thức HTTPS để ngăn chặn các cuộc tấn công trung gian (MITMA).

  • Máy khách bắt tay với máy chủ lần đầu tiên và máy chủ tạo khóa chung cho máy khách và giữ khóa riêng bằng cách sử dụng sơ đồ mã hóa bất đối xứng. Máy khách lưu trữ khóa "công khai" của máy chủ trong bộ nhớ cục bộ, được mã hóa bằng mật khẩu an toàn mà bạn không lưu ở bất cứ đâu.

  • Hiện tại khách hàng đang offline. Khách hàng muốn thực hiện các hành động đáng tin cậy. Máy khách nhập mật khẩu của mình và lấy khóa công khai của máy chủ.

  • Bây giờ máy khách thực hiện các hành động dựa trên kiến ​​thức về dữ liệu đó và máy khách mã hóa mọi hành động mà nó thực hiện với khóa chung của máy chủ cho máy khách đó .

  • Khi máy khách trực tuyến, máy khách sẽ gửi ID khách của nó và tất cả các hành động mà máy khách thực hiện được gửi đến máy chủ được mã hóa bằng khóa chung của máy chủ.

  • Máy chủ giải mã các hành động và nếu chúng ở định dạng chính xác, nó tin tưởng rằng chúng có nguồn gốc từ máy khách.

Chú thích:

  • Bạn không thể lưu trữ mật khẩu của khách hàng ở bất cứ đâu, nếu không, kẻ tấn công sẽ có thể lấy khóa và ký các hành động như của chính họ. Tính bảo mật của lược đồ này chỉ dựa vào tính toàn vẹn của khóa mà máy chủ tạo cho máy khách. Máy khách vẫn cần được xác thực với máy chủ khi yêu cầu khóa đó.

  • Thực tế bạn vẫn dựa vào máy chủ để bảo mật chứ không phải máy khách. Mỗi hành động khách hàng thực hiện bạn phải xác nhận trên máy chủ.

  • Có thể chạy các tập lệnh bên ngoài trong nhân viên web . Hãy ghi nhớ mọi yêu cầu JSONP mà bạn có bây giờ là vấn đề bảo mật lớn hơn nhiều. Bạn cần bảo vệ chìa khóa bằng mọi giá. Một khi bạn mất nó, kẻ tấn công có thể mạo danh người dùng.

  • Điều này đáp ứng nhu cầu của bạn rằng 'không ping đến máy chủ' được thực hiện. Kẻ tấn công không thể bắt chước một yêu cầu HTTP với dữ liệu giả mạo nếu chúng không biết khóa.

  • Câu trả lời của Joachim vẫn đúng . Thực tế, bạn vẫn đang thực hiện tất cả xác thực trên máy chủ . Điều duy nhất bạn đã lưu ở đây là nhu cầu xác thực mật khẩu với máy chủ mỗi lần. Bây giờ bạn chỉ cần liên quan đến máy chủ khi bạn muốn cam kết hoặc lấy dữ liệu cập nhật. Tất cả những gì chúng tôi đã làm ở đây là lưu một khóa đáng tin cậy ở phía máy khách và để máy khách xác nhận lại nó.

  • Đây là một lược đồ khá phổ biến cho các ứng dụng trang đơn (ví dụ, với AngularJS).

  • Tôi gọi khóa công khai của máy chủ là "công khai" vì điều đó có nghĩa là gì trong các chương trình như RSA , nhưng thực tế nó là thông tin nhạy cảm trong sơ đồ và cần được bảo vệ.

  • Tôi sẽ không giữ mật khẩu ở bất cứ đâu trong bộ nhớ. Tôi sẽ khiến người dùng gửi mật khẩu 'ngoại tuyến' của mình mỗi khi anh ấy / cô ấy bắt đầu chạy mã ngoại tuyến.

  • Đừng cuộn mật mã của riêng bạn - sử dụng một thư viện đã biết như Stanford để xác thực.

  • Hãy xem lời khuyên này là như vậy . Trước khi bạn triển khai loại xác thực này trong một ứng dụng quan trọng trong kinh doanh trong thế giới thực, hãy tham khảo ý kiến ​​chuyên gia bảo mật . Đây là một vấn đề nghiêm trọng vừa đau đớn vừa dễ mắc sai lầm.

Điều quan trọng là không có tập lệnh nào khác có quyền truy cập vào trang. Điều này có nghĩa là bạn chỉ cho phép các tập lệnh bên ngoài với nhân viên web. Bạn không thể tin tưởng bất kỳ tập lệnh bên ngoài nào khác có thể chặn mật khẩu của bạn khi người dùng nhập nó.

Sử dụng promptkhông phải là trường mật khẩu nội tuyến nếu bạn không hoàn toàn chắc chắn và không trì hoãn việc thực thi nó (nghĩa là, nó không nên tồn tại đến điểm mà các sự kiện có quyền truy cập vào nó mà chỉ trong mã đồng bộ hóa). Và không thực sự lưu trữ mật khẩu trong một biến - một lần nữa, điều này chỉ hoạt động nếu bạn tin rằng máy tính của người dùng không bị xâm phạm (mặc dù điều đó hoàn toàn đúng khi xác thực với máy chủ).

Tôi muốn thêm một lần nữa rằng chúng tôi vẫn không tin tưởng khách hàng . Bạn không thể tin tưởng khách hàng một mình và tôi nghĩ rằng câu trả lời của Joachim đóng đinh nó. Chúng tôi chỉ đạt được sự thuận tiện khi không phải ping máy chủ trước khi bắt đầu làm việc.

Tài liệu liên quan:


3
"Đừng cuộn tiền điện tử của riêng bạn" chỉ áp dụng cho các giao thức giống như các giao thức nguyên thủy, nếu không thậm chí còn hơn thế, bởi vì trong khi mọi người thường không đủ dại dột để tạo ra các nguyên thủy của riêng mình, họ nghĩ rằng họ có thể tạo ra một giao thức tốt . Tôi cũng không thấy tại sao RSA lại cần thiết ở đây. Vì bạn đang sử dụng HTTPS, tại sao không tạo bí mật chia sẻ 16-32 byte và yêu cầu được gửi với các yêu cầu trong tương lai? Tất nhiên, nếu bạn làm điều này, hãy chắc chắn sử dụng kiểm tra sự bình đẳng bất biến theo thời gian trên chuỗi ...
Reid

2
+1 @Reid Vâng, tôi vừa có một cuộc thảo luận về điều này với một số chuyên gia về điều này gần đây. Tôi gần như dựa trên sơ đồ nguyên thủy ở đây trên một giao thức mà tôi đã tìm hiểu (bởi Rabin IIRC) nhưng ít nhất cho đến khi tôi có thể tìm thấy các chi tiết cụ thể (và biện minh cho ví dụ tại sao cần mã hóa bất đối xứng trong trường hợp này). Không sử dụng lược đồ được đề xuất trong câu trả lời này mà không hỏi ý kiến ​​chuyên gia bảo mật trước . Tôi đã thấy cách tiếp cận này được sử dụng ở một số nơi, nhưng trong thực tế có nghĩa là rất ít, nếu có bất cứ điều gì. Tôi cũng chỉnh sửa câu trả lời để tăng cường điều đó.
Benjamin Gruenbaum

Sử dụng một dấu nhắc thêm ít bảo mật. Kẻ tấn công có thể ghi đè window.promptphương thức để chặn cụm từ hoặc khởi chạy một dấu nhắc riêng (có thể trong iframe!). Trường mật khẩu có một lợi ích bổ sung: các ký tự không được hiển thị.
Rob W

@RobW Tất nhiên, toàn bộ chương trình này là vô giá trị nếu trang bị xâm phạm. Nếu kẻ tấn công có quyền truy cập để chạy JavaScript trong trang, chúng tôi sẽ bị lừa. Ý tưởng đằng sau lời nhắc là nó chặn nhưng bạn nói đúng, bất kỳ lợi ích bảo mật nào nó cung cấp đều đáng nghi ngờ. Xem liên kết cuối cùng trong danh sách.
Benjamin Gruenbaum

1
Đầu tiên. Câu trả lời tuyệt vời, tôi nghĩ rằng tôi không thể yêu cầu bất cứ điều gì khác. Mặt khác, tôi muốn làm các dự án thú cưng cho tôi (và tất nhiên cho những ai muốn sử dụng nó) và có lẽ điều này là quá mức cần thiết (hoặc có thể không). Ý tôi là, tôi không muốn làm gì nghiêm trọng và tôi sợ rằng tôi không thể lăn loại auth mà bạn đã giải thích, thiếu kiến ​​thức. Tôi nghĩ rằng tôi sẽ thực hiện kiểm tra 401 đơn giản hoặc nếu tôi không có yêu cầu nào, tôi chỉ ping máy chủ mỗi khi tôi truy cập loại tuyến đường đó. Mã thông báo xác thực cũng là một tùy chọn (và có thể là thứ gần nhất liên quan đến những gì bạn đã giải thích ở đây AFAIK). Cảm ơn bạn :)
Jesus Rodriguez

89

Thật đơn giản: bất kỳ cơ chế bảo mật nào phụ thuộc vào máy khách chỉ làm những gì bạn bảo nó làm có thể bị xâm phạm khi kẻ tấn công có quyền kiểm soát máy khách.

Bạn có thể kiểm tra bảo mật trên máy khách, nhưng chỉ hoạt động hiệu quả như một "bộ đệm" (để tránh thực hiện một chuyến đi khứ hồi đắt tiền đến máy chủ nếu khách hàng biết rằng câu trả lời sẽ là "không").

Nếu bạn muốn giữ thông tin từ một nhóm người dùng, hãy đảm bảo rằng ứng dụng khách của những người dùng đó không bao giờ có được thông tin đó. Nếu bạn gửi "dữ liệu bí mật" đó cùng với hướng dẫn "nhưng vui lòng không hiển thị nó", nó sẽ trở nên tầm thường để vô hiệu hóa mã kiểm tra yêu cầu đó.

Như bạn thấy, câu trả lời này không thực sự đề cập đến bất kỳ chi tiết cụ thể về JavaScript / Trình duyệt nào. Đó là bởi vì khái niệm này là giống nhau, bất kể khách hàng của bạn là gì. Nó không thực sự quan trọng đó là một ứng dụng khách béo (ứng dụng khách / máy chủ truyền thống), ứng dụng web trường học cũ hoặc ứng dụng một trang với JavaScript phía máy khách rộng rãi.

Khi dữ liệu của bạn rời khỏi máy chủ, bạn phải cho rằng kẻ tấn công có toàn quyền truy cập vào nó.


Cảm ơn bạn. Sẽ thật đáng yêu nếu bạn có thể giải thích thêm một chút, kiến ​​thức bảo mật của tôi không tốt và phần duy nhất tôi hiểu là tôi sai: P. Khi bạn nói về bộ nhớ đệm, nó chỉ để bộ đệm khi máy chủ nói không? Ý tôi là, nếu máy chủ nói có một lần, bạn không thể lưu trữ nó, phải không?
Jesus Rodriguez

3
Tôi chỉ muốn nói thêm rằng nó có thể biến truy cập đóng cửa trong trình duyệt (như trong mô hình mô-đun đề cập của bạn), đặc biệt là với một trình gỡ lỗi :)
Benjamin Gruenbaum

2
@BenjaminGruenbaum: vui lòng mở rộng câu trả lời thành câu trả lời tập trung vào khía cạnh JS. Tôi chỉ đưa ra cái nhìn tổng quan về công nghệ cao, bất khả tri ở đây. Một câu trả lời tập trung vào bản thân JS cũng sẽ rất hay!
Joachim Sauer

1
Vì vậy, trong ngắn hạn, nếu một số thông tin / tuyến đường / bất cứ điều gì có thể truy cập tùy thuộc vào một biến javascript, thì điều đó sẽ không an toàn trong mọi trường hợp vì bạn có thể dễ dàng thay đổi biến đó để nói những gì bạn cần để truy cập vào những thứ riêng tư đó.
Jesus Rodriguez

4
@JoachimSauer Tôi nghĩ rằng sẽ bỏ lỡ điểm của câu hỏi này mà bạn đóng đinh độc đáo. Bất kể khách hàng thực hiện các biện pháp bảo mật nào, có thể thỏa hiệp thông tin liên lạc . Bạn có thể tạo các hệ thống xác thực rất chắc chắn trong JavaScript nhưng tất cả đều không có giá trị gì ngay khi bạn chèn thông tin liên lạc đến máy chủ mà các máy khách khác cũng coi là nguồn sự thật. Tất cả mã nguồn được gửi đến phía máy khách, kẻ tấn công thông minh chỉ có thể đọc nó và bắt chước một yêu cầu HTTP đến máy chủ. Người ta phải coi bất cứ thứ gì có nguồn gốc từ máy khách là không đáng tin trừ khi được xác nhận trên máy chủ.
Benjamin Gruenbaum

10

Có một câu nói trong cộng đồng chơi game: " Khách hàng nằm trong tay kẻ thù". Bất kỳ mã nào đang chạy bên ngoài khu vực được bảo mật như máy chủ đều dễ bị tấn công. Trong trường hợp cơ bản nhất, dễ bị tấn công ngay từ đầu. Đó là quyết định của khách hàng về việc thực sự chạy" mã bảo mật "của bạn và người dùng có thể chỉ "chọn không tham gia". Mặc dù với mã gốc, bạn có ít nhất một chức năng tự động lắp ráp và một lớp bảo vệ bổ sung bởi thực tế là kẻ tấn công cần phải là một lập trình viên giỏi để thao túng điều đó, nhưng JS thường không bị biến dạng và là văn bản thuần túy. Tất cả những gì bạn cần để thực hiện một cuộc tấn công là các công cụ nguyên thủy như máy chủ proxy và trình soạn thảo văn bản. Kẻ tấn công sẽ vẫn cần một mức độ giáo dục nhất định liên quan đến lập trình, nhưng cách dễ dàng hơn để sửa đổi tập lệnh bằng cách sử dụng bất kỳ đoạn văn bản nào hơn là tiêm mã vào một tệp thực thi.


Hội không phải là một trò hề, và ai tin rằng chưa bao giờ chơi một trò chơi chiến tranh
miniBill

@miniBill: Mặc dù kẻ tấn công có kinh nghiệm vừa phải sẽ không gặp rắc rối với mã được lắp ráp, nó sẽ cung cấp bộ lọc thông cao rất cơ bản. (Than ôi, điều này mang tính học thuật, vì việc loại bỏ các kịch bản kiddies cung cấp sự gia tăng tối thiểu về bảo mật cho kịch bản của OP)
Piskvor

1

Đây không phải là một câu hỏi về việc hack JavaScript. Nếu tôi muốn tấn công ứng dụng của bạn, tôi sẽ sử dụng proxy riêng cho phép tôi nắm bắt, sửa đổi và phát lại lưu lượng. Đề án bảo mật được đề xuất của bạn dường như không có bất kỳ sự bảo vệ nào chống lại điều đó.


0

Nói riêng về Angular:

Bảo vệ phía khách hàng tuyến không tồn tại. Ngay cả khi bạn 'ẩn' một nút để định tuyến đó, người dùng luôn có thể nhập nó vào, Angular sẽ khiếu nại, nhưng khách hàng có thể mã xung quanh đó.

Tại một số điểm, bộ điều khiển của bạn sẽ phải yêu cầu máy chủ của bạn cung cấp dữ liệu cần thiết để hiển thị chế độ xem, nếu người dùng không được phép truy cập dữ liệu đó, họ sẽ không nhận được dữ liệu đó vì bạn đã bảo vệ dữ liệu này ở phía máy chủ và ứng dụng Angular của bạn sẽ xử lý thích hợp 401.

Nếu bạn đang cố gắng bảo vệ dữ liệu thô, bạn không thể phía khách hàng, nếu bạn chỉ muốn một người dùng cụ thể chỉ có thể xem dữ liệu chung theo một cách nhất định, hãy tạo dữ liệu 'lượt xem' trên máy chủ thay vì gửi dữ liệu thô cho khách hàng và yêu cầu tổ chức lại nó (dù sao bạn cũng nên làm điều này vì lý do hiệu suất).

Lưu ý bên lề: không bao giờ có bất kỳ thứ gì nhạy cảm được tích hợp trong các mẫu xem mà Angular yêu cầu, đừng làm điều đó. Nếu vì một lý do điên rồ nào đó, bạn cần bảo vệ các mẫu xem đó ở phía máy chủ, giống như khi bạn thực hiện kết xuất phía máy chủ.

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.