Lựa chọn phương pháp xác thực cho ứng dụng tài chính trên PostgreSQL


15

Đầu tiên một số nền tảng.

Dự án LedgerSMB là một dự án phần mềm kế toán tài chính nguồn mở chạy trên PostgreSQL. Chúng tôi triển khai một lượng logic nghiệp vụ rất lớn trong các hàm do người dùng xác định, đóng vai trò là công cụ ánh xạ chính giữa các phương thức đối tượng chương trình và hành vi cơ sở dữ liệu. Hiện tại chúng tôi sử dụng người dùng cơ sở dữ liệu làm người dùng xác thực, một phần do lựa chọn (điều này cho phép logic bảo mật tập trung, để các công cụ khác có thể được viết và sử dụng lại quyền cho người dùng) và một phần do sự cần thiết (sau khi chúng tôi rẽ nhánh từ SQL-Ledger, ở đó không có nhiều tùy chọn để trang bị thêm bảo mật cho cơ sở mã đó).

Điều này mua cho chúng tôi quyền truy cập vào một số lượng hợp lý các tùy chọn đăng nhập duy nhất mà PostgreQuery có quyền truy cập, từ LDAP đến Kerberos 5. Chúng tôi thậm chí có thể sử dụng PAM khi mật khẩu có liên quan. Nó cũng cho phép chúng tôi sử dụng lại các quyền khi tích hợp với các ứng dụng khác hoặc cho phép các giao diện máy khách khác. Đối với một ứng dụng kế toán tài chính, điều này có vẻ như là một chiến thắng ròng.

Có chi phí rõ ràng liên quan. Đối với ứng dụng web, chúng tôi rất hạn chế các loại http auth có thể được hỗ trợ. Ví dụ, DIGEST hoàn toàn không có. BASIC hoạt động và chúng tôi có thể thực hiện KRB5 đủ dễ dàng (tôi dự định sẽ hỗ trợ và giải quyết vấn đề này trong 1.4). Các biện pháp xác thực rất mạnh không thể được quản lý trực tiếp trên điều này mặc dù chúng tôi có thể bắt chước chúng nếu cần thiết (ví dụ chứng chỉ SSL phía máy khách BASIC + với cn khớp với tên người dùng và ca gốc cụ thể).

Đồng thời, chúng tôi gặp phải nhiều chỉ trích chủ yếu từ đám đông phát triển và đôi khi từ dba, người nói với tôi rằng ứng dụng nên là rào cản bảo mật, không phải cơ sở dữ liệu. Quan điểm của tôi vẫn là một vành đai bảo mật nhỏ hơn thường tốt hơn, việc sử dụng lại logic kinh doanh và logic bảo mật đi đôi với nhau và nó gây nguy hiểm cho tôi khi sử dụng lại logic kinh doanh mà không sử dụng lại logic bảo mật ở cùng cấp độ của chương trình.

Tôi có bỏ lỡ bất kỳ sự đánh đổi lớn nào ở đây không? Có những vấn đề mà tôi không xem xét?


1
Đăng chéo vào danh sách gửi thư chung pssql. Xem chủ đề bắt đầu ở đây .
Craig Ringer

Câu trả lời:


17

Tôi nghĩ rằng bạn đang xác thựcủy quyền .

Tôi hoàn toàn đồng ý rằng việc giữ mô hình bảo mật trong DB là khôn ngoan, đặc biệt là khi LedgerSMB được thiết kế với sự truy cập từ nhiều khách hàng. Trừ khi bạn có kế hoạch đi 3 tầng với lớp phần mềm trung gian, sẽ rất hợp lý khi có người dùng làm vai trò cơ sở dữ liệu, đặc biệt là đối với một ứng dụng kế toán.

Điều này không có nghĩa là bạn phải xác thực người dùng dựa trên cơ sở dữ liệu bằng phương thức xác thực được PostgreSQL hỗ trợ. Người dùng cơ sở dữ liệu, vai trò và trợ cấp của bạn chỉ có thể được sử dụng để ủy quyền nếu bạn muốn.

Đây là cách nó hoạt động cho một web ui chẳng hạn:

  • janekết nối với máy chủ web ui và xác thực bằng bất kỳ phương thức nào mong muốn, nói bắt tay chứng chỉ ứng dụng khách HTTPS X.509 và xác thực DIGEST. Máy chủ hiện có kết nối từ người dùng mà nó chấp nhận là thực sự jane.

  • Máy chủ kết nối với PostgreSQL bằng tên người dùng / mật khẩu cố định (hoặc Kerberos hoặc bất cứ thứ gì bạn thích), xác thực chính nó với máy chủ db là người dùng webui. Máy chủ db tin tưởng webuiđể xác thực người dùng của nó vì vậy webuiđã được cung cấp GRANTs thích hợp (xem bên dưới).

  • Trên kết nối đó, máy chủ sử dụng SET ROLE jane;để đảm nhận mức ủy quyền của người dùng jane. Cho đến khi RESET ROLE;hoặc một cái khác SET ROLEđược chạy, kết nối đang hoạt động với quyền truy cập tương tự janeSELECT current_user()vv sẽ báo cáo jane.

  • Các máy chủ duy trì các mối liên hệ giữa các kết nối cơ sở dữ liệu mà nó có SET ROLEtới janevà phiên web cho người sử dụng jane, không cho phép kết nối PostgreSQL được sử dụng bởi các kết nối khác với những người dùng khác mà không có một mới SET ROLEInbetween.

Bạn đang chứng thực bên ngoài máy chủ, nhưng việc duy trì quyền trong máy chủ. PG cần biết những gì người dùng tồn tại, nhưng không cần mật khẩu hoặc phương thức xác thực cho họ.

Xem:

Chi tiết

Máy chủ webui kiểm soát các truy vấn chạy và nó sẽ không janechạy SQL thô (tôi hy vọng!) Vì vậy janekhông thể RESET ROLE; SET ROLE special_admin_user;thông qua web ui. Để an toàn hơn, tôi thêm bộ lọc câu lệnh vào máy chủ đã từ chối SET ROLERESET ROLEtrừ khi kết nối nằm trong hoặc nhập vào nhóm kết nối chưa được gán.

Bạn vẫn được tự do sử dụng xác thực trực tiếp để PG trong các máy khách khác; bạn có thể trộn và kết hợp tự do. Bạn chỉ cần GRANTnhững webuingười sử dụng quyền SET ROLEđể người dùng có thể đăng nhập qua web và sau đó cung cấp cho những người dùng bất kỳ bình thường CONNECTquyền, mật khẩu, vv mà bạn muốn. Nếu bạn muốn đặt chúng chỉ trên web, quyền REVOKEcủa chúng CONNECTtrên cơ sở dữ liệu (và từ public).

Để làm cho việc phân tách xác thực / ủy quyền dễ dàng như vậy, tôi có một vai trò đặc biệt assume_any_userGRANTmọi người dùng mới được tạo. Sau đó, tôi GRANT assume_any_userđến tên người dùng thực sự được sử dụng bởi những thứ như giao diện web đáng tin cậy, cho họ quyền trở thành bất kỳ người dùng nào họ thích.

Điều quan trọng là phải đảm assume_any_usermột NOINHERITvai trò, vì vậy webuingười sử dụng hay bất cứ điều gì không có privilges bởi tự nó và chỉ có thể hoạt động trên cơ sở dữ liệu khi nó đã SET ROLEcho một người dùng thực sự. Trong mọi trường hợp nên webuilà một siêu người dùng hoặc chủ sở hữu DB .

Nếu bạn kết nối nhóm, bạn chỉ có thể sử dụng SET LOCAL ROLEđể đặt vai trò trong một giao dịch, do đó bạn có thể trả lại kết nối cho nhóm sau COMMIThoặc ROLLBACK. Coi chừng RESET ROLEvẫn hoạt động, vì vậy vẫn không an toàn khi để máy khách chạy bất kỳ SQL nào họ muốn.

SET SESSION AUTHORIZATIONlà phiên bản liên quan nhưng mạnh hơn của lệnh này. Nó không yêu cầu thành viên vai trò, nhưng đó là một lệnh siêu người dùng. Bạn không muốn web của bạn kết nối như một siêu người dùng. Nó có thể được đảo ngược với RESET SESSION AUTHORIZATION, SET SESSION AUTHORIZATION DEFAULThoặc SET SESSION AUTHORIZATION theusernameđể lấy lại quyền superuser nên nó không phải là một rào cản an ninh đặc quyền-thả một trong hai.

Một lệnh hoạt động như thế SET SESSION AUTHORIZATIONnhưng không thể đảo ngược và sẽ hoạt động nếu bạn là thành viên vai trò nhưng không phải siêu người dùng sẽ rất tuyệt. Tại thời điểm này không có, nhưng bạn vẫn có thể tách biệt xác thực và ủy quyền khá tốt nếu bạn cẩn thận.

Ví dụ và giải thích

CREATE ROLE dbowner NOLOGIN;
CREATE TABLE test_table(x text);
INSERT INTO test_table(x) VALUES ('bork');
ALTER TABLE test_table OWNER TO dbowner;

CREATE ROLE assume_any_user NOINHERIT NOLOGIN;
CREATE ROLE webui LOGIN PASSWORD 'somepw' IN ROLE assume_any_user;

CREATE ROLE jane LOGIN PASSWORD 'somepw';
GRANT jane TO assume_any_user;
GRANT ALL ON TABLE test_table TO jane;

CREATE ROLE jim LOGIN PASSWORD 'somepw';
GRANT jim TO assume_any_user;

Bây giờ kết nối như webui. Lưu ý rằng bạn không thể làm bất cứ điều gì để test_tablemà bạn có thể SET ROLE đến janesau đó bạn có thể truy cập vào test_table:

$ psql -h 127.0.0.1 -U webui regress
Password for user webui:

regress=> SELECT session_user, current_user;
 session_user | current_user 
--------------+--------------
 webui        | webui
(1 row)



regress=> SELECT * FROM test_table;
ERROR:  permission denied for relation test_table

regress=> SET ROLE jane;
SET

regress=> SELECT session_user, current_user;
 session_user | current_user 
--------------+--------------
 webui        | jane
(1 row)

regress=> SELECT * FROM test_table;
  x   
------
 bork
(1 row)

Lưu ý rằng webui can SET ROLE tới jim, ngay cả khi đã SET ROLEd đến janevà mặc dù janechưa được GRANTed quyền giả định vai trò jim. SET ROLEđặt ID người dùng hiệu quả của bạn, nhưng nó không loại bỏ khả năng của bạn đối SET ROLEvới các vai trò khác, đó là một thuộc tính của vai trò bạn đã kết nối chứ không phải vai trò hiệu quả hiện tại của bạn. Do đó, bạn phải kiểm soát cẩn thận quyền truy cập vào các lệnh SET ROLERESET ROLE. AFAIK, không có cách nào để SET ROLEkết nối vĩnh viễn , thực sự trở thành người dùng mục tiêu, mặc dù điều đó chắc chắn sẽ rất tốt nếu có.

Đối chiếu:

$ psql -h 127.0.0.1 -U webui regress
Password for user webui:

regress=> SET ROLE jane;
SET

regress=> SET ROLE jim;
SET
regress=> SELECT session_user, current_user;
 session_user | current_user 
--------------+--------------
 webui        | jim
(1 row)

đến:

$ psql -h 127.0.0.1 -U jane regress
Password for user jane:

regress=> SET ROLE webui;
ERROR:  permission denied to set role "webui"
regress=> SET ROLE jim;
ERROR:  permission denied to set role "jim"

Điều này có nghĩa SET ROLElà không chính xác giống như đăng nhập như một vai trò nhất định, một điều bạn phải ghi nhớ.

webuiKhông SET ROLEthể dbownervì nó đã không GRANTđúng:

regress=> SET ROLE dbowner;
ERROR:  permission denied to set role "dbowner"

do đó, bản thân nó khá bất lực, nó chỉ có thể đảm nhận quyền của những người dùng khác và chỉ khi những người dùng đó có quyền truy cập web.


1
btw bạn có thể muốn xem làm thế nào để làm pgbouncerviệc cho một số chi tiết.
Craig Ringer

2
Ồ, DISCARD ALLlà một cách khác để các quyền được đưa trở lại mặc định. Tôi thực sự mong muốn PG có một SET ROLE NORESEThoặc tương tự ...
Craig Ringer
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.