PostgreSQL
 sql >> Cơ Sở Dữ Liệu >  >> RDS >> PostgreSQL

Các chế độ xem PostgreSQL security_barrier hoạt động như thế nào?

Bạn có thể đã thấy hỗ trợ được thêm vào cho security_barrier các khung nhìn trong PostgreSQL 9.2. Tôi đã xem xét mã đó với mục đích bổ sung hỗ trợ cập nhật tự động cho chúng như một phần của quá trình tiến triển công việc bảo mật cấp hàng cho dự án AXLE và tôi nghĩ mình sẽ nhân cơ hội giải thích cách chúng hoạt động.

Robert đã giải thích lý do tại sao chúng hữu ích và những gì chúng bảo vệ chống lại. (Hóa ra nó cũng được thảo luận trong phần có gì mới trong 9.2). Bây giờ tôi muốn đi sâu vào cách thức họ làm việc và thảo luận về cách security_barrier các chế độ xem tương tác với các chế độ xem có thể cập nhật tự động.

Chế độ xem thông thường

Chế độ xem đơn giản thông thường được mở rộng theo kiểu giống macro như một truy vấn con, sau đó thường được tối ưu hóa bằng cách kéo vị từ lên và nối nó vào các quals của truy vấn chứa. Điều đó có thể có ý nghĩa hơn với một ví dụ.

CREATE TABLE t AS SELECT n, 'secret'||n AS secret FROM generate_series(1,20) n;

và xem:

CREATE VIEW t_odd AS SELECT n, secret FROM t WHERE n % 2 = 1;

một truy vấn như:

SELECT * FROM t_odd WHERE n < 4

được mở rộng chế độ xem bên trong trình ghi lại truy vấn thành biểu diễn cây phân tích cú pháp của một truy vấn như:

SELECT * FROM (SELECT * FROM t WHERE n % 2 = 1) t_odd WHERE n < 4

mà sau đó trình tối ưu hóa sẽ biến thành một truy vấn truyền đơn bằng cách loại bỏ truy vấn con và thêm vào WHERE điều khoản mệnh đề cho truy vấn bên ngoài, tạo ra:

SELECT * FROM t t_odd WHERE (n % 2 = 1) AND (n < 4)

Mặc dù bạn không thể nhìn thấy các truy vấn trung gian trực tiếp và chúng không bao giờ tồn tại dưới dạng SQL thực, bạn có thể quan sát quá trình này bằng cách bật debug_print_parse =on , debug_print_rewritten =on debug_print_plan =on trong postgresql.conf . Tôi sẽ không tạo lại các cây phân tích cú pháp và lập kế hoạch ở đây vì chúng khá lớn và dễ tạo dựa trên các ví dụ ở trên.

Vấn đề với việc sử dụng các chế độ xem để bảo mật

Bạn có thể nghĩ rằng việc cấp cho ai đó quyền truy cập vào dạng xem mà không cấp cho họ quyền truy cập vào bảng bên dưới sẽ khiến họ không nhìn thấy các hàng được đánh số chẵn. Ban đầu có vẻ như điều đó đúng:

regress=> SELECT * FROM t_odd WHERE n < 4;
 n | secret  
---+---------
 1 | secret1
 3 | secret3
(2 rows)

nhưng khi nhìn vào kế hoạch, bạn có thể thấy một vấn đề tiềm ẩn:

regress=> EXPLAIN SELECT * FROM t_odd WHERE n < 4;
                    QUERY PLAN                     
---------------------------------------------------
 Seq Scan on t  (cost=0.00..31.53 rows=2 width=36)
   Filter: ((n < 4) AND ((n % 2) = 1))
(2 rows)

Truy vấn phụ của chế độ xem đã được tối ưu hóa, với các bộ định lượng của chế độ xem được nối trực tiếp vào truy vấn bên ngoài.

Trong SQL, AND HOẶC không được đặt hàng. Trình tối ưu hóa / người thực thi có thể tự do chạy bất kỳ nhánh nào mà họ cho rằng có nhiều khả năng đưa ra câu trả lời nhanh cho họ và có thể để họ tránh chạy các nhánh khác. Vì vậy, nếu người lập kế hoạch cho rằng n <4 nhanh hơn nhiều so với n% 2 =1 nó sẽ đánh giá điều đó đầu tiên. Có vẻ vô hại, phải không? Hãy thử:

regress=> CREATE OR REPLACE FUNCTION f_leak(text) RETURNS boolean AS $$
BEGIN
  RAISE NOTICE 'Secret is: %',$1;
  RETURN true;
END;
$$ COST 1 LANGUAGE plpgsql;

regress=> SELECT * FROM t_odd WHERE f_leak(secret) AND n < 4;
NOTICE:  Secret is: secret1
NOTICE:  Secret is: secret2
NOTICE:  Secret is: secret3
NOTICE:  Secret is: secret4
NOTICE:  Secret is: secret5
NOTICE:  Secret is: secret6
NOTICE:  Secret is: secret7
NOTICE:  Secret is: secret8
NOTICE:  Secret is: secret9
NOTICE:  Secret is: secret10
NOTICE:  Secret is: secret11
NOTICE:  Secret is: secret12
NOTICE:  Secret is: secret13
NOTICE:  Secret is: secret14
NOTICE:  Secret is: secret15
NOTICE:  Secret is: secret16
NOTICE:  Secret is: secret17
NOTICE:  Secret is: secret18
NOTICE:  Secret is: secret19
NOTICE:  Secret is: secret20
 n | secret  
---+---------
 1 | secret1
 3 | secret3
(2 rows)

regress=> EXPLAIN SELECT * FROM t_odd WHERE f_leak(secret) AND n < 4;
                        QUERY PLAN                        
----------------------------------------------------------
 Seq Scan on t  (cost=0.00..34.60 rows=1 width=36)
   Filter: (f_leak(secret) AND (n < 4) AND ((n % 2) = 1))
(2 rows)

Rất tiếc! Như bạn có thể thấy, chức năng vị ngữ do người dùng cung cấp được coi là chạy rẻ hơn so với các thử nghiệm khác, vì vậy, nó đã được vượt qua mọi hàng trước khi vị ngữ của chế độ xem loại trừ nó. Một hàm độc hại có thể sử dụng thủ thuật tương tự để sao chép hàng.

security_barrier lượt xem

security_barrier các chế độ xem khắc phục điều đó bằng cách buộc các bộ định tính trên chế độ xem phải được thực thi trước, trước khi bất kỳ bộ định tính nào do người dùng cung cấp chạy. Thay vì mở rộng chế độ xem và nối bất kỳ bộ định nghĩa chế độ xem nào vào truy vấn bên ngoài, chúng thay thế tham chiếu đến chế độ xem bằng một truy vấn con. Truy vấn con này có security_barrier cờ được đặt trên mục nhập bảng phạm vi của nó, điều này cho trình tối ưu hóa biết rằng nó không nên làm phẳng truy vấn con hoặc đẩy các điều kiện truy vấn bên ngoài xuống như đối với truy vấn con thông thường.

Vì vậy, với chế độ xem hàng rào bảo mật:

CREATE VIEW t_odd_sb WITH (security_barrier) AS SELECT n, secret FROM t WHERE n % 2 = 1;

chúng tôi nhận được:

regress=> SELECT * FROM t_odd_sb WHERE f_leak(secret) AND n < 4;
NOTICE:  Secret is: secret1
NOTICE:  Secret is: secret3
 n | secret  
---+---------
 1 | secret1
 3 | secret3
(2 rows)

regress=> EXPLAIN SELECT * FROM t_odd_sb WHERE f_leak(secret) AND n < 4;
                          QUERY PLAN                           
---------------------------------------------------------------
 Subquery Scan on t_odd_sb  (cost=0.00..31.55 rows=1 width=36)
   Filter: f_leak(t_odd_sb.secret)
   ->  Seq Scan on t  (cost=0.00..31.53 rows=2 width=36)
         Filter: ((n < 4) AND ((n % 2) = 1))
(4 rows)

Kế hoạch truy vấn sẽ cho bạn biết điều gì đang xảy ra, mặc dù nó không hiển thị thuộc tính hàng rào bảo mật trong đầu ra giải thích. Truy vấn con lồng nhau buộc quét trên t với bộ định lượng chế độ xem, thì hàm do người dùng cung cấp sẽ chạy trên kết quả của truy vấn con.

Nhưng. Đợi một giây. Tại sao vị từ do người dùng cung cấp lại là n <4 cũng bên trong truy vấn con? Đó có phải là một lỗ hổng bảo mật tiềm ẩn không? Nếu n <4 bị đẩy xuống, tại sao lại không f_leak (bí mật) ?

CHỐNG THẤM toán tử và chức năng

Lời giải thích cho điều đó là < toán tử được đánh dấu LEAKPROOF . Thuộc tính này cho biết rằng một toán tử hoặc hàm được tin cậy để không làm rò rỉ thông tin, vì vậy nó có thể được đẩy xuống một cách an toàn thông qua security_barrier lượt xem. Vì những lý do rõ ràng, bạn không thể đặt LEAKPROOF như một người dùng bình thường:

regress=> ALTER FUNCTION f_leak(text)  LEAKPROOF;
ERROR:  only superuser can define a leakproof function

và siêu người dùng đã có thể làm bất cứ điều gì họ muốn, vì vậy họ không cần phải dùng đến các thủ thuật với các chức năng làm rò rỉ thông tin để vượt qua hàng rào bảo mật.

Tại sao bạn không thể cập nhật security_barrier lượt xem

Các chế độ xem đơn giản trong PostgreSQL 9.3 có thể tự động cập nhật, nhưng security_barrier lượt xem không được coi là "đơn giản". Đó là vì việc cập nhật chế độ xem dựa vào việc có thể làm phẳng truy vấn con của chế độ xem, biến cập nhật thành một cập nhật đơn giản trên bảng. Toàn bộ điểm của security_barrier quan điểm là để ngăn chặn làm phẳng đó. CẬP NHẬT hiện không thể hoạt động trực tiếp trên một truy vấn con, vì vậy PostgreSQL sẽ từ chối mọi nỗ lực cập nhật security_barrier xem:

regress=> UPDATE t_odd SET secret = 'secret_haha'||n;
UPDATE 10
regress=> UPDATE t_odd_sb SET secret = 'secret_haha'||n;
ERROR:  cannot update view "t_odd_sb"
DETAIL:  Security-barrier views are not automatically updatable.
HINT:  To enable updating the view, provide an INSTEAD OF UPDATE trigger or an unconditional ON UPDATE DO INSTEAD rule.

Đó là hạn chế mà tôi muốn dỡ bỏ như một phần của công việc để tăng cường bảo mật cấp hàng cho dự án AXLE. Kohei KaiGai đã thực hiện một số công việc tuyệt vời với bảo mật cấp hàng và các tính năng như security_barrier LEAKPROOF phần lớn đã phát sinh từ công việc của anh ấy nhằm tăng cường bảo mật cấp độ hàng cho PostgreSQL. Thách thức tiếp theo là làm thế nào để đối phó với các bản cập nhật trên hàng rào bảo mật một cách an toàn và theo cách có thể bảo trì trong tương lai.

Tại sao lại là truy vấn phụ?

Bạn có thể tự hỏi tại sao chúng ta phải sử dụng truy vấn con cho việc này. Tôi đã làm. Phiên bản ngắn là chúng tôi không cần phải làm như vậy, nhưng nếu chúng tôi không sử dụng truy vấn phụ, thay vào đó chúng tôi phải tạo các biến thể phân biệt thứ tự mới của AND HOẶC và dạy cho trình tối ưu hóa rằng nó không thể di chuyển các điều kiện trên chúng. Vì các chế độ xem đã được mở rộng dưới dạng truy vấn con, nên sẽ ít phức tạp hơn nhiều nếu chỉ gắn cờ các truy vấn phụ là hàng rào chặn kéo lên / đẩy xuống.

Tuy nhiên, đã có một hoạt động có thứ tự chập mạch trong PostgreSQL - CASE . Sự cố khi sử dụng CASE điều đó không các hoạt động có thể được di chuyển qua ranh giới của một CASE , thậm chí LEAKPROOF những cái. Trình tối ưu hóa cũng không thể đưa ra quyết định sử dụng chỉ mục dựa trên các biểu thức bên trong CASE kỳ hạn. Vì vậy, nếu chúng tôi sử dụng CASE như tôi đã hỏi về on -hackers, chúng tôi không bao giờ có thể sử dụng chỉ mục để đáp ứng tiêu chuẩn định tính do người dùng cung cấp.

Trong mã

security_barrier hỗ trợ đã được thêm vào 0e4611c0234d89e288a53351f775c59522baed7c . Nó được tăng cường hỗ trợ chống rò rỉ trong cd30728fb2ed7c367d545fc14ab850b5fa2a4850 . Tín dụng xuất hiện trong ghi chú cam kết. Cảm ơn tất cả mọi người đã tham gia.

Hình ảnh tính năng trang nhất là Security Barrier của Craig A. Rodway, trên Flikr

Nghiên cứu dẫn đến những kết quả này đã nhận được tài trợ từ Chương trình khung thứ bảy của Liên minh Châu Âu (FP7 / 2007-2013) theo thỏa thuận tài trợ số 318633


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Cài đặt và kết nối với PostgreSQL 10 trên Ubuntu 16.04

  2. Làm thế nào để liệt kê các bản ghi có ngày từ 10 ngày qua?

  3. Làm cách nào để bạn thay đổi mã hóa ký tự của cơ sở dữ liệu postgres?

  4. PostgreSQL 12:Khóa ngoại và bảng phân vùng

  5. Không thể trừ các ngày giờ có nhận biết bù trừ và bù trừ