Giải pháp tốt nhất để ủy quyền rằng người dùng chỉ được phép sửa đổi / hành động với tài nguyên của chính họ trong API REST


8

Lý lịch:

Hiện đang trong quá trình xây dựng API REST, sử dụng nút w / express và nó được sử dụng bởi một ứng dụng di động và cuối cùng là một trang web (dựa trên trình duyệt hiện đại).

Tôi đang cố gắng xác định cách tốt nhất để ủy quyền cho yêu cầu cập nhật / hành động của người dùng để họ chỉ được phép sửa đổi tài nguyên của chính họ. Các hành động sẽ xảy ra ở một tỷ lệ bán cao do đó mối quan tâm.

Lưu ý: Quyền sở hữu của các thực thể không thể được chuyển giao trong trường hợp sử dụng này.

Các giải pháp tiềm năng:

Giải pháp : Lưu trữ và duy trì danh sách từng tài nguyên của người dùng trong phiên máy chủ được hỗ trợ bởi thứ gì đó như reddis.

Mối quan tâm : Việc duy trì phiên phía máy chủ có tập hợp phức tạp riêng được chia tỷ lệ cụ thể với nhiều máy chủ. Điều này cũng vi phạm REST. do-session-thực sự vi phạm-yên tĩnh để biết thêm thông tin.

Giải pháp: Thực hiện truy vấn đọc trước truy vấn hành động / cập nhật của người dùng. IE đưa cho tôi các mục của người dùng này sau đó nếu trong danh sách tiến hành cập nhật.

Mối quan tâm: Chi phí đọc thêm mỗi khi người dùng hành động thay mặt cho tài nguyên.

Giải pháp: Truyền id người dùng xuống lớp db và biến nó thành một phần của bản cập nhật có điều kiện hoặc nếu bạn muốn có được sự ưa thích, hãy sử dụng thứ gì đó như bảo mật mức hàng của Postgres cho tài nguyên đó tùy thuộc vào phụ trợ dữ liệu.

Mối quan tâm: Điều này có vẻ hơi muộn trong vòng đời yêu cầu để kiểm tra xem tài nguyên có phải là người dùng yêu cầu hay không. Lỗi sẽ phải được ném lên từ phần cuối dữ liệu. Cùng một lưu ý, nó cũng sẽ hơi lạc lõng khi xem xét xác thực và ủy quyền dựa trên vai trò thường được thực hiện khi bắt đầu vòng đời yêu cầu. Việc thực hiện cũng phụ thuộc vào phụ trợ dữ liệu. Nó cũng đẩy logic kinh doanh vào phụ trợ dữ liệu.

Giải pháp: Phía khách hàng đã ký phiên các loại. Hoặc với JWT hoặc cookie được mã hóa / đã ký. Về cơ bản duy trì một phiên đáng tin cậy có chứa một danh sách các id tài nguyên của người dùng.

Mối quan tâm: Kích thước của phiên phía khách hàng. Thực tế là nó sẽ được gửi với mỗi yêu cầu ngay cả khi không cần thiết. Bảo trì trở nên cực kỳ phức tạp khi bạn giới thiệu khả năng nhiều phiên / khách hàng đang hoạt động. Làm thế nào bạn sẽ cập nhật trạng thái phía máy khách khi một tài nguyên được thêm vào một máy khách khác.

Giải pháp: Truyền mã thông báo cập nhật đã ký (JWT) hoặc url cho khách hàng với tài nguyên khi tài nguyên được tìm nạp. Hy vọng rằng khi một tài nguyên được cập nhật / hành động. Mã thông báo đã ký sẽ chứa id người dùng và id tài nguyên và bạn có thể dễ dàng xác minh đối với những mã đó.

Mối quan tâm: Trở nên phức tạp nếu quyền sở hữu tài nguyên có thể chuyển nhượng được nhưng trong trường hợp của tôi đó không phải là vấn đề đáng lo ngại. Giới thiệu sự phức tạp qua một lần đọc trước khi cập nhật. Hơi lạ phải không?

Suy nghĩ cuối cùng:

Tôi đang nghiêng về giải pháp cuối cùng, nhưng vì tôi không thấy nó xảy ra rất thường xuyên. Tôi tự hỏi liệu tôi có đang thiếu thứ gì không? hoặc có thể là một phần của mẫu thiết kế mà tôi không biết.


1
Giả sử rằng có thể chuyển quyền sở hữu, cách tiếp cận cuối cùng sẽ đòi hỏi phải kiểm tra xem người dùng đó có còn là chủ sở hữu của tài nguyên nói trên hay không. Vì vậy, cuối cùng bạn có mã thông báo cộng với một trong những cách tiếp cận khác.
Miguel van de Laar

@MiguelvandeLaar Cảm ơn bạn đã phản hồi! bạn là chính xác, tuy nhiên trong trường hợp sử dụng của tôi quyền sở hữu không thể được chuyển giao, trong mọi trường hợp.
Ashtonian

2
"Phiên máy chủ" Trừ khi tôi thiếu thứ gì đó đáng kể, REST loại trừ các phiên phía máy chủ.
Các cuộc đua nhẹ nhàng trong quỹ đạo

@BarryTheHatchet - Có vẻ như đó là điều có thể tranh luận, có một số cuộc thảo luận thú vị ở đây: stackoverflow.com/questions/6068113/ Lỗi . Giải pháp đó cũng có mặt cuối cùng vì nó làm cho việc giới thiệu các máy chủ cân bằng tải mới trở nên thú vị ..
Ashtonian

@Ashtonian: Câu trả lời được chấp nhận với số điểm 131 cho câu hỏi đó đồng ý với tôi;) (cũng như theo dõi 223 điểm)
Các cuộc đua Lightness trong Orbit

Câu trả lời:


1

Tôi nghĩ có hai giải pháp trong danh sách của bạn phù hợp nhất với trường hợp sử dụng của bạn; truy vấn đọc trước khi cập nhật (giải pháp 2) và gửi mã thông báo cập nhật với yêu cầu đọc (giải pháp 5).

Nếu bạn lo lắng về hiệu suất, tôi sẽ quyết định cái này hay cái khác tùy thuộc vào số lần đọc so với cập nhật cho tài nguyên mà bạn mong đợi. Nếu bạn mong đợi cách cập nhật nhiều hơn đọc, thì rõ ràng giải pháp 5 là tốt hơn, vì bạn không cần phải tìm nạp thêm cơ sở dữ liệu để tìm ra chủ sở hữu của tài nguyên.

Tuy nhiên, bạn không nên quên ý nghĩa bảo mật của việc đưa ra mã thông báo cập nhật. Với giải pháp 2, giả sử xác thực là an toàn, thì việc cập nhật tài nguyên có thể cũng an toàn vì bạn xác định chủ sở hữu của tài nguyên trên máy chủ.

Với giải pháp 5, Bạn không kiểm tra kỹ yêu cầu của khách hàng, ngoại trừ việc bạn kiểm tra chữ ký hợp lệ. Nếu bạn đang để cập nhật xảy ra trên một liên kết rõ ràng (ví dụ: không có SSL), thì chỉ mã hóa tài nguyên và id người dùng trong mã thông báo không an toàn. Đối với một người, bạn đang tự mở để phát lại các cuộc tấn công, vì vậy bạn nên bao gồm một người không phát triển với mỗi yêu cầu. Ngoài ra, nếu bạn không mã hóa dấu thời gian / ngày hết hạn trong mã thông báo cập nhật, về cơ bản bạn sẽ cấp quyền truy cập cập nhật vô thời hạn cho bất kỳ ai có mã thông báo đó. Cuối cùng, nếu bạn không muốn nonce, thì ít nhất bạn nên bao gồm một hmac của tài nguyên được tìm nạp, để mã thông báo cập nhật chỉ hợp lệ cho trạng thái của tài nguyên khi nó được tìm nạp. Điều này làm cho các cuộc tấn công phát lại trở nên khó khăn hơn và hạn chế hơn nữa kiến ​​thức về thiệt hại của mã thông báo cập nhật có thể làm,

Tôi nghĩ rằng ngay cả khi bạn đang liên lạc qua một liên kết an toàn, việc thêm một nonce (hoặc ít nhất là một trạng thái của tài nguyên) và ngày hết hạn cho mã thông báo cập nhật sẽ là một việc làm thông minh. Tôi không biết miền ứng dụng, nhưng bạn có thể đối phó với người dùng độc hại và họ có thể phá hỏng tất cả các loại tàn phá với sức mạnh của quyền truy cập cập nhật không giới hạn vào tài nguyên của chính họ.

Thêm một nonce sẽ có nghĩa là một cột bổ sung cho mỗi tài nguyên trong cơ sở dữ liệu của bạn, nơi bạn lưu trữ giá trị của nonce mà bạn đã gửi với yêu cầu tìm nạp cuối cùng. Bạn có thể tính toán hmac qua biểu diễn json nối tiếp của tài nguyên của bạn. Sau đó, bạn có thể gửi mã thông báo của mình không phải là một phần của nội dung thư mà là một tiêu đề HTTP bổ sung.

Ồ, và tôi sẽ sử dụng mã thông báo, không phải URL; trong REST, URL cập nhật cho một tài nguyên nhất định phải là cùng một URL mà tài nguyên được tìm nạp từ phải không? Tôi sẽ chuyển tất cả các nội dung liên quan đến xác thực và ủy quyền sang các tiêu đề HTTP, ví dụ: bạn có thể cung cấp mã thông báo cập nhật trong Tiêu đề ủy quyền của yêu cầu PUT.

Lưu ý rằng việc thêm một nonce phát triển với mỗi lần tìm nạp tài nguyên cũng sẽ yêu cầu cập nhật cơ sở dữ liệu (giá trị mới cho nonce) cho mỗi yêu cầu tìm nạp tài nguyên (mặc dù bạn có thể thoát khỏi việc chỉ cập nhật nonce khi trạng thái của tài nguyên thực sự thay đổi , do đó, nó sẽ không có quan điểm về hiệu suất), trừ khi bạn muốn giữ thông tin đó trong bộ nhớ nhất thời và chỉ cần khách hàng thử lại khi máy chủ của bạn được khởi động lại giữa yêu cầu tìm nạp và cập nhật.

Lưu ý phụ cho giải pháp 4 của bạn (phiên phía khách hàng): Tùy thuộc vào số lượng tài nguyên mà người dùng của bạn có thể tạo, kích thước phiên có thể không phải là vấn đề. Vấn đề cập nhật phiên phía máy khách cũng có thể khá dễ giải quyết: Nếu yêu cầu cập nhật đối với tài nguyên không thành công do tài nguyên không được liệt kê trong dữ liệu phiên bạn nhận được từ máy khách của mình, nhưng người dùng đã chính xác, thì bạn hãy thực hiện kiểm tra phần phụ trợ xem dữ liệu phiên từ máy khách đó có bị lỗi thời không. Nếu có, bạn cho phép cập nhật và gửi lại cookie đã cập nhật cùng với câu trả lời cho yêu cầu cập nhật. Điều này sẽ chỉ gây ra tra cứu cơ sở dữ liệu khi người dùng cố cập nhật tài nguyên từ máy khách với dữ liệu phiên cục bộ đã lỗi thời (hoặc khi anh ta độc hại và cố gắng làm phiền bạn, nhưng tỷ lệ giới hạn trong việc giải cứu!). Tuy nhiên, Tôi đồng ý rằng giải pháp 4 phức tạp hơn các giải pháp khác và bạn tốt hơn với một trong những ý tưởng khác của mình. Giải pháp 4 cũng có những cân nhắc bảo mật khác nhau mà bạn nên tính đến; lưu trữ trạng thái ủy quyền nhiều này trên máy khách thực sự cần bảo mật của bạn để kín nước.


Điều gì xảy ra nếu tất cả các tài nguyên thuộc sở hữu của người dùng được mô hình hóa thành tài nguyên con. (Ví dụ / người dùng / 1 / thực thể / 2). Kết hợp điều đó với JWT đã ký có id người dùng. Nếu bạn làm điều này, ủy quyền thậm chí có thể được ủy quyền cho một máy chủ riêng biệt (API Gateway) vì nó không cần truy cập vào cơ sở dữ liệu.
Chamindu

0

Một giải pháp khác bạn có thể xem xét:

Nếu tài nguyên thực sự không thể được chuyển sang người dùng khác sau khi được tạo, bạn có thể nghĩ về việc mã hóa id người dùng trong id tài nguyên.

Ví dụ: tất cả các tài nguyên thuộc về 'alice' của người dùng được đặt tên là 'alice-1', 'alice-2', v.v.

Sau đó, việc kiểm tra xem 'eve' có quyền truy cập vào tài nguyên có tên 'alice-1' hay không.

Nếu bạn không muốn quyền sở hữu tài nguyên là kiến ​​thức công khai, bạn có thể sử dụng hàm băm mật mã như vậy:

  1. Cung cấp một mật khẩu chỉ có máy chủ của bạn biết
  2. Và tên người dùng u (ví dụ: 'alice')
  3. Và một tên tài nguyên r (ví dụ '1')

Tạo hmac(password, u | '-' | r ), ở đâu | là nối. Sử dụng kết quả, cùng với tên tài nguyên r, làm id của tài nguyên. Tùy chọn thêm một giá trị muối (như để lưu trữ mật khẩu).

Khi một yêu cầu cập nhật đến từ người dùng 'alice' cho một id tài nguyên nhất định, bạn trích xuất r từ id tài nguyên, tính toán hmac (mật khẩu, 'alice' | '-' | r) và so sánh nó với phần còn lại của id tài nguyên . Nếu nó phù hợp, alice được phép cập nhật tài nguyên, nếu nó không phù hợp, cô ấy không được phép. Và không có mật khẩu, không ai có thể tìm ra ai sở hữu tài nguyên nào.

Tôi nghĩ rằng điều đó an toàn, nhưng bạn có thể muốn cải thiện phẩm chất của hmacs.


0

Dường như có hai vấn đề riêng biệt mà bạn cần quản lý. Chúng là (1) Làm thế nào để bạn xác thực người dùng đang tạo yêu cầu? và (2) làm thế nào để bạn biết đối tượng cuối nào được liên kết với người dùng đó. Tôi cũng có một quan sát có thể phù hợp với trường hợp sử dụng của bạn (3)

(1) Xác thực người dùng theo cách RESTful không bao giờ đẹp. Tôi có xu hướng thích sử dụng các tiêu đề Xác thực / Ủy quyền HTTP và các phản hồi HTTP 401 để kích hoạt xác thực, điều đó có nghĩa là bạn có khả năng xác thực người dùng theo mọi yêu cầu. Vì là ứng dụng dành cho thiết bị di động, bạn có tùy chọn tạo sơ đồ xác thực tùy chỉnh của riêng mình, có thể cho phép bạn cung cấp mã thông báo phiên thay vì chi tiết xác thực đầy đủ trong các yêu cầu trong tương lai.

(2) Người dùng được liên kết với một tập hợp các đối tượng chắc chắn là dữ liệu chính mà bạn cần lưu trữ cùng với các đối tượng thực tế trong kho lưu trữ dữ liệu của bạn. Là một phần của logic kinh doanh của bạn, nó cần kiểm tra ai là chủ sở hữu của đối tượng và so sánh nó với danh tính truy cập đối tượng. Tôi sẽ làm điều này một cách rõ ràng trong mã, như là một phần của lớp nghiệp vụ xác nhận yêu cầu. Nếu các lần truy cập cơ sở dữ liệu là một vấn đề đủ lớn, thì sẽ rất hợp lý khi lưu thông tin này vào kho lưu trữ giá trị khóa, chẳng hạn như memcache hoặc (đối với khối lượng rất cao, các trang web có tính sẵn sàng cao, riak) và chỉ truy cập cơ sở dữ liệu nếu bộ đệm bị lạnh cho sự kết hợp người dùng / đối tượng này.

(3) Nếu bạn có số lượng người dùng và đối tượng đủ nhỏ, bạn có thể kết hợp id người dùng và đối tượng vào cùng một trường và sử dụng trường này làm khóa chính của cơ sở dữ liệu cho bảng đối tượng. ví dụ: số 64 bit cung cấp không gian 24 bit cho ID người dùng và 40 bit không gian cho id đối tượng. Bằng cách đó, khi bạn đang truy vấn đối tượng, bạn có thể chắc chắn 100% nó là dành cho người dùng của bạn.

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.