Hướng dẫn bảo mật máy chủ PostgreSQL của bạn

PostgreSQL được coi là một trong những hệ quản trị cơ sở dữ liệu quan hệ - đối tượng mạnh mẽ và nâng cao nhất thế giới. Nó có khả năng mở rộng cao, có thể mở rộng và là một lựa chọn tuyệt vời để xử lý các tập dữ liệu lớn, đặc biệt là trong các môi trường sản xuất.

Tuy nhiên, các lỗ hổng bảo mật được ghi nhận theo cơ sở dữ liệu CVE khiến nó trở thành một mục tiêu dễ bị tấn công của hacker. Trong hướng dẫn này, chúng ta khám phá các biện pháp khác nhau mà bạn có thể thực hiện để củng cố bảo mật máy chủ PostgreSQL và thiết lập tường thuật chống lại các xâm phạm tiềm ẩn.

Khóa quyền truy cập cấp cổng vào PostgreSQL 

Quyền truy cập mạng vào cơ sở dữ liệu nên được giới hạn ở một vài cổng; chính cổng cơ sở dữ liệu (cổng 5432) và một cổng quản lý, tốt nhất là cổng SSH. Tất cả các cổng khác có quyền truy cập mạng nên được khóa để giảm bề mặt tấn công.

Do đó, việc triển khai tường lửa được khuyến nghị cao trên máy chủ chủ đang chạy máy chủ PostgreSQL. Một tường lửa cho phép bạn xác định lượng truy cập mạng đến hoặc đi được phép. Có nhiều cách khác nhau để thực hiện việc này bao gồm mở cổng PostgreSQL mặc định 5432 và xác định giao thức (IPv4 hoặc IPv6). Ngoài ra, bạn có thể đặt một địa chỉ nguồn hoặc một mạng con các máy chủ được phép truy cập vào máy chủ cơ sở dữ liệu.

Thông thường, các bản phân phối Linux hiện đại đi kèm với một ứng dụng tường lửa được cài sẵn để lọc lưu lượng truy cập. Đối với các phiên bản Debian / Ubuntu, chúng ta có UFW, trong khi Firewalld là tường lửa mặc định trong các bản phân phối Red Hat như RHEL, Fedora, Rocky Linux và AlmaLinux.

Trên các hệ thống Debian/Ubuntu chạy tường lửa UFW, cho phép lưu lượng truy cập đến trên cổng 5432 và 22 như sau: 

sudo ufw allow 5432/tcp

sudo ufw allow 22/tcp

Sau đó, tải lại tường lửa để áp dụng các thay đổi đã thực hiện.

sudo ufw reload

Trên các hệ thống chạy Firewalld như Red Hat, Fedora và Rocky, mở cổng 5432 và 22 như sau:

sudo firewalld --add-port=5432/tcp --zone=public --permanent 

sudo firewalld --add-port=22/tcp --zone=public --permanent

Sau đó, tải lại tường lửa để các thay đổi có hiệu lực. 

sudo firewalld --reload

Nếu bạn đang chạy tiện ích tường lửa Iptables, hãy chạy các lệnh sau để cho phép kết nối SSH và PostgreSQL tương ứng.

iptables -A INPUT -p tcp -m state --state NEW --dport 22 -j ACCEPT 

iptables -A INPUT -p tcp -m state --state NEW --dport 5432 -j ACCEPT

Tiếp theo, cho phép tất cả các kết nối đi và loại bỏ bất kỳ lưu lượng truy cập đến nào khác. 

iptables -A OUTPUT -j ACCEPT 

iptables -A INPUT -j DROP

iptables -A FORWARD -j DROP

Vô hiệu hóa truy cập từ xa vào PostgreSQL

Biện pháp này ngăn chặn một lượng lớn các vector tấn công khác bao gồm brute force và tấn công xen giữa. 

Để hạn chế truy cập vào localhost, hãy sửa đổi tệp postgresql.conf và đặt listen_addresses thành localhost.

Để truy cập vào tệp cấu hình, hãy chạy lệnh sau. Hãy chắc chắn thay 14 bằng số phiên bản của máy chủ cơ sở dữ liệu PostgreSQL đã cài đặt.

sudo vim /etc/postgresql/14/main/postgresql.conf

Tiếp theo, tìm chỉ thị listen_addresses và đặt nó thành localhost.

listen_addresses = 'localhost'

<Hình ảnh>

Sau đó, khởi động lại dịch vụ PostgreSQL để áp dụng thay đổi đã thực hiện. 

sudo systemctl restart postgresql

Cấu hình máy chủ được phép

Ngoài ra, bạn có thể cho phép các máy chủ cụ thể kết nối với máy chủ cơ sở dữ liệu thay vì hoàn toàn vô hiệu hóa các kết nối từ xa. Điều này đảm bảo rằng chỉ những người dùng được ủy quyền mới có thể kết nối với máy chủ cơ sở dữ liệu. 

Để làm được điều này, truy cập tệp pg_hba.conf.

sudo vim /etc/postgresql/14/main/pg_hba.conf

Dưới phần chú thích mô tả cách cho phép các kết nối không phải cục bộ, hãy chèn một mục bao gồm địa chỉ IP công cộng của máy chủ cơ sở dữ liệu cùng với cơ sở dữ liệu và người dùng được phép truy cập vào cơ sở dữ liệu.

host sample_db cherry client_ip_address/24 md5

<Hình ảnh>

Hãy xem xét các giá trị chi tiết.

Thuộc tính host cho biết rằng một kết nối TCP/IP sẽ được sử dụng để kết nối với cơ sở dữ liệu.

Mục sample_db chỉ định cơ sở dữ liệu mà người dùng sẽ kết nối. Nhiều cơ sở dữ liệu có thể được chỉ định bằng cách phân tách các tên cơ sở dữ liệu bằng dấu phẩy.

Mục cherry cho biết người dùng được phép thực hiện kết nối. Và giống như tên cơ sở dữ liệu, nhiều người dùng có thể được chỉ định bằng cách phân tách tên của họ bằng dấu phẩy. 

Mục client_ip_address là địa chỉ IP công cộng của máy khách đang kết nối với máy chủ.

Một khi hoàn tất, lưu và thoát khỏi tệp. Sau đó, chỉnh sửa tệp postgresql.conf.

sudo vim /etc/postgresql/14/main/postgresql.conf

Tìm dòng listen_addresses và chỉ định địa chỉ IP công cộng của máy chủ cơ sở dữ liệu của bạn được biểu thị bằng thuộc tính server-ip

listen_addresses = 'localhost, server-ip'

Một khi hoàn tất, lưu các thay đổi và đóng tệp. Sau đó, khởi động lại PostgreSQL để các thay đổi có hiệu lực.

sudo systemctl restart postgresql

Quản lý thích hợp người dùng và nhóm vai trò

Cho đến nay, chúng ta đã xem xét cách bạn có thể bảo mật PostgreSQL ở cấp mạng. Ở cấp độ cơ sở dữ liệu, bạn cũng có thể củng cố máy chủ của mình bằng cách gán đặc quyền thích hợp cho người dùng và vai trò. 

Trong bảo mật thông tin, quy tắc vàng là luôn áp dụng nguyên tắc đặc quyền tối thiểu. Điều này ngụ ý cấp cho người dùng chỉ đúng số lượng quyền cần thiết để hoàn thành nhiệm vụ.

Cùng áp dụng cho quản lý người dùng và vai trò. Người dùng nên được cấp các đặc quyền tối thiểu không cho phép quá nhiều quyền truy cập.

Người dùng, vai trò và nhóm đồng nghĩa trong PostgreSQL, với sự khác biệt duy nhất là người dùng có quyền đăng nhập theo mặc định. Để cụ thể hơn, người dùng là một vai trò với đặc quyền KẾT NỐI.

Cả các câu lệnh CREATE USERCREATE ROLE đều có thể được sử dụng để tạo người dùng. Tuy nhiên, người dùng phải có vai trò LOGIN. Khi được tạo bằng câu lệnh CREATE USER, người dùng được tự động cấp vai trò LOGIN.

Ví dụ: trong lệnh SQL sau, vai trò LOGIN được gán cho người dùng cherry_user

CREATE USER cherry_user WITH ENCRYPTED PASSWORD

Sau khi tạo người dùng hoặc vai trò, hãy gọi câu truy vấn SQL sau để xác minh xem người dùng có thể đăng nhập hay không.

SELECT rolcanlogin from pg_roles where rolname = 'cherry_user';

<hình ảnh>

Đầu ra trả về một giá trị boolean cho biết liệu người dùng có thể đăng nhập hay không. Giá trị t cho thấy người dùng có thể đăng nhập và f cho thấy ngược lại.

Tuy nhiên, khi bạn tạo một người dùng bằng câu lệnh CREATE ROLE, bạn phải rõ ràng thêm thuộc tính LOGIN để cho phép người dùng đăng nhập.

CREATE ROLE cherry_user LOGIN;

Các vai trò trong PostgreSQL

Một vai trò xác định một người dùng, một nhóm hoặc một tập hợp các quyền được gán cho một nhóm hoặc người dùng cho các đối tượng khác nhau trong cơ sở dữ liệu. Đó là một thực thể có thể có các đặc quyền cơ sở dữ liệu và sở hữu các đối tượng cơ sở dữ liệu.

Các câu lệnh CREATE USERCREATE GROUP đã được thay thế bởi câu lệnh chung hơn, CREATE ROLE với các thuộc tính cụ thể để phân biệt người dùng cơ sở dữ liệu.

Một người dùng cơ sở dữ liệu là một vai trò với đặc quyền LOGIN theo mặc định. Người dùng postgres là người dùng cơ sở dữ liệu có đặc quyền cao nhất trong máy chủ PostgreSQL. Nó sở hữu một đặc quyền đặc biệt được gọi là SUPERUSER trao cho nó quyền truy cập không hạn chế vào cơ sở dữ liệu, giống như tài khoản root trên Linux.

Các thuộc tính của vai trò 

Các thuộc tính vai trò là các chỉ thị trên bản thân vai trò đó xác định một số đặc quyền cốt lõi mà nó có ở cấp độ cơ sở dữ liệu. Thuộc tính có thể được chỉ định khi tạo vai trò, hoặc sửa đổi sau này.

Ví dụ về các thuộc tính vai trò có thể được áp dụng cho một vai trò bao gồm:

LOGIN: Cho phép người dùng cơ sở dữ liệu kết nối với cụm cơ sở dữ liệu. Như chúng ta đã thấy trước đó, câu lệnh CREATE USER tự động thêm thuộc tính này, trong khi lệnh CREATE ROLE thì không. 

CREATEDB: Thuộc tính cho phép vai trò tạo các cơ sở dữ liệu mới.

CREATEROLE: Điều này cho phép vai trò tạo, thay đổi và xóa các vai trò khác. Ngoài ra, nó cho phép vai trò gán hoặc thay đổi thành viên vai trò. Ngoại lệ duy nhất là vai trò với thuộc tính CREATEROLE không thể thay đổi các vai trò SUPERUSER mà không có thuộc tính SUPERUSER

SUPERUSER: Cho phép vai trò bỏ qua tất cả các kiểm tra quyền ngoại trừ quyền đăng nhập. Lưu ý rằng chỉ có các vai trò SUPERUSER mới có thể tạo các vai trò với thuộc tính này.

REPLICATION: Cho phép vai trò khởi động sao chép luồng. Các vai trò với thuộc tính này cũng phải mang thuộc tính LOGIN

INHERIT: Xác định liệu vai trò có thể kế thừa các đặc quyền của các vai trò mà nó là thành viên hay không.

Để xem các vai trò và các thuộc tính vai trò được gán cho người dùng, hãy chạy truy vấn sau.

\du

<Hình ảnh>

Từ đầu ra, bạn có thể thấy rằng postgres có một danh sách các vai trò cơ sở dữ liệu bao gồm vai trò superuser cung cấp cho nó quyền truy cập không hạn chế vào cơ sở dữ liệu.


Cấp quyền cho vai trò 

Thay vì gán quyền truy cập cho từng người dùng / vai trò một cách riêng lẻ, cách tiếp cận được khuyến nghị nhất là tạo một vai trò nhóm và cấp cho các vai trò khác (ánh xạ người dùng cá nhân) quyền thành viên của nhóm này.

Để minh họa điều này, chúng ta có một bảng gọi là database_inventory chứa các bản ghi về các máy chủ cơ sở dữ liệu được quản lý bởi các quản trị hệ thống khác nhau.

Dưới đây là sơ đồ bảng.

CREATE TABLE database_inventory (

  os text,

    description text,

    ip_address text,

    staff text

  );

Chúng ta đã thêm một số bản ghi, và bảng trông như thế này.

<Hình ảnh>

Giả sử bạn muốn cho phép các quản trị viên hệ thống của bạn, ví dụ Mike, Bob và Alice xem bảng nhưng không được sửa đổi nó.

Thay vì gán quyền xem bảng cho từng người dùng một cách riêng lẻ, đây là cách bạn sẽ thực hiện:

Đầu tiên, tạo một vai trò nhóm không có khả năng đăng nhập và sau đó cấp cho nó quyền SELECT trên schema.

CREATE ROLE sysadmins;

GRANT SELECT ON database_inventory TO sysadmins;

<Hình ảnh>

Tiếp theo, tạo ba tài khoản người dùng sẽ kế thừa quyền sysadmins một khi đăng nhập vào cơ sở dữ liệu.

CREATE USER bob WITH ENCRYPTED PASSWORD 'P@ss321';

CREATE USER mike WITH ENCRYPTED PASSWORD 'P@ss321';

CREATE USER alice WITH ENCRYPTED PASSWORD 'P@ss321';

<Hình ảnh>

Cuối cùng, gán vai trò sysadmins cho các tài khoản người dùng. 


GRANT sysadmins TO bob, mike, alice;

Một khi kết nối với cơ sở dữ liệu, Bob, Mike và Alice sẽ kế thừa các đặc quyền của nhóm vai trò "sysadmins" và có thể xem các bản ghi trong bảng database_inventory nhưng không thể sửa đổi nó.

Để kiểm tra điều này, chúng ta sẽ chuyển sang một người dùng có tên 'bob' và xem bảng bằng câu lệnh SELECT

SELECT * FROM database_inventory;

<Hình ảnh>

Truy vấn trên sẽ in ra toàn bộ bảng. Bất kỳ nỗ lực nào để cập nhật các bản ghi trong bảng đều dẫn đến lỗi vì người dùng chỉ có quyền chỉ đọc trên bảng.

Bảo mật cấp hàng (row-level)

Ngoài việc cấp quyền hoặc quyền cho người dùng trên các bảng, bạn có thể thực hiện các chính sách chặt chẽ hơn ở cấp hàng. Bảo mật cấp hàng (Row Level Security - RLS) là một cơ chế bảo mật kiểm soát quyền truy cập vào các hàng trong bảng cơ sở dữ liệu dựa trên quyền ủy quyền hiện tại của người dùng. 

Các bản ghi từ các bảng được hiển thị dựa trên người dùng là ai và người dùng đó có quyền truy cập vào những bản ghi nào. Mục đích của Bảo mật cấp hàng là cho phép người dùng cụ thể truy cập vào dữ liệu của riêng họ mà không cấp quyền xem hoặc sửa đổi bản ghi của người dùng khác. 

Để minh họa khái niệm Bảo mật cấp hàng, chúng ta sẽ xây dựng trên ví dụ bảng trước đó. Đầu tiên, bạn cần bật Bảo mật cấp hàng trên bảng.

ALTER TABLE database_inventory ENABLE ROW LEVEL SECURITY;

Tiếp theo, chúng ta sẽ tạo một chính sách có tên modify_servers sẽ hạn chế người dùng chỉ có thể xem các bản ghi của họ dựa trên trường staff trong bảng. Từ khóa SELECT cấp quyền cho người dùng truy vấn các bản ghi của riêng họ. Biểu thức USING so sánh tên người dùng đã đăng nhập hiện tại với cột staff trong bảng.

CREATE POLICY modify_servers on database_inventory FOR SELECT TO sysadmins USING (staff = current_user)

Để kiểm tra các chính sách của chúng ta, chúng ta sẽ chuyển sang một trong những người dùng cơ sở dữ liệu, trong trường hợp này là bob

\c postgres bob

Khi người dùng truy vấn toàn bộ bảng, anh ấy chỉ xem được bản ghi của mình chứ không phải của người dùng khác. Điều tương tự cũng xảy ra với những người dùng khác. Họ chỉ có thể truy cập các bản ghi thuộc về họ dựa trên các chính sách đã áp dụng.

<Hình ảnh>

Cập nhật bản vá thường xuyên

Theo quy tắc chung, việc áp dụng các bản cập nhật và bản vá bảo mật quan trọng được khuyến nghị cho các ứng dụng phần mềm. Điều này giải quyết các lỗ hổng và lỗ hổng bảo mật có thể bị khai thác để để có được quyền truy cập vào cơ sở dữ liệu. Ngoài ra, việc cập nhật các bản cập nhật bảo mật là điều kiện tiên quyết trong tuân thủ PCI-DSS nếu ứng dụng web dựa trên PostgreSQL của bạn lưu trữ dữ liệu thẻ tín dụng.

Kết luận

Trong hướng dẫn này, chúng ta đã xem xét các cấp độ khác nhau của việc giải quyết bảo mật cơ sở dữ liệu. Chúng ta đã xem xét bảo mật cấp mạng bao gồm triển khai tường lửa và socket TCP/IP, bảo mật cấp vận chuyển cho phép giao tiếp an toàn bằng SSL/TLS và cuối cùng, bảo mật cấp cơ sở dữ liệu liên quan đến việc gán quyền cho người dùng bằng cách sử dụng vai trò và quyền cùng với bảo mật cấp hàng.

Comments

Popular posts from this blog

So sánh SQLite và MySQL: 5 điểm khác biệt quan trọng

Windows VPS là gì? Hướng dẫn cơ bản nhất dành cho người mới bắt đầu năm 2024