29 ส.ค. 2568·อ่าน 1 นาที

ร่องรอยการตรวจสอบที่ตรวจจับการปลอมแปลงใน PostgreSQL ด้วยการเชนแฮช

เรียนรู้การสร้างร่องรอยการตรวจสอบที่ตรวจจับการปลอมแปลงใน PostgreSQL โดยใช้ตารางแบบ append-only และการเชนแฮช เพื่อให้การแก้ไขค้นพบได้ง่ายเมื่อมีการตรวจสอบหรือสืบสวน

ร่องรอยการตรวจสอบที่ตรวจจับการปลอมแปลงใน PostgreSQL ด้วยการเชนแฮช

ทำไมล็อกการตรวจสอบปกติถึงถูกโต้แย้งได้ง่าย

ร่องรอยการตรวจสอบ (audit trail) คือบันทึกที่คุณใช้เมื่อมีสิ่งผิดปกติ: การคืนเงินที่แปลกไหม, การเปลี่ยนสิทธิ์ที่ไม่มีใครจำได้, หรือระเบียนลูกค้าที่ “หายไป” หากร่องรอยนั้นแก้ไขได้ มันจะเลิกเป็นพยานหลักฐานและกลายเป็นข้อมูลชิ้นหนึ่งที่ใครก็สามารถเขียนทับได้

หลายระบบที่เรียกว่า “ล็อกการตรวจสอบ” แท้จริงแล้วเป็นแค่ตารางปกติ ถ้าบรรทัดสามารถอัปเดตหรือลบได้ เรื่องราวก็ถูกแก้ไขหรือลบตามไปด้วย

ความแตกต่างสำคัญ: การบล็อกการแก้ไขไม่เหมือนกับการทำให้การแก้ไขตรวจจับได้ คุณลดการเปลี่ยนแปลงได้ด้วยสิทธิ์ แต่ใครก็ตามที่มีสิทธิ์เพียงพอ (หรือข้อมูลการเข้าถึงของแอดมินที่ถูกขโมย) ยังคงเปลี่ยนประวัติได้ การทำให้การแก้ไขตรวจจับได้ยอมรับความจริงข้อนั้นไว้ — คุณอาจไม่ป้องกันการเปลี่ยนแปลงทั้งหมด แต่คุณทำให้การเปลี่ยนแปลงทิ้งลายนิ้วมือที่ชัดเจน

ล็อกการตรวจสอบปกติมักถูกโต้แย้งด้วยเหตุผลที่คาดเดาได้ ผู้ใช้ที่มีสิทธิพิเศษสามารถ “แก้ไข” บันทึกหลังเหตุการณ์ได้ บัญชีแอปที่ถูกแฮ็กสามารถเขียนรายการที่น่าเชื่อได้ที่ดูเป็นทราฟฟิกปกติ เวลาสามารถถูกเติมย้อนหลังเพื่อซ่อนการเปลี่ยนแปลง หรือบางคนอาจลบเฉพาะบรรทัดที่เป็นอันตรายที่สุด

“ตรวจจับการปลอมแปลง” หมายความว่าคุณออกแบบร่องรอยการตรวจสอบให้แม้แต่การแก้ไขเล็กน้อย (เปลี่ยนฟิลด์หนึ่ง ฟ้าถอนแถวหนึ่ง หรือเรียงลำดับเหตุการณ์ใหม่) ก็สามารถตรวจพบได้ภายหลัง คุณไม่ได้สัญญาว่าจะมีเวทมนตร์ แต่สัญญาว่าเมื่อมีคนถามว่า “เรารู้ได้อย่างไรว่าล็อกนี้เป็นของจริง?” คุณจะสามารถรันการตรวจสอบที่แสดงว่าล็อกถูกแตะต้องหรือไม่

ตัดสินใจว่าคุณต้องพิสูจน์อะไร

ร่องรอยการตรวจสอบที่ตรวจจับการปลอมแปลงมีประโยชน์เฉพาะเมื่อมันตอบคำถามที่คุณจะเจอในภายหลัง: ใครทำอะไร, เมื่อใด, และอะไรที่ถูกเปลี่ยน

เริ่มจากเหตุการณ์ที่สำคัญต่อธุรกิจของคุณ การเปลี่ยนแปลงข้อมูล (สร้าง อัปเดต ลบ) เป็นพื้นฐาน แต่การสืบสวนมักขึ้นอยู่กับความปลอดภัยและการเข้าถึงเช่นกัน: การเข้าสู่ระบบ, รีเซ็ตรหัสผ่าน, การเปลี่ยนสิทธิ์, และการล็อกบัญชี หากคุณจัดการการชำระเงิน ควรถือการเคลื่อนไหวของเงินเป็นอีเวนต์สำคัญ ไม่ใช่ผลพลอยได้จากการอัปเดตแถว

จากนั้นตัดสินใจว่าอะไรทำให้อีเวนต์น่าเชื่อถือ ผู้ตรวจสอบมักคาดหวังตัวดำเนินการ (ผู้ใช้หรือบริการ), เวลาเซิร์ฟเวอร์, การกระทำที่ทำ, และวัตถุที่ถูกกระทบ สำหรับการอัปเดต ให้เก็บค่าก่อนและหลัง (หรืออย่างน้อยฟิลด์ที่ละเอียดอ่อน) รวมทั้ง request id หรือ correlation id เพื่อผูกการเปลี่ยนแปลงหลายรายการกลับไปยังการกระทำของผู้ใช้หนึ่งคน

สุดท้าย ให้ชัดเจนว่าคำว่า “ไม่เปลี่ยนแปลง” หมายถึงอะไรในระบบของคุณ กฎที่ง่ายที่สุดคือ: อย่าอัปเดตหรือแถวที่เป็น audit ให้ลบ เพียงแทรกเท่านั้น หากมีสิ่งผิดพลาด ให้เขียนอีเวนต์ใหม่ที่แก้หรือครอบงำรายการเก่า และเก็บของเดิมไว้ให้เห็น

สร้างตาราง audit แบบ append-only

เก็บข้อมูล audit แยกจากตารางปกติ สคีมา audit เฉพาะช่วยลดการแก้ไขโดยไม่ตั้งใจและทำให้การจัดการสิทธิ์ง่ายขึ้น

เป้าหมายง่ายๆ คือ ให้เพิ่มแถวได้เท่านั้น แต่ห้ามเปลี่ยนหรือเอาออก ใน PostgreSQL คุณบังคับใช้ด้วยสิทธิ์ (ใครทำอะไรได้) และเสริมด้วยมาตรการความปลอดภัยบางอย่างในการออกแบบตาราง

ตัวอย่างตารางเริ่มต้นเชิงปฏิบัติ:

CREATE SCHEMA IF NOT EXISTS audit;

CREATE TABLE audit.events (
  id            bigserial PRIMARY KEY,
  entity_type   text        NOT NULL,
  entity_id     text        NOT NULL,
  event_type    text        NOT NULL CHECK (event_type IN ('INSERT','UPDATE','DELETE')),
  actor_id      text,
  occurred_at   timestamptz NOT NULL DEFAULT now(),
  request_id    text,
  before_data   jsonb,
  after_data    jsonb,
  notes         text
);

มีฟิลด์บางตัวที่มีประโยชน์ในระหว่างการสืบสวนโดยเฉพาะ:

  • occurred_at พร้อม DEFAULT now() เพื่อให้เวลาถูกประทับโดยฐานข้อมูล ไม่ใช่ไคลเอนต์
  • entity_type และ entity_id เพื่อให้คุณติดตามเรคคอร์ดเดียวข้ามการเปลี่ยนแปลง
  • request_id เพื่อให้การกระทำของผู้ใช้หนึ่งครั้งสามารถถูกติดตามข้ามหลายแถว

ล็อกตารางด้วยบทบาท แอปของคุณควรมีสิทธิ์ INSERT และ SELECT บน audit.events แต่ไม่ควรมี UPDATE หรือ DELETE ให้เก็บการเปลี่ยนแปลงสคีมาและสิทธิ์ที่เข้มงวดไว้สำหรับบทบาทแอดมินที่ไม่ได้ใช้โดยแอป

บันทึกการเปลี่ยนแปลงด้วยทริกเกอร์ (สะอาดและคาดเดาได้)

หากคุณต้องการร่องรอยการตรวจสอบที่ตรวจจับการปลอมแปลงได้ ที่ที่น่าเชื่อถือที่สุดในการจับการเปลี่ยนแปลงคือฐานข้อมูล ล็อกแอปฯ อาจถูกข้าม กรอง หรือเขียนทับได้ ทริกเกอร์จะทำงานไม่ว่าจะเป็นแอป ไหน สคริปต์ หรือเครื่องมือแอดมินมาจับตาราง

ให้ทริกเกอร์เรียบง่าย งานของมันควรเป็นอย่างเดียว: แทรกอีเวนต์ audit หนึ่งรายการสำหรับทุก INSERT, UPDATE, และ DELETE บนตารางที่สำคัญ

เรคคอร์ด audit เชิงปฏิบัติมักรวมถึงชื่อโต๊ะ ประเภทการดำเนินการ คีย์หลัก ค่าเก่าและค่าใหม่ ประทับเวลา และตัวระบุที่ช่วยรวมการเปลี่ยนแปลงที่เกี่ยวข้องกัน (transaction id และ correlation id)

correlation id คือความต่างระหว่าง “อัปเดต 20 แถว” กับ “นี่คือการคลิกปุ่มครั้งเดียว” แอปของคุณสามารถตั้งค่า correlation id ต่อคำขอ (เช่น ในการตั้งค่าเซสชัน DB) และทริกเกอร์สามารถอ่านค่าได้ เก็บ txid_current() ด้วยเช่นกัน เพื่อให้คุณรวมการเปลี่ยนแปลงได้เมื่อ correlation id หายไป

นี่คือตัวอย่างรูปแบบทริกเกอร์ที่คงไว้ซึ่งความคาดเดาได้เพราะมันเพียงแต่แทรกเข้าไปในตาราง audit เท่านั้น (ปรับชื่อให้ตรงกับสคีมาของคุณ):

CREATE OR REPLACE FUNCTION audit_row_change() RETURNS trigger AS $$
DECLARE
  corr_id text;
BEGIN
  corr_id := current_setting('app.correlation_id', true);

  INSERT INTO audit_events(
    occurred_at, table_name, op, row_pk,
    old_row, new_row, db_user, txid, correlation_id
  ) VALUES (
    now(), TG_TABLE_NAME, TG_OP, COALESCE(NEW.id, OLD.id),
    to_jsonb(OLD), to_jsonb(NEW), current_user, txid_current(), corr_id
  );

  RETURN COALESCE(NEW, OLD);
END;
$$ LANGUAGE plpgsql;

ต้านทานความอยากที่จะทำอะไรเพิ่มในทริกเกอร์ หลีกเลี่ยงการคิวรีเพิ่ม, การเรียกเครือข่าย, หรือการแบ่งทางเลือกที่ซับซ้อน ทริกเกอร์เล็กๆ ทดสอบง่าย ทำงานเร็ว และยากที่จะโต้แย้งได้ในระหว่างการตรวจสอบ

เพิ่มการเชนแฮชเพื่อให้การแก้ไขทิ้งลายนิ้วมือ

รักษาความสม่ำเสมอของอีเวนต์ตรวจสอบ
มาตรฐานชื่ออีเวนต์และ payload ข้ามฟีเจอร์ เพื่อให้ร่องรอยการตรวจสอบของคุณคงความน่าเชื่อถือในระยะยาว
เริ่มสร้างฟรี

ตารางแบบ append-only ช่วยได้ แต่คนที่มีสิทธิ์เพียงพอยังคงเขียนทับแถวเก่าได้ การเชนแฮชทำให้การดัดแปลงแบบนั้นมองเห็นได้

เพิ่มสองคอลัมน์ในแต่ละแถว audit: prev_hash และ row_hash (บางครั้งเรียกว่า chain_hash) prev_hash เก็บแฮชของแถวก่อนหน้าที่อยู่ในเชนเดียวกัน row_hash เก็บแฮชของแถวปัจจุบัน ซึ่งคำนวณจากข้อมูลแถวบวกกับ prev_hash

สิ่งที่คุณแฮชมีความสำคัญ คุณต้องการอินพุตที่คงที่และทำซ้ำได้ เพื่อให้แถวเดิมผลิตแฮชเดียวกันเสมอ

แนวทางปฏิบัติคือแฮชสตริงที่เป็น canonical ที่ประกอบด้วยคอลัมน์คงที่ (timestamp, actor, action, entity id), payload แบบ canonical (มักเป็น jsonb เพราะคีย์ถูกเก็บอย่างสม่ำเสมอ) และ prev_hash

ระวังรายละเอียดที่อาจเปลี่ยนได้โดยไม่มีความหมาย เช่น ช่องว่าง, ลำดับคีย์ JSON เมื่อเป็นข้อความ, หรือรูปแบบตามลักษณะท้องถิ่น รักษาประเภทให้สอดคล้องและซีเรียลไลซ์ในวิธีที่คาดเดาได้

เชนแยกตามสตรีม ไม่ใช่ทั้งฐานข้อมูล

ถ้าคุณเชนทุกเหตุการณ์ในลำดับเดียวทั่วทั้งระบบ การเขียนอาจกลายเป็นคอขวด หลายระบบเชนภายใน “สตรีม” เช่น ต่อ tenant, ต่อ entity type, หรือวัตถุธุรกิจแต่ละประเภท

แต่ละแถวใหม่จะค้นหา row_hash ล่าสุดสำหรับสตรีมนั้น เก็บเป็น prev_hash แล้วคำนวณ row_hash ของตัวเอง

-- Requires pgcrypto
-- digest() returns bytea; store hashes as bytea
row_hash = digest(
  concat_ws('|',
    stream_key,
    occurred_at::text,
    actor_id::text,
    action,
    entity,
    entity_id::text,
    payload::jsonb::text,
    encode(prev_hash, 'hex')
  ),
  'sha256'
);

เก็บ snapshot ของ chain head

สำหรับการตรวจสอบที่เร็วขึ้น เก็บ row_hash ล่าสุด ("chain head") เป็นระยะ เช่น รายวันต่อสตรีม ในตาราง snapshot ขนาดเล็ก ในการสืบสวนคุณสามารถยืนยันเชนจนถึง snapshot แต่ละรายการ แทนการสแกนประวัติทั้งหมดพร้อมกัน Snapshots ยังช่วยเปรียบเทียบการส่งออกและค้นหารอยต่อที่น่าสงสัยได้ง่ายขึ้น

การจัดการความขนานและการจัดลำดับโดยไม่ทำลายเชน

การเชนแฮชซับซ้อนเมื่อมีทราฟฟิกจริง หากสองทรานแซคชันเขียนแถว audit พร้อมกันแล้วทั้งคู่ใช้ prev_hash เดียวกัน คุณอาจได้การแตกแขนง (forks) นั่นทำให้ความสามารถในการพิสูจน์ลำดับเดียวชัดเจนอ่อนลง

เริ่มจากตัดสินใจว่าเชนของคุณเป็นตัวแทนของอะไร เชนระดับโลกหนึ่งชุดอธิบายง่ายที่สุดแต่มีการแย่งชิงสูง สตรีมแยกหลายชุดลดการแย่งชิง แต่คุณต้องชัดเจนเกี่ยวกับสิ่งที่แต่ละเชนพิสูจน์ได้

ไม่ว่าจะเลือกแบบไหน ให้กำหนดลำดับที่เข้มงวดด้วย id เหตุการณ์ที่เพิ่มขึ้นเสมอ (มักจะเป็น id ที่รองรับด้วย sequence) timestamp ไม่พอเพราะสามารถชนกันและถูกจัดการได้

เพื่อหลีกเลี่ยงสภาวะแข่งขันเมื่อคำนวณ prev_hash ให้ทำการซีเรียลไลซ์ “ค้นหาแฮชล่าสุด + แทรกแถวถัดไป” สำหรับแต่ละสตรีม วิธีที่นิยมคือการล็อกแถวเดียวที่เป็นตัวแทนหัวเชน หรือใช้ advisory lock ที่ได้คีย์จาก stream id เป้าหมายคือให้สองผู้เขียนในสตรีมเดียวกันไม่สามารถอ่านแฮชล่าสุดเดียวกันทั้งคู่ได้

การแบ่งพาร์ติชันและการชาร์ดจะส่งผลต่อที่อยู่ของ “แถวล่าสุด” หากคุณคาดว่าจะพาร์ติชันข้อมูล audit ให้เก็บเชนแต่ละอันไว้ในพาร์ติชันเดียวโดยใช้คีย์พาร์ติชันเดียวกับ stream key (เช่น tenant id) ด้วยวิธีนี้ เชนของ tenant จะยังยืนยันได้แม้ tenant จะย้ายข้ามเซิร์ฟเวอร์ในภายหลัง

วิธีตรวจสอบเชนระหว่างการสืบสวน

ส่งมอบแผงแอดมินที่เป็นไปตามข้อกำหนด
สร้างแผงแอดมินที่ปลอดภัยพร้อมการเข้าถึงตามบทบาทและประวัติอีเวนต์แบบ append-only สำหรับตารางที่สำคัญ
สร้างแอป

การเชนแฮชช่วยได้เฉพาะเมื่อคุณพิสูจน์ได้ว่าเชนยังคงถูกต้องเมื่อมีคนถาม วิธีที่ปลอดภัยคือรันการตรวจสอบแบบอ่านอย่างเดียวที่คำนวณแฮชของแต่ละแถวจากข้อมูลที่เก็บไว้แล้วเปรียบเทียบกับค่าที่บันทึกไว้

ตัวตรวจสอบง่ายๆ ที่รันเมื่อจำเป็น

ตัวตรวจสอบควร: สร้างแฮชที่คาดหวังสำหรับแต่ละแถวยืนยันว่าแต่ละแถวเชื่อมกับแถวก่อนหน้า และแจ้งสิ่งที่ผิดปกติ

นี่เป็นรูปแบบทั่วไปที่ใช้ฟังก์ชันหน้าต่าง ปรับชื่อคอลัมน์ให้ตรงกับตารางของคุณ

WITH ordered AS (
  SELECT
    id,
    created_at,
    actor_id,
    action,
    entity,
    entity_id,
    payload,
    prev_hash,
    row_hash,
    LAG(row_hash) OVER (ORDER BY created_at, id) AS expected_prev_hash,
    /* expected row hash, computed the same way as in your insert trigger */
    encode(
      digest(
        coalesce(prev_hash, '') || '|' ||
        id::text || '|' ||
        created_at::text || '|' ||
        coalesce(actor_id::text, '') || '|' ||
        action || '|' ||
        entity || '|' ||
        entity_id::text || '|' ||
        payload::text,
        'sha256'
      ),
      'hex'
    ) AS expected_row_hash
  FROM audit_log
)
SELECT
  id,
  created_at,
  CASE
    WHEN prev_hash IS DISTINCT FROM expected_prev_hash THEN 'BROKEN_LINK'
    WHEN row_hash IS DISTINCT FROM expected_row_hash THEN 'HASH_MISMATCH'
    ELSE 'OK'
  END AS status
FROM ordered
WHERE prev_hash IS DISTINCT FROM expected_prev_hash
   OR row_hash IS DISTINCT FROM expected_row_hash
ORDER BY created_at, id;

นอกจากผลลัพธ์ "เสียหรือไม่" แล้ว ก็ควรตรวจหาช่องว่าง (id หายไปในช่วง), ลิงก์เรียงลำดับผิด หรือสำเนาที่น่าสงสัยซึ่งไม่สอดคล้องกับเวิร์กโฟลว์จริง

บันทึกผลการตรวจสอบเป็นอีเวนต์ที่ไม่เปลี่ยนแปลง

อย่ารันคิวรีแล้วฝังผลลัพธ์ไว้ในตั๋ว บันทึกผลการตรวจสอบลงในตาราง append-only แยกต่างหาก (เช่น audit_verification_runs) พร้อมเวลารัน, เวอร์ชันของตัวตรวจสอบ, ผู้ทริกเกอร์, ช่วงที่ตรวจ, และจำนวนลิงก์เสียกับแฮชที่ไม่ตรง

นั่นให้ร่องรอยที่สอง: ไม่เพียงแต่ล็อกการตรวจสอบยังคงอยู่ แต่คุณยังแสดงว่าคุณได้ทำการตรวจสอบมันอยู่เสมอ

จังหวะปฏิบัติได้แก่: รันหลังการ deploy ที่แตะต้องตรรกะ audit, ทุกคืนสำหรับระบบที่ใช้งานหนาแน่น, และเสมอก่อนการตรวจสอบตามแผน

ข้อผิดพลาดทั่วไปที่ทำให้การตรวจจับการปลอมแปลงล้มเหลว

ปรับใช้ด้วยความมั่นใจ
ปรับใช้แอปของคุณไปยังคลาวด์และรักษารูปแบบการตรวจสอบเดียวกันข้ามสภาพแวดล้อมและการกู้คืน
ปรับใช้

ความล้มเหลวส่วนใหญ่ไม่เกี่ยวกับอัลกอริธึมแฮช แต่เกี่ยวกับข้อยกเว้นและช่องว่างที่เปิดทางให้คนโต้แย้ง

วิธีที่เร็วที่สุดในการเสียความเชื่อถือคืออนุญาตให้อัปเดตแถว audit แม้แต่ "แค่ครั้งนี้" คุณได้สร้างบรรทัดฐานและทางปฏิบัติสำหรับการเขียนทับประวัติ หากต้องแก้ไข ให้เพิ่มอีเวนต์ใหม่ที่อธิบายการแก้ไขและเก็บของเดิมไว้

การเชนแฮชก็ล้มเหลวเมื่อคุณแฮชข้อมูลที่ไม่คงที่ JSON เป็นกับดักทั่วไป หากคุณแฮชสตริง JSON ความแตกต่างที่ไม่เป็นอันตราย (ลำดับคีย์ ช่องว่าง รูปแบบตัวเลข) อาจเปลี่ยนแฮชและทำให้การยืนยันมีเสียงดังวุ่นวาย ให้ใช้รูปแบบ canonical: ฟิลด์ที่เป็นมาตรฐาน, jsonb, หรือการซีเรียลไลซ์ที่สม่ำเสมอ

รูปแบบอื่นที่ทำลายความน่าเชื่อถือ:

  • แฮชเฉพาะ payload แล้วข้ามบริบท (timestamp, actor, object id, action)
  • จับการเปลี่ยนแปลงเฉพาะในแอปฯ แล้วสมมติว่าฐานข้อมูลตรงเสมอ
  • ใช้บทบาทฐานข้อมูลเดียวที่สามารถเขียนข้อมูลธุรกิจและแก้ไขประวัติ audit ได้ด้วย
  • อนุญาตค่า NULL สำหรับ prev_hash ในเชนโดยไม่มีกฎที่ชัดเจนและมีเอกสาร

การแยกหน้าที่มีความสำคัญ หากบทบาทเดียวกันสามารถแทรกอีเวนต์ audit และแก้ไขมันได้ การตรวจจับการปลอมแปลงจะกลายเป็นแค่คำสัญญาแทนที่จะเป็นการควบคุม

เช็คลิสต์ด่วนสำหรับร่องรอยการตรวจสอบที่น่าเชื่อถือ

ร่องรอยการตรวจสอบที่น่าเชื่อถือควรแก้ไขยากและตรวจสอบง่าย

เริ่มจากการควบคุมการเข้าถึง: ตาราง audit ต้องเป็นแบบ append-only ในทางปฏิบัติ บทบาทแอปควรแทรก (และมักจะอ่าน) แต่ไม่อัปเดตหรือลบ การเปลี่ยนแปลงสคีมาต้องถูกจำกัดอย่างเข้มงวด

ตรวจให้แน่ใจว่าแต่ละแถวตอบคำถามที่ผู้สืบสวนจะถาม: ใครทำ, เวลาเกิด (ฝั่งเซิร์ฟเวอร์), สิ่งที่เกิดขึ้น (ชื่ออีเวนต์ที่ชัดเจนพร้อมการดำเนินการ), สิ่งที่ถูกกระทบ (ชื่อ entity และ id), และการเชื่อมต่อ (request/correlation id และ transaction id)

จากนั้นยืนยันเลเยอร์ความสมบูรณ์ ทดสอบง่ายคือเล่นซ้ำช่วงหนึ่งและยืนยันว่า prev_hash แต่ละตัวตรงกับแฮชของแถวก่อนหน้า และแฮชที่เก็บไว้ตรงกับแฮชที่คำนวณใหม่

ในเชิงปฏิบัติการ ทำให้การตรวจสอบเป็นงานปกติ:

  • รันการตรวจสอบความสมบูรณ์ตามกำหนดและบันทึกผลผ่าน/ไม่ผ่านและช่วงที่ตรวจ
  • แจ้งเตือนเมื่อมีความไม่ตรงกัน ช่องว่าง และลิงก์เสีย
  • เก็บแบ็กอัพไว้นานพอเพื่อครอบคลุมหน้าต่างการเก็บรักษาของคุณ และล็อกการเก็บรักษาเพื่อป้องกันการ "ล้างประวัติ" ก่อนเวลา

ตัวอย่าง: พบการแก้ไขที่น่าสงสัยในการตรวจสอบความเป็นไปตามข้อกำหนด

เป็นเจ้าของการใช้งานตรวจสอบของคุณ
ต้องการการควบคุมเต็มรูปแบบในภายหลังหรือไม่? ส่งออกซอร์สโค้ดแล้วเก็บตรรกะการตรวจสอบของคุณให้โปร่งใสและตรวจสอบได้
ส่งออกโค้ด

กรณีทดสอบทั่วไปคือข้อพิพาทการคืนเงิน ลูกค้าอ้างว่าได้รับการอนุมัติคืนเงิน $250 แต่ระบบตอนนี้แสดง $25 ฝ่ายสนับสนุนยืนยันว่าอนุมัติถูกต้อง และฝ่ายปฏิบัติตามต้องการคำตอบ

เริ่มค้นหาด้วย correlation id (order id, ticket id, หรือ refund_request_id) และช่วงเวลา ดึงแถว audit สำหรับ correlation id นั้นและครอบคลุมรอบๆ เวลาที่อนุมัติ

คุณกำลังมองหาอีเวนต์ทั้งหมด: สร้างคำขอ, อนุมัติการคืนเงิน, ตั้งจำนวนคืนเงิน, และการอัปเดตภายหลังใดๆ ด้วยการออกแบบที่ตรวจจับการปลอมแปลงได้ คุณยังตรวจสอบได้ว่าลำดับยังสมบูรณ์หรือไม่

ไหลการสืบสวนง่ายๆ:

  • ดึงแถว audit ทั้งหมดสำหรับ correlation id ตามลำดับเวลา
  • คำนวณแฮชของแต่ละแถวใหม่จากฟิลด์ที่เก็บไว้ (รวม prev_hash)
  • เปรียบเทียบแฮชที่คำนวณกับแฮชที่เก็บไว้
  • หาจุดแถวแรกที่ต่างกันและดูว่าบรรทัดหลังๆ ล้มเหลวด้วยหรือไม่

ถ้ามีคนแก้แถว audit เดี่ยวๆ (เช่น เปลี่ยนจำนวนจาก 250 เป็น 25) แฮชของแถวนั้นจะไม่ตรง ปกติการไม่ตรงจะลุกลามต่อไปข้างหน้าเพราะแถวถัดไปรวมแฮชของแถวก่อนหน้า การลุกลามนั้นเป็นลายนิ้วมือ: มันแสดงว่าบันทึกการตรวจสอบถูกแก้ไขหลังเหตุการณ์

สิ่งที่เชนบอกได้: เกิดการแก้ไข จุดแรกที่เชนขาดหาย และขอบเขตของแถวที่ได้รับผลกระทบ สิ่งที่มันบอกไม่ได้ด้วยตัวมันเอง: ใครเป็นคนแก้ไข ค่าเดิมคืออะไรหากถูกเขียนทับ หรือว่าตารางอื่นๆ ถูกเปลี่ยนด้วยหรือไม่

ขั้นตอนต่อไป: นำไปใช้อย่างปลอดภัยและรักษาความสามารถในการดูแล

ปฏิบัติกับร่องรอยการตรวจสอบเหมือนการควบคุมความปลอดภัยอื่นๆ นำไปใช้ทีละน้อย พิสูจน์ว่ามันทำงาน แล้วค่อยขยาย

เริ่มจากการกระทำที่จะทำให้คุณเสียหายมากที่สุดหากถูกโต้แย้ง: การเปลี่ยนสิทธิ์, การจ่ายเงิน, การคืนเงิน, การส่งออกข้อมูล, และการโอเวอร์ไรด์ด้วยมือ เมื่อครอบคลุมเหตุการณ์เหล่านี้แล้ว ให้เพิ่มอีเวนต์ความเสี่ยงต่ำโดยไม่เปลี่ยนการออกแบบหลัก

เขียนสัญญาของอีเวนต์ audit: ฟิลด์ใดถูกบันทึก, แต่ละประเภทอีเวนต์หมายถึงอะไร, แฮชคำนวณอย่างไร, และวิธีรันการตรวจสอบ เก็บเอกสารนั้นไว้ใกล้กับมิเกรชันฐานข้อมูลของคุณ และทำให้กระบวนการตรวจสอบทำซ้ำได้

การซ้อมกู้คืนสำคัญเพราะการสืบสวนมักเริ่มจากแบ็กอัพ ไม่ใช่ระบบสด กู้คืนเป็นฐานข้อมูลทดสอบเป็นประจำและยืนยันเชนตั้งแต่ต้นจนจบ หากคุณไม่สามารถทำซ้ำผลการตรวจสอบหลังการกู้คืนได้ การยืนยันการตรวจจับการปลอมแปลงจะยากที่จะปกป้อง

หากคุณสร้างเครื่องมือภายในและเวิร์กโฟลว์แอดมินโดยใช้ AppMaster (appmaster.io) การทำให้อีเวนต์ audit ถูกเขียนผ่านกระบวนการฝั่งเซิร์ฟเวอร์ที่เป็นมาตรฐานจะช่วยรักษาสคีมาอีเวนต์และ correlation id ให้สม่ำเสมอข้ามฟีเจอร์ ซึ่งทำให้การตรวจสอบและการสืบสวนง่ายขึ้นมาก

จัดเวลาบำรุงรักษาสำหรับระบบนี้ ร่องรอยการตรวจสอบมักล้มเหลวอย่างเงียบๆ เมื่อทีมปล่อยฟีเจอร์ใหม่แต่ลืมเพิ่มอีเวนต์ อัปเดตอินพุตแฮช หรือรักษางานตรวจสอบและการซ้อมกู้คืนให้ทำงานต่อเนื่อง

ง่ายต่อการเริ่มต้น
สร้างบางสิ่งที่ น่าทึ่ง

ทดลองกับ AppMaster ด้วยแผนฟรี
เมื่อคุณพร้อม คุณสามารถเลือกการสมัครที่เหมาะสมได้

เริ่ม