SQLi là bài toán taht theo dấu dữ liệu. XSS cũng là taint nhưng ở đầu ra HTML. IDOR thì không phải taint — nó là bài toán thiếu kiểm tra quyền, cần LLM hiểu logic nghiệp vụ. Hai loại đòi hai cách tiếp cận.
A. XSS — dữ liệu bẩn ra HTML mà không escape
XSS (Cross-Site Scripting) xảy ra khi input người dùng được render vào trang mà không escape, cho phép chèn <script>.
$name = $_GET['name'];
echo "<h1>Xin chào $name</h1>"; // XSS: name = <script>...</script>
Điểm tinh tế: ngữ cảnh output quyết định cách escape đúng.
- Trong HTML body →
htmlspecialchars. - Trong thuộc tính HTML → escape + đóng ngoặc kép.
- Trong
<script>/ JSON → JS/JSON encode. - Trong URL →
urlencode.
htmlspecialchars đặt sai chỗ (ví dụ bên trong <script>) vẫn dính XSS. Prompt XSS phải hỏi: dữ liệu ra ở ngữ cảnh nào, và escape có khớp ngữ cảnh đó không?Tìm XSS. Với mỗi nơi in dữ liệu người dùng ra response:
1. Xác định NGỮ CẢNH output: html_body | html_attr | js | url | css.
2. Xác định escape đang dùng (nếu có).
3. Báo XSS nếu escape THIẾU hoặc SAI ngữ cảnh.
Chú ý framework: template auto-escape (Blade {{ }}, Twig) là AN TOÀN,
nhưng {!! !!} hoặc |raw thì KHÔNG.
Mẹo framework: Blade {{ $x }} tự escape (an toàn), {!! $x !!} thì không. Agent phải biết dấu hiệu này để tránh báo nhầm.
B. IDOR — thiếu kiểm tra quyền sở hữu
IDOR (Insecure Direct Object Reference) xảy ra khi người dùng truy cập tài nguyên của người khác bằng cách đổi ID, vì server không kiểm tra quyền sở hữu.
// GET /invoice?id=123
$id = (int) $_GET['id']; // đã ép kiểu -> KHÔNG phải SQLi
$inv = Invoice::find($id);
return $inv->toJson(); // IDOR: không kiểm invoice thuộc user!
Chú ý: ép kiểu (int) loại bỏ SQLi nhưng không giải quyết IDOR. Đây là điểm nhiều tool bỏ sót vì chúng chỉ nghĩ về taint.
Bản vá đúng:
$inv = Invoice::find($id);
if ($inv->user_id !== auth()->id()) abort(403);
Khung tư duy IDOR
Với mỗi handler nhận một ID tài nguyên từ request, hỏi 3 câu:
- Tài nguyên này có chủ sở hữu (user_id, tenant_id) không?
- Trước khi trả/sửa/xóa, code có so khớp chủ sở hữu với người đang đăng nhập không?
- Nếu là hành động quản trị, có kiểm tra role không?
Tìm IDOR. Với mỗi route nhận ID tài nguyên:
- Tài nguyên có cột owner (user_id/tenant_id/account_id)?
- Có so khớp owner == người dùng hiện tại TRƯỚC khi trả dữ liệu?
- Có kiểm role cho hành động nhạy cảm?
Báo IDOR nếu thiếu kiểm tra quyền. Ghi rõ dòng NÊN có check.
IDOR cần LLM đọc ý định: model có cột user_id nghĩa là tài nguyên có chủ → phải kiểm. Đây chính là chỗ LLM vượt trội so với rule tĩnh.
Các bước triển khai
- Tách hai prompt riêng:
xss.mdvàidor.md(bản chất khác nhau). - Với XSS: cấp thông tin template engine để biết auto-escape.
- Với IDOR: cấp schema bảng (cột owner) qua tool tra DB.
- Chạy song song, gộp finding.
- Đưa tất cả qua bước phản biện (bài 5).
Checklist
- [ ] XSS: đã xét đúng ngữ cảnh output (body/attr/js/url)?
- [ ] XSS: nhận biết auto-escape của template engine?
- [ ] IDOR: đã tra schema để biết tài nguyên có owner?
- [ ] IDOR: phân biệt rõ với SQLi (ép kiểu ≠ chống IDOR)?
Sai lầm thường gặp
- Dùng chung một prompt cho cả 3 loại: XSS/SQLi là taint, IDOR là access-control — trộn lẫn làm giảm độ chính xác.
- Báo XSS với template auto-escape: false positive kinh điển.
- Bỏ sót IDOR vì đã thấy ép kiểu: ép kiểu chỉ chống injection, không chống truy cập trái phép.
- Không cấp schema cho IDOR: agent không biết tài nguyên có chủ, đoán mò.