การ Audit Log: บันทึกทุกการเปลี่ยนแปลงในฐานข้อมูล
ในบทที่แล้ว เราได้พูดถึง Two-Factor Authentication (2FA) เพื่อเพิ่มความปลอดภัยในการยืนยันตัวตนผู้ใช้งาน ในบทนี้ เราจะมาเรียนรู้เรื่อง Audit Log ซึ่งเป็นอีกหนึ่งเครื่องมือสำคัญในการรักษาความปลอดภัยและการตรวจสอบระบบของเรา Audit Log คือบันทึกการเปลี่ยนแปลงข้อมูลที่เกิดขึ้นในฐานข้อมูล ช่วยให้เราสามารถติดตามได้ว่าใคร ทำอะไร เมื่อไหร่ และที่ไหน การมี Audit Log ที่ดีจะช่วยให้เรา:
- ตรวจสอบย้อนหลัง: เมื่อเกิดปัญหา เช่น ข้อมูลถูกแก้ไขหรือลบโดยไม่ได้รับอนุญาต เราสามารถใช้ Audit Log เพื่อตรวจสอบหาสาเหตุและผู้กระทำ
- ปฏิบัติตามกฎหมายและข้อบังคับ: ในหลายอุตสาหกรรม มีข้อกำหนดทางกฎหมายให้ต้องมีการบันทึกการเปลี่ยนแปลงข้อมูลเพื่อการตรวจสอบ
- ปรับปรุงระบบ: การวิเคราะห์ Audit Log สามารถช่วยให้เราเข้าใจพฤติกรรมการใช้งานระบบและนำไปปรับปรุงให้ดีขึ้น
การสร้าง Audit Log Table
ขั้นตอนแรกในการใช้งาน Audit Log คือการสร้างตารางสำหรับเก็บข้อมูลการเปลี่ยนแปลง นี่คือตัวอย่างโครงสร้างตาราง Audit Log ใน MySQL:
CREATE TABLE audit_log (
id INT AUTO_INCREMENT PRIMARY KEY,
user_id INT,
action VARCHAR(255) NOT NULL,
table_name VARCHAR(255) NOT NULL,
record_id INT,
old_value TEXT,
new_value TEXT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
คำอธิบายแต่ละฟิลด์:
id: Primary key ของตาราง Audit Loguser_id: ID ของผู้ใช้ที่ทำการเปลี่ยนแปลง (Foreign Key อ้างอิงตาราง users)action: ประเภทของการกระทำ (เช่น 'CREATE', 'UPDATE', 'DELETE')table_name: ชื่อตารางที่เกิดการเปลี่ยนแปลงrecord_id: ID ของ record ที่ถูกเปลี่ยนแปลงold_value: ค่าเดิมของข้อมูลก่อนการเปลี่ยนแปลง (เก็บเป็น JSON หรือ String)new_value: ค่าใหม่ของข้อมูลหลังการเปลี่ยนแปลง (เก็บเป็น JSON หรือ String)created_at: วันและเวลาที่เกิดการเปลี่ยนแปลง
เหตุผลเชิงออกแบบ:
- การใช้
TEXTสำหรับold_valueและnew_valueช่วยให้เราสามารถเก็บข้อมูลขนาดใหญ่ได้ แต่ควรระวังเรื่อง performance หากมีการ query ข้อมูลจำนวนมาก - การเก็บ
old_valueและnew_valueเป็น JSON ทำให้เราสามารถเก็บข้อมูลที่ซับซ้อนได้ง่าย แต่ต้องระวังเรื่องความเข้ากันได้ของข้อมูล - การใช้
TIMESTAMP DEFAULT CURRENT_TIMESTAMPทำให้ระบบบันทึกเวลาที่เกิดการเปลี่ยนแปลงโดยอัตโนมัติ
การบันทึก User Action
เมื่อเรามีตาราง Audit Log แล้ว ขั้นตอนต่อไปคือการบันทึกการเปลี่ยนแปลงข้อมูลที่เกิดขึ้นในฐานข้อมูล นี่คือตัวอย่างการบันทึกการสร้าง, แก้ไข, และลบข้อมูล:
ตัวอย่าง: การบันทึกการสร้างข้อมูล (CREATE)
<?php
function createUser($pdo, $user_data) {
try {
$sql = "INSERT INTO users (username, email, password) VALUES (:username, :email, :password)";
$stmt = $pdo->prepare($sql);
$stmt->execute([
'username' => $user_data['username'],
'email' => $user_data['email'],
'password' => password_hash($user_data['password'], PASSWORD_DEFAULT)
]);
$user_id = $pdo->lastInsertId();
// บันทึก Audit Log
$audit_sql = "INSERT INTO audit_log (user_id, action, table_name, record_id, new_value) VALUES (:user_id, :action, :table_name, :record_id, :new_value)";
$audit_stmt = $pdo->prepare($audit_sql);
$audit_stmt->execute([
'user_id' => $_SESSION['user_id'], // สมมติว่ามี Session เก็บ user_id
'action' => 'CREATE',
'table_name' => 'users',
'record_id' => $user_id,
'new_value' => json_encode($user_data)
]);
return $user_id;
} catch (PDOException $e) {
// จัดการ Error
echo "Error: " . $e->getMessage();
return false;
}
}
?>
ตัวอย่าง: การบันทึกการแก้ไขข้อมูล (UPDATE)
<?php
function updateUser($pdo, $user_id, $user_data) {
try {
// ดึงข้อมูลเดิมก่อนแก้ไข
$sql_select = "SELECT * FROM users WHERE id = :id";
$stmt_select = $pdo->prepare($sql_select);
$stmt_select->execute(['id' => $user_id]);
$old_data = $stmt_select->fetch(PDO::FETCH_ASSOC);
$sql = "UPDATE users SET username = :username, email = :email WHERE id = :id";
$stmt = $pdo->prepare($sql);
$stmt->execute([
'username' => $user_data['username'],
'email' => $user_data['email'],
'id' => $user_id
]);
// บันทึก Audit Log
$audit_sql = "INSERT INTO audit_log (user_id, action, table_name, record_id, old_value, new_value) VALUES (:user_id, :action, :table_name, :record_id, :old_value, :new_value)";
$audit_stmt = $pdo->prepare($audit_sql);
$audit_stmt->execute([
'user_id' => $_SESSION['user_id'], // สมมติว่ามี Session เก็บ user_id
'action' => 'UPDATE',
'table_name' => 'users',
'record_id' => $user_id,
'old_value' => json_encode($old_data),
'new_value' => json_encode($user_data)
]);
return true;
} catch (PDOException $e) {
// จัดการ Error
echo "Error: " . $e->getMessage();
return false;
}
}
?>
ตัวอย่าง: การบันทึกการลบข้อมูล (DELETE)
<?php
function deleteUser($pdo, $user_id) {
try {
// ดึงข้อมูลเดิมก่อนลบ
$sql_select = "SELECT * FROM users WHERE id = :id";
$stmt_select = $pdo->prepare($sql_select);
$stmt_select->execute(['id' => $user_id]);
$old_data = $stmt_select->fetch(PDO::FETCH_ASSOC);
$sql = "DELETE FROM users WHERE id = :id";
$stmt = $pdo->prepare($sql);
$stmt->execute(['id' => $user_id]);
// บันทึก Audit Log
$audit_sql = "INSERT INTO audit_log (user_id, action, table_name, record_id, old_value) VALUES (:user_id, :action, :table_name, :record_id, :old_value)";
$audit_stmt = $pdo->prepare($audit_sql);
$audit_stmt->execute([
'user_id' => $_SESSION['user_id'], // สมมติว่ามี Session เก็บ user_id
'action' => 'DELETE',
'table_name' => 'users',
'record_id' => $user_id,
'old_value' => json_encode($old_data)
]);
return true;
} catch (PDOException $e) {
// จัดการ Error
echo "Error: " . $e->getMessage();
return false;
}
}
?>
ข้อควรระวัง:
- อย่าลืมจัดการ Error อย่างเหมาะสมเมื่อบันทึก Audit Log
- ควรบันทึก
user_idจาก Session หรือ Authentication token เพื่อระบุผู้ใช้งานที่ทำการเปลี่ยนแปลง - การเก็บข้อมูล
old_valueและnew_valueอาจทำให้ตาราง Audit Log มีขนาดใหญ่ได้ ควรพิจารณาการ archive ข้อมูลเก่า - การบันทึก Audit Log ทุกครั้งอาจทำให้ performance ลดลง ควรพิจารณาใช้ Asynchronous Task หรือ Queue เพื่อบันทึกข้อมูลใน background
การตรวจสอบ Audit Log
เมื่อเรามี Audit Log แล้ว เราสามารถใช้ SQL Query เพื่อตรวจสอบข้อมูลได้ ตัวอย่าง:
-- ดึงข้อมูล Audit Log ทั้งหมด
SELECT * FROM audit_log;
-- ดึงข้อมูล Audit Log ของผู้ใช้ ID 123
SELECT * FROM audit_log WHERE user_id = 123;
-- ดึงข้อมูล Audit Log ที่เกิดจากการแก้ไข (UPDATE) ตาราง users
SELECT * FROM audit_log WHERE action = 'UPDATE' AND table_name = 'users';
-- ดึงข้อมูล Audit Log ในช่วงเวลาที่กำหนด
SELECT * FROM audit_log WHERE created_at BETWEEN '2023-10-26 00:00:00' AND '2023-10-26 23:59:59';
แนวปฏิบัติที่ดี:
- สร้างหน้าจอสำหรับแสดง Audit Log ให้ผู้ดูแลระบบสามารถตรวจสอบได้ง่าย
- เพิ่มฟังก์ชันการค้นหาและกรองข้อมูลใน Audit Log
- กำหนดสิทธิ์การเข้าถึง Audit Log อย่างเข้มงวด
Audit Log เป็นเครื่องมือที่สำคัญในการรักษาความปลอดภัยและการตรวจสอบระบบของเรา การออกแบบและใช้งาน Audit Log อย่างถูกต้องจะช่วยให้เราสามารถติดตามและแก้ไขปัญหาที่เกิดขึ้นได้อย่างมีประสิทธิภาพ ในบทต่อไป เราจะพูดถึงการ Backup and Restore Database เพื่อป้องกันข้อมูลสูญหาย