KI: PRAKTEK 11: AI untuk Audit Data Pribadi

From OnnoWiki
Jump to navigation Jump to search

Di dunia nyata, kebocoran data sering bukan karena hacker super canggih—tapi karena data pribadi “nyangkut” di tempat yang tidak seharusnya: file CSV di folder proyek, log aplikasi, backup SQL lama, export Excel, atau chat yang dipaste ke dokumen.

Di sesi ini, mahasiswa akan bikin tool audit yang bertindak seperti “robot auditor”: ia masuk ke folder data, membaca file satu per satu, lalu mendeteksi PII (Personally Identifiable Information), memberi skor risiko, dan menghasilkan laporan.

Mindset penting:

  • Audit itu kebiasaan (continuous), bukan tugas akhir semester.
  • Target kita bukan “sempurna”, tapi lebih aman tiap iterasi.

Tujuan

Mahasiswa mampu:

  • Mendesian pipeline audit data: scan → detect → classify → report → protect
  • Mendeteksi PII dengan pendekatan Regex + NLP/ML ringan
  • Memberi risk score untuk membantu prioritas perbaikan
  • Menghasilkan AI Data Scanner (CLI tool) + laporan JSON/CSV
  • Melakukan langkah “tindak lanjut” menggunakan GnuPG: enkripsi / redaksi

Konsep: PII Detection (Realistic)

PII adalah data yang bisa mengidentifikasi seseorang, baik langsung maupun kombinasi.

Contoh PII yang sering ditemukan di data kampus/perusahaan:

  • Email (nama@domain)
  • Nomor HP (08xx… / +62…)
  • NIK (16 digit, kadang dipisah spasi/strip)
  • No. Rekening (variasi panjang)
  • Alamat (lebih sulit—banyak variasi)
  • IP address (bukan selalu PII, tapi bisa sensitif)
  • API token / session token (bukan PII, tapi sensitif)

Trik audit yang benar:

Deteksi bukan hanya “ada email”, tapi juga konteks:

  • Email muncul di data “publik” → risiko sedang
  • Email + NIK + tanggal lahir → risiko tinggi
  • Token API di log → risiko kritikal

Tools (Open Source)

1. Python (Utama)

  • re untuk regex
  • json, csv, pathlib
  • (opsional) scikit-learn untuk ML ringan
  • (opsional) spacy untuk NLP (bisa berat, tapi open-source)

2. GnuPG (GNU Privacy Guard)

Dipakai untuk “aksi setelah audit”:

  • enkripsi file yang mengandung PII
  • sign laporan audit (integritas)
  • dekripsi saat perlu akses aman

Tahap Praktikum (Step-by-step)

Tahap 0 — Setup Environment (Ubuntu 24.04)

Jalankan:

sudo apt update
sudo apt install -y python3 python3-venv python3-pip gnupg jq
python3 -m venv venv
source venv/bin/activate
pip install --upgrade pip

Buat folder proyek:

mkdir -p ai_auditor/{data,output}

Tahap 1 — Siapkan Dataset Contoh (Realistic)

Buat file data/sample.txt:

cat > data/sample.txt << 'EOF'
Nama: Budi Santoso
Email: budi.santoso@gmail.com
NIK: 3174012301990002
HP: +62 812-3456-7890
Alamat: Jl. Melati No. 10, Tangerang Selatan
Catatan: reset token = sk_live_51Hxxxxxxx
IP Login: 103.10.20.30
EOF

Buat juga contoh CSV data/mahasiswa.csv:

cat > data/mahasiswa.csv << 'EOF'
nama,email,nik,no_hp
Ayu,ayu@kampus.ac.id,3174020101010003,081234567890
Doni,doni@gmail.com,3174030202020004,628123111222
EOF

Tahap 2 — Bangun “AI Data Scanner” Versi 1 (Regex Engine)

Buat file ai_auditor.py:

#!/usr/bin/env python3
import re
import json
from pathlib import Path
from datetime import datetime

# --- Pola PII (sengaja sederhana dulu, nanti bisa ditingkatkan) ---
PATTERNS = {
    "EMAIL": re.compile(r"\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}\b"),
    "PHONE_ID": re.compile(r"\b(\+62\s?8\d{2}[-\s]?\d{3,4}[-\s]?\d{3,4}|\b08\d{8,12}\b|\b62\d{9,13}\b)"),
    "NIK_ID": re.compile(r"\b\d{16}\b"),
    "IP_ADDR": re.compile(r"\b(?:(?:25[0-5]|2[0-4]\d|[01]?\d?\d)\.){3}(?:25[0-5]|2[0-4]\d|[01]?\d?\d)\b"),
    # Token contoh (jangan terlalu agresif biar tidak banyak false positive)
    "API_TOKEN": re.compile(r"\b(sk_live|sk_test|token|apikey|api_key|bearer)\S{6,}\b", re.IGNORECASE),
}

# Bobot risiko (bisa disesuaikan)
RISK_WEIGHT = {
    "EMAIL": 2,
    "PHONE_ID": 3,
    "NIK_ID": 5,
    "IP_ADDR": 1,
    "API_TOKEN": 6,
}

def classify_risk(found_types):
    score = sum(RISK_WEIGHT.get(t, 0) for t in found_types)
    if score >= 10:
        return score, "HIGH"
    if score >= 5:
        return score, "MEDIUM"
    return score, "LOW"

def scan_text(text):
    findings = []
    found_types = set()
    for t, rx in PATTERNS.items():
        matches = rx.findall(text)
        if matches:
            found_types.add(t)
            # Normalisasi hasil findall (kadang tuple)
            norm = []
            for m in matches:
                norm.append(m[0] if isinstance(m, tuple) else m)
            findings.append({
                "type": t,
                "count": len(norm),
                "samples": list(dict.fromkeys(norm))[:3],  # max 3 sample unik
            })
    score, level = classify_risk(found_types)
    return findings, score, level

def read_file(path: Path):
    # Baca sebagai text "best effort"
    try:
        return path.read_text(encoding="utf-8", errors="replace")
    except Exception:
        return ""

def main(input_dir="data", output_dir="output"):
    input_path = Path(input_dir)
    out_path = Path(output_dir)
    out_path.mkdir(parents=True, exist_ok=True)

    report = {
        "generated_at": datetime.utcnow().isoformat() + "Z",
        "scanned_dir": str(input_path.resolve()),
        "files": [],
        "summary": {"total_files": 0, "flagged_files": 0, "by_level": {"LOW": 0, "MEDIUM": 0, "HIGH": 0}},
    }

    for p in input_path.rglob("*"):
        if not p.is_file():
            continue

        # Filter file sederhana (bisa diperluas)
        if p.suffix.lower() not in [".txt", ".csv", ".log", ".json"]:
            continue

        text = read_file(p)
        findings, score, level = scan_text(text)

        report["summary"]["total_files"] += 1

        file_entry = {
            "path": str(p),
            "size_bytes": p.stat().st_size,
            "risk_score": score,
            "risk_level": level,
            "findings": findings,
        }

        if findings:
            report["summary"]["flagged_files"] += 1
            report["summary"]["by_level"][level] += 1

        report["files"].append(file_entry)

    # Simpan laporan
    out_file = out_path / "audit_report.json"
    out_file.write_text(json.dumps(report, indent=2, ensure_ascii=False), encoding="utf-8")

    print(f"[OK] Report saved: {out_file}")
    print(json.dumps(report["summary"], indent=2))

if __name__ == "__main__":
    main()

Jalankan:

chmod +x ai_auditor.py
./ai_auditor.py

Cek laporan:

cat output/audit_report.json | jq .

Tahap 3 — “Tandai Risiko” + Output yang Bisa Dipakai (CSV Ringkas)

Tambahkan output ringkas output/audit_summary.csv (ini real dipakai tim audit).

Buat file export_summary.py:

#!/usr/bin/env python3
import json
import csv
from pathlib import Path

def main(report_path="output/audit_report.json", out_csv="output/audit_summary.csv"):
    report = json.loads(Path(report_path).read_text(encoding="utf-8"))
    rows = []
    for f in report["files"]:
        if not f["findings"]:
            continue
        types = ",".join(x["type"] for x in f["findings"])
        rows.append([f["path"], f["risk_level"], f["risk_score"], types, f["size_bytes"]])

    with open(out_csv, "w", newline="", encoding="utf-8") as fp:
        w = csv.writer(fp)
        w.writerow(["path", "risk_level", "risk_score", "finding_types", "size_bytes"])
        w.writerows(rows)

    print(f"[OK] CSV saved: {out_csv}")

if __name__ == "__main__":
    main()

Run:

chmod +x export_summary.py
./export_summary.py

column -t -s, output/audit_summary.csv


Tahap 4 — Upgrade ke “Regex + ML ringan” (Opsional tapi Keren)

Regex bagus untuk pola tetap (email, NIK). Tapi untuk alamat / nama / kalimat sensitif, kita butuh ML sederhana.

Konsep ML ringan yang realistis untuk kelas:

  • Kita bikin text classifier yang menentukan kalimat termasuk “sensitif” atau “tidak”
  • Model: Logistic Regression / Linear SVM
  • Fitur: TF-IDF

Install:

pip install scikit-learn

Buat file ml_sensitive_classifier.py:

#!/usr/bin/env python3
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.linear_model import LogisticRegression

# Dataset mini (contoh). Di kelas, mahasiswa harus menambah data sendiri.
TRAIN_TEXT = [
    "NIK saya 3174012301990002",
    "Nomor HP saya 081234567890",
    "Email saya budi@gmail.com",
    "Token reset: sk_live_123xxx",
    "Alamat saya Jl. Melati No. 10",
    "Hari ini cuaca cerah",
    "Saya suka belajar keamanan informasi",
    "Meeting jam 2 siang",
]
TRAIN_LABEL = [1,1,1,1,1,0,0,0]  # 1 = sensitif, 0 = non-sensitif

def build_model():
    vec = TfidfVectorizer(ngram_range=(1,2))
    X = vec.fit_transform(TRAIN_TEXT)
    clf = LogisticRegression(max_iter=200)
    clf.fit(X, TRAIN_LABEL)
    return vec, clf

def predict_lines(lines, threshold=0.6):
    vec, clf = build_model()
    X = vec.transform(lines)
    proba = clf.predict_proba(X)[:,1]
    results = []
    for line, p in zip(lines, proba):
        results.append((line, float(p), "SENSITIVE" if p >= threshold else "OK"))
    return results

if __name__ == "__main__":
    test = [
        "Silakan kirim NIK dan nomor HP untuk verifikasi",
        "Jangan lupa rapat jam 3",
        "Password admin adalah admin123",
        "Email saya ayu@kampus.ac.id",
    ]
    for line, p, label in predict_lines(test):
        print(f"{label}\t{p:.2f}\t{line}")

Ini bukan “AI super”, tapi realistic ML pipeline yang bisa dibesarkan dataset-nya.

Tahap 5 — Aksi Setelah Audit dengan GnuPG

Audit tanpa aksi = cuma “tahu masalah”. Sekarang kita lakukan aksi aman.

1. Generate Key (untuk kelas, pakai mode cepat)

gpg --full-generate-key

Cek key:

gpg --list-keys

2. Enkripsi Laporan Audit

Enkripsi file laporan supaya aman saat dikirim ke dosen/tim:

gpg -c output/audit_report.json

Hasilnya: output/audit_report.json.gpg

Dekripsi:

gpg -d output/audit_report.json.gpg > output/audit_report.decrypted.json

3. Sign Laporan (Integritas)

Ini penting untuk audit: laporan harus bisa dibuktikan tidak diubah.

gpg --clearsign output/audit_summary.csv

Hasil: output/audit_summary.csv.asc Verifikasi:

gpg --verify output/audit_summary.csv.asc

Output yang Wajib Dikumpulkan (Sesuai Modul)

Mahasiswa menyerahkan:

  • ai_auditor.py (AI data scanner)
  • output/audit_report.json (detail)
  • output/audit_summary.csv (ringkas)
  • output/audit_report.json.gpg (enkripsi)
  • output/audit_summary.csv.asc (signature)

Laporan singkat (1–2 halaman) berisi:

  • Temuan PII paling sering
  • File paling berisiko
  • Rekomendasi perbaikan

Challenge (Fun & Menantang)

Pilih minimal 2:

  • Tambah deteksi PII lain: NPWP / Passport / KK (buat regex-nya)
  • Buat fitur redaction: output file versi “tersensor” (contoh: email jadi ***@***)
  • Buat rule “HIGH jika NIK + email muncul di file yang sama”
  • Buat whitelist domain email kampus (mis. @kampus.ac.id) dan beri skor lebih rendah
  • Tambah deteksi “leak token” dengan pola lebih baik

Bonus: Redaction (Contoh Kode yang Real Dipakai)

Buat redact.py:

#!/usr/bin/env python3
import re
from pathlib import Path

EMAIL = re.compile(r"\b[A-Za-z0-9._%+-]+@([A-Za-z0-9.-]+\.[A-Za-z]{2,})\b")
NIK = re.compile(r"\b\d{16}\b")
PHONE = re.compile(r"\b(\+62\s?8\d{2}[-\s]?\d{3,4}[-\s]?\d{3,4}|\b08\d{8,12}\b|\b62\d{9,13}\b)")

def redact_text(t: str) -> str:
    t = EMAIL.sub(r"***@\1", t)
    t = NIK.sub("****************", t)
    t = PHONE.sub("***REDACTED_PHONE***", t)
    return t

def main(infile="data/sample.txt", outfile="output/sample.redacted.txt"):
    p = Path(infile)
    text = p.read_text(encoding="utf-8", errors="replace")
    out = redact_text(text)
    Path(outfile).write_text(out, encoding="utf-8")
    print(f"[OK] Redacted saved: {outfile}")

if __name__ == "__main__":
    main()

Run:

chmod +x redact.py
./redact.py
cat output/sample.redacted.txt

Pranala Menarik