Làm cách nào để bảo mật các lệnh gọi API REST?


91

Tôi đang phát triển ứng dụng web yên tĩnh sử dụng một số khuôn khổ web phổ biến trên phần phụ trợ, chẳng hạn (rails, sinatra, flask, express.js). Lý tưởng nhất là tôi muốn phát triển phía khách hàng với Backbone.js. Làm cách nào để chỉ cho phép phía ứng dụng khách javascript của tôi tương tác với các lệnh gọi API đó? Tôi không muốn các lệnh gọi API đó ở chế độ công khai và được gọi bằng curlhoặc đơn giản bằng cách nhập liên kết trên trình duyệt.


Tất cả các lệnh gọi API của bạn có yêu cầu mã thông báo được chuyển cho máy khách khi trang của bạn được phân phát không?
hajpoj


Amazon AWS javascript SDK sử dụng URL đối tượng được ký trước: - docs.aws.amazon.com/AmazonS3/latest/dev/…
rjha94

Câu trả lời:


90

Theo nguyên tắc đầu tiên, nếu API của bạn được sử dụng bởi ứng dụng khách JS của bạn, bạn phải giả định rằng nó là công khai: Một trình gỡ lỗi JS đơn giản đặt kẻ tấn công vào một vị trí, nơi anh ta có thể gửi một yêu cầu giống nhau từng byte từ một công cụ của sự lựa chọn của mình.

Điều đó nói rằng, nếu tôi đọc câu hỏi của bạn một cách chính xác, thì đây không phải là điều bạn muốn tránh: Điều bạn thực sự không muốn xảy ra là API của bạn được sử dụng (thường xuyên) mà không có ứng dụng khách JS của bạn tham gia. Dưới đây là một số ý tưởng về cách nếu không thực thi, thì ít nhất hãy khuyến khích sử dụng ứng dụng khách của bạn:

  • Tôi chắc chắn, API của bạn có một số loại trường xác thực (ví dụ: băm được tính trên máy khách). Nếu không, hãy xem câu hỏi SO này . Đảm bảo bạn sử dụng muối (hoặc thậm chí là khóa API) được cấp cho ứng dụng khách JS của bạn trên cơ sở phiên (không phải mã cứng). Bằng cách này, người tiêu dùng trái phép API của bạn bị buộc phải làm nhiều việc hơn.

  • Khi tải ứng dụng khách JS, hãy nhớ một số tiêu đề HTTP (tác nhân người dùng nghĩ đến) và địa chỉ IP và yêu cầu xác thực lại nếu chúng thay đổi, sử dụng danh sách đen cho các nghi phạm thông thường. Điều này buộc kẻ tấn công phải làm lại bài tập về nhà kỹ lưỡng hơn.

  • Ở phía máy chủ, hãy nhớ một vài lệnh gọi API cuối cùng và trước khi cho phép một lệnh khác, hãy kiểm tra xem logic nghiệp vụ có cho phép lệnh mới ngay bây giờ hay không: Điều này phủ nhận kẻ tấn công có khả năng tập trung nhiều phiên của mình vào một phiên với máy chủ của bạn: kết hợp với các biện pháp khác, điều này sẽ làm cho kẻ ngược đãi dễ dàng bị phát hiện.

Tôi có thể đã không nói điều đó với sự rõ ràng cần thiết: Tôi cho rằng không thể làm cho kẻ lạm dụng hoàn toàn không thể sử dụng dịch vụ của bạn, nhưng bạn có thể làm cho nó khó khăn như vậy, điều đó có thể không đáng.


đây là thông tin hữu ích, nhưng điều gì sẽ xảy ra nếu tôi muốn tạo một số xác thực từ api phụ trợ của mình sang một ứng dụng api khác như một máy chủ riêng biệt, để đơn giản hóa câu hỏi của tôi, tôi muốn back-end aka node.js của mình gửi yêu cầu tìm nạp đến một back- máy chủ cuối của riêng tôi, vì một số lý do, điều này là cần thiết, nhưng tôi muốn bảo mật các cuộc gọi api, vì nó có thể truy cập dữ liệu nhạy cảm và tôi không thể sử dụng sesions hoặc jwt vì tôi không thể lưu trữ chúng thực sự trong trình duyệt.
Kim tự tháp

@Thepyramid Không quan trọng, lệnh gọi API làm gì ở phía máy chủ, đặc biệt nếu phía máy chủ thực hiện một lệnh gọi API cấp 2 khác. Phần quan trọng là xử lý máy chủ của bạn không phải như một proxy mà là một ứng dụng.
Eugen Rieck

bạn có thể giải thích thêm về cách làm cho ứng dụng không phải là proxy
The kim tự tháp

1
Ý tôi là: Để có được mức độ bảo mật tốt, bạn cần sử dụng tất cả các công cụ mà ứng dụng web có: Phiên, cơ sở dữ liệu xác thực, logic nghiệp vụ. Nếu không làm điều đó và chỉ coi máy chủ của bạn như một cách để chuyển yêu cầu đến máy chủ khác, bạn chỉ đang sử dụng nó làm proxy cho máy chủ khác đó và bị giới hạn bởi bất kỳ bảo mật nào mà máy chủ khác cung cấp.
Eugen Rieck

1
@PirateApp Kẻ tấn công có thể dễ dàng bỏ qua các tiêu đề CSRF. Chúng chỉ hoạt động, nếu thiết bị cuối là một trình duyệt chưa được vá
Eugen Rieck

12

Bạn nên triển khai một số loại hệ thống xác thực. Một cách tốt để xử lý điều này là xác định một số biến tiêu đề dự kiến. Ví dụ: bạn có thể có lệnh gọi API xác thực / đăng nhập trả về mã thông báo phiên. Các lệnh gọi tiếp theo tới API của bạn sẽ yêu cầu mã thông báo phiên được đặt trong biến tiêu đề HTTP với tên cụ thể như 'your-api-token'.

Ngoài ra, nhiều hệ thống tạo mã thông báo truy cập hoặc khóa được mong đợi (như youtube, facebook hoặc twitter) bằng cách sử dụng một số loại hệ thống tài khoản api. Trong những trường hợp đó, khách hàng của bạn sẽ phải lưu trữ chúng theo một cách nào đó trong máy khách.

Sau đó, nó chỉ đơn giản là vấn đề thêm một kiểm tra cho phiên vào khuôn khổ REST của bạn và đưa ra một ngoại lệ. Nếu có thể, mã trạng thái (đang hoạt động) sẽ là lỗi 401.


8
Mặc dù không có gì ngăn cản họ xem tiêu đề và tái tạo chúng.
cdmckay

1
@cdmckay - Mã thông báo phải khớp với mã thông báo được lưu trữ trong một phiên. Chỉ cần tạo lại tiêu đề sẽ dẫn đến phản hồi "Trái phép" nếu nó đến từ một phiên khác.
Andrei Volgin

3
Tuy nhiên, họ vẫn có thể sử dụng cùng một phiên và thay đổi các yêu cầu trước khi chúng được gửi đến API ... hoặc thậm chí sử dụng bảng điều khiển trong thời gian chạy, tạo ra một lệnh gọi với các tiêu đề / trường phù hợp chỉ sửa đổi những phần bạn cần ...
Potter Rafed

2
@PotterRafed: Nếu người dùng truy cập vào phiên hợp lệ của riêng họ, phiên đó được gọi là sử dụng một ứng dụng, không tấn công nó. Mục đích của xác thực là ngăn chặn quyền truy cập vào các phiên / dữ liệu của người dùng khác .
Andrei Volgin 22/09/17

@AndreiVolgin vâng chợ đủ, nhưng nó vẫn còn một lỗ hổng
Potter Rafed

9

Hiện có một tiêu chuẩn mở được gọi là "JSON Web Token",

xem https://jwt.io/ & https://en.wikipedia.org/wiki/JSON_Web_Token

JSON Web Token (JWT) là một tiêu chuẩn mở dựa trên JSON (RFC 7519) để tạo các mã thông báo xác nhận một số yêu cầu. Ví dụ: một máy chủ có thể tạo mã thông báo có yêu cầu "đăng nhập với tư cách quản trị viên" và cung cấp mã đó cho khách hàng. Sau đó, khách hàng có thể sử dụng mã thông báo đó để chứng minh rằng họ đã đăng nhập với tư cách quản trị viên. Các mã thông báo được ký bằng khóa của máy chủ, vì vậy máy chủ có thể xác minh rằng mã thông báo đó là hợp pháp. Các mã thông báo được thiết kế nhỏ gọn, an toàn với URL và có thể sử dụng được, đặc biệt là trong ngữ cảnh đăng nhập một lần (SSO) của trình duyệt web. Các xác nhận quyền sở hữu JWT thường có thể được sử dụng để chuyển danh tính của người dùng đã xác thực giữa nhà cung cấp danh tính và nhà cung cấp dịch vụ hoặc bất kỳ loại xác nhận quyền sở hữu nào khác theo yêu cầu của quy trình kinh doanh. [1] [2] Các mã thông báo cũng có thể được xác thực và mã hóa. [3] [4]


Điều gì sẽ ngăn người dùng sao chép mã thông báo của họ và sử dụng nó trong bất kỳ phản hồi nào khác?
Ulad Kasach

1
@UladKasach thành thật mà nói, tôi chưa bao giờ thực sự đi sâu vào chúng, nhưng afaik chúng có thể hết hạn sử dụng, duy nhất cho người dùng của bạn và được mã hóa bằng SSL (tất nhiên là bạn đang thực hành), đó chính là ý tưởng đằng sau oauth afaik
bbozo

3

Xin lỗi @MarkAmery và Eugene, nhưng điều đó không chính xác.

Ứng dụng js + html (client) của bạn đang chạy trong trình duyệt CÓ THỂ được thiết lập để loại trừ các lệnh gọi trực tiếp trái phép tới API như sau:

  1. Bước đầu tiên: Thiết lập API để yêu cầu xác thực. Trước tiên, máy khách phải tự xác thực thông qua máy chủ (hoặc một số máy chủ bảo mật khác), ví dụ như yêu cầu người dùng cung cấp mật khẩu chính xác.

Trước khi xác thực, các lệnh gọi tới API không được chấp nhận.

Trong quá trình xác thực, một "mã thông báo" được trả lại.

Sau khi xác thực, chỉ các lệnh gọi API có "mã thông báo" xác thực mới được chấp nhận.

Tất nhiên ở giai đoạn này, chỉ những người dùng được ủy quyền có mật khẩu mới có thể truy cập API, mặc dù nếu họ là lập trình viên gỡ lỗi ứng dụng, họ có thể truy cập trực tiếp vào mục đích thử nghiệm.

  1. Bước thứ hai: Bây giờ, hãy thiết lập một API bảo mật bổ sung, được gọi trong giới hạn thời gian ngắn sau khi ứng dụng js + html của ứng dụng khách được yêu cầu ban đầu từ máy chủ. "Cuộc gọi lại" này sẽ cho máy chủ biết rằng máy khách đã được tải xuống thành công. Hạn chế lệnh gọi API REST của bạn chỉ hoạt động nếu ứng dụng khách được yêu cầu gần đây và thành công.

Bây giờ để sử dụng API của bạn, trước tiên họ phải tải xuống ứng dụng khách và thực sự chạy nó trong trình duyệt. Chỉ sau khi nhận được lệnh gọi lại thành công và sau đó là mục nhập của người dùng trong một khoảng thời gian ngắn, API mới chấp nhận lệnh gọi.

Vì vậy, bạn không phải lo lắng rằng đây có thể là một người dùng trái phép mà không có thông tin xác thực.

(Tiêu đề của câu hỏi, 'Làm cách nào để bảo mật các lệnh gọi API REST', và từ hầu hết những gì bạn nói, đó là mối quan tâm chính của bạn, và không phải là câu hỏi nghĩa đen về CÁCH API của bạn được gọi, mà là BẰNG CÁCH NÀO, đúng không? )


5
Điểm thứ hai không có ý nghĩa. Nếu kẻ tấn công cần tải ứng dụng của bạn, hắn sẽ làm điều đó (lệnh gọi lại của bạn sẽ hiển thị). Và sau đó tấn công.
Andrei Volgin

Điểm 2 bổ sung cho điểm 1. Kẻ tấn công vẫn cần xác thực. Điểm 2 chỉ bổ sung thêm rằng nhu cầu thực sự tải xuống ứng dụng html để được cấp phép. Vì vậy, một cuộc gọi trực tiếp đến các API mà không có ứng dụng (có lẽ chỉ được truy cập và tải xuống sau khi xác thực) là không thể. Đó là một cái gì đó đã được yêu cầu trong câu hỏi này.
pashute,

Bạn chỉ có thể cho phép các yêu cầu từ miền của mình.
Andrei Volgin

Điều đó chỉ giới hạn các lệnh gọi bên trong miền, vì vậy bây giờ người dùng ứng dụng trình duyệt javascript phải ở bên trong miền (có thể không phải điều gì đó knd muốn) và những người dùng đó vẫn có thể gọi API trực tiếp thông qua curl.
pashute

2
Những gì bạn có vẻ bỏ qua là BAO GIỜ bạn yêu cầu trình duyệt của người dùng làm, có thể bị kẻ tấn công sao chép - để khiến trình duyệt làm điều đó, nó phải có thể đọc được.
Eugen Rieck

1
  1. Đặt var SESSION trên máy chủ khi máy khách tải index.html(hoặc backbone.jsv.v.) của bạn lần đầu tiên

  2. Kiểm tra var này ở phía máy chủ trong mỗi lệnh gọi API.

PS đây không phải là một giải pháp "bảo mật" !!! Điều này chỉ là để giảm tải trên máy chủ của bạn để mọi người không lạm dụng nó hoặc "liên kết nóng" API của bạn từ các trang web và ứng dụng khác.


0

Đây là những gì tôi làm:

  1. Bảo mật API bằng Tiêu đề HTTP với các lệnh gọi như X-APITOKEN:

  2. Sử dụng các biến phiên trong PHP. Có sẵn hệ thống đăng nhập và lưu mã thông báo người dùng trong các biến phiên.

  3. Gọi mã JS với Ajax sang PHP và sử dụng biến phiên với curl để gọi API. Theo cách đó, nếu biến phiên không được đặt, nó sẽ không gọi và mã PHP chứa Mã thông báo truy cập vào API.

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.