CodeGym /Các khóa học /SQL SELF /Những lỗi thường gặp khi cấu hình bảo mật và cách phòng t...

Những lỗi thường gặp khi cấu hình bảo mật và cách phòng tránh

SQL SELF
Mức độ , Bài học
Có sẵn

"Bảo mật database giống như một mật khẩu mạnh: bạn có thể nghĩ ra một chuỗi siêu khó, nhưng nếu viết nó lên giấy dán lên màn hình thì cũng vô dụng thôi." Vậy nên nhiệm vụ của tụi mình là không chỉ biết cấu hình bảo vệ mà còn tránh mấy lỗi cơ bản có thể phá hỏng mọi nỗ lực.

1. Dùng role có quyền quá mức

Nhiều dev sợ bị hạn chế quyền nên tạo role với quyền rất rộng, ví dụ như cho SUPERUSER hoặc ALL PRIVILEGES. Lý do thường là: "Biết đâu sau này cần!". Nhưng role quyền quá lớn là lỗ hổng bảo mật to đùng luôn.

Ví dụ quyền quá mức:

GRANT ALL PRIVILEGES ON DATABASE university TO student_role;

Ở đây student_role được full quyền với mọi dữ liệu trong database. Dù role này chỉ nên đọc dữ liệu thôi, giờ nó có thể xóa bảng, sửa cấu trúc, thậm chí lấy quyền admin luôn.

Làm sao tránh?

Tạo role với quyền tối thiểu cần thiết. Đây gọi là nguyên tắc tối thiểu quyền hạn. Ví dụ, role chỉ để đọc dữ liệu nên như này:
GRANT CONNECT ON DATABASE university TO student_role;
GRANT SELECT ON ALL TABLES IN SCHEMA public TO student_role;

Cách này giúp xác định rõ student_role chỉ được làm gì: kết nối database và chỉ đọc dữ liệu thôi.

2. Không mã hóa dữ liệu nhạy cảm

Thử tưởng tượng bảng users lưu mật khẩu dạng plain text:

CREATE TABLE users (
    id SERIAL PRIMARY KEY,
    username TEXT NOT NULL,
    password TEXT NOT NULL
);

Nếu hacker lấy được bảng này, họ sẽ có hết mật khẩu của mọi user. Kiểu như để chìa khóa nhà dưới thảm vậy.

Để tránh chuyện này, hãy mã hóa mật khẩu bằng pgcrypto. Ví dụ:

CREATE EXTENSION IF NOT EXISTS pgcrypto;

INSERT INTO users (username, password)
VALUES ('johndoe', pgp_sym_encrypt('secure_password', 'encryption_key'));

Để kiểm tra mật khẩu thì giải mã như sau:

SELECT username
FROM users
WHERE pgp_sym_decrypt(password::BYTEA, 'encryption_key') = 'secure_password';

Đừng bao giờ lưu thông tin nhạy cảm ở dạng plain text nhé!

3. Bỏ qua SQL-injection

SQL-injection vẫn là một trong những kiểu tấn công phổ biến nhất, vì dev vẫn hay tạo query bằng cách ghép chuỗi. Ví dụ:

DO $$
DECLARE
    username TEXT := 'John';
    query TEXT;
BEGIN
    query := 'SELECT * FROM users WHERE username = ''' || username || ''';';
    EXECUTE query;
END $$;

Nếu hacker gửi username là John' OR '1'='1, kết quả là toàn bộ dữ liệu bảng users bị lộ hết.

Làm sao tránh? Dùng query có tham số:

PREPARE user_query (TEXT) AS
SELECT * FROM users WHERE username = $1;

EXECUTE user_query('John');

Ở đây biến được truyền vào an toàn, không lo injection nữa.

4. Cấu hình sai pg_hba.conf

pg_hba.conf là công cụ chính để kiểm soát truy cập theo IP. Cấu hình sai có thể khiến ai cũng vào được database.

Ví dụ cấu hình tệ:

host    all     all     0.0.0.0/0       trust

Dòng này cho phép bất kỳ ai kết nối bất kỳ database nào từ bất kỳ IP nào mà không cần mật khẩu.

Làm sao tránh? Chỉ cho phép IP cụ thể và dùng xác thực kiểu md5 hoặc scram-sha-256:

host    university    student_role    192.168.1.0/24    md5

Cách này chỉ cho student_role truy cập từ mạng nội bộ với mật khẩu.

Sau khi sửa pg_hba.conf, nhớ áp dụng thay đổi bằng lệnh:

pg_ctl reload

5. Dùng ROW LEVEL SECURITY sai cách

RLS mạnh thật, nhưng vô dụng nếu cấu hình sai hoặc quên bật. Ví dụ, viết policy rồi mà chưa bật RLS thì cũng như không:

CREATE POLICY my_policy ON users
USING (username = current_user);

-- Nhưng RLS chưa bật!
SELECT * FROM users; -- Thấy hết mọi dòng luôn!

Làm sao tránh? Nhớ bật RLS nhé:

ALTER TABLE users ENABLE ROW LEVEL SECURITY;

Và kiểm tra policy hoạt động chưa:

SET ROLE student_role;

SELECT * FROM users; -- Chỉ thấy dòng phù hợp với policy thôi.

6. Không kiểm soát hành động của admin

Đôi khi admin database có full quyền với mọi dữ liệu, dù không cần thiết cho công việc. Nếu tài khoản admin bị hack thì nguy cơ lộ dữ liệu rất cao.

Làm sao tránh? Tách role ra. Tạo role riêng cho admin mà không có quyền truy cập dữ liệu:

CREATE ROLE admin_role WITH LOGIN CREATEDB CREATEROLE;

Role truy cập dữ liệu thì tạo riêng, chỉ cho quyền tối thiểu:

CREATE ROLE data_analyst_role;
GRANT SELECT ON ALL TABLES IN SCHEMA public TO data_analyst_role;

Gán role cho user tùy theo nhiệm vụ:

GRANT admin_role TO some_user;
GRANT data_analyst_role TO another_user;

7. Ghi log không đủ

Nếu không cấu hình log, bạn sẽ không biết có gì bất thường cho đến khi quá muộn.

Ví dụ không ghi log:

-- Không có cấu hình trong file postgresql.conf
log_statement = 'none';

Làm sao tránh? Bật log cơ bản ít nhất là như này:

log_statement = 'all'
log_connections = on
log_disconnections = on

Như vậy bạn sẽ thấy mọi query, kết nối và ngắt kết nối.

Bạn cũng có thể audit chi tiết hơn bằng extension pgAudit:

CREATE EXTENSION pgaudit;

8. Dùng phương pháp xác thực lỗi thời

Dùng phương pháp xác thực cũ như password thì không đủ an toàn đâu.

Làm sao tránh? Chuyển sang phương pháp an toàn hơn như scram-sha-256:

ALTER SYSTEM SET password_encryption = 'scram-sha-256';

Và cập nhật mật khẩu cho user:

ALTER USER student_role WITH PASSWORD 'new_secure_password';

Những vấn đề này nghe có vẻ nhỏ, nhưng mỗi cái đều có thể thành lỗ hổng bảo mật nghiêm trọng. Nhiệm vụ của bạn là quản lý database như thể ai kết nối cũng đáng nghi. Như người ta nói, "tin thì tin, nhưng phải kiểm tra". Giờ bạn đã có công cụ để không chỉ cấu hình bảo mật mà còn tránh được mấy lỗi phổ biến nhất. Chúc bạn may mắn, dữ liệu luôn an toàn nhé!

1
Khảo sát/đố vui
, cấp độ , bài học
Không có sẵn
Giới thiệu về mã hóa dữ liệu
Giới thiệu về mã hóa dữ liệu
Bình luận
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION