Skip to content

PlusMagi's Blog By Pitt Phunsanit

Plus emotional magic to the knowledge of logic.

  • About’s Pitt
Close Button

PHP: การสร้างและตรวจสอบ CSRF Token ในฟอร์มPHP: การสร้างและตรวจสอบ CSRF Token ในฟอร์ม

2011-05-012011-05-01| phunsanitphunsanit| 0 Comment | 07:00

การปกป้องเว็บแอปพลิเคชันจากภัยคุกคามทางไซเบอร์เป็นเรื่องที่ไม่ควรมองข้าม และหนึ่งในช่องโหว่พื้นฐานที่พบได้บ่อยที่สุดคือ CSRF (Cross-Site Request Forgery) หรือการปลอมแปลงคำร้องขอจากฝั่งผู้ใช้

บทความนี้จะพาคุณไปเข้าใจหลักการของ CSRF และเขียนโค้ด PHP ในการสร้างและตรวจสอบ CSRF Token ด้วยตัวเองอย่างง่าย แต่ได้ผลจริงครับ


CSRF คืออะไร? ทำไมต้องป้องกัน?

CSRF คือการที่ผู้ไม่หวังดี (Hacker) หลอกให้ผู้ใช้ที่กำลังเข้าสู่ระบบ (Log in) อยู่ในเว็บของเรา กดลิงก์หรือส่งฟอร์มจากเว็บอื่น โดยที่ผู้ใช้ไม่รู้ตัว ทำให้ระบบคิดว่าเป็นคำสั่งที่มาจากผู้ใช้จริง เช่น การแอบเปลี่ยนรหัสผ่าน หรือการโอนเงิน

แก้ปัญหาอย่างไร? วิธีป้องกันที่ดีที่สุดคือการใช้ CSRF Token ซึ่งเป็นรหัสสุ่มสั้นๆ ที่สร้างขึ้นฝั่งเซิร์ฟเวอร์ และแนบไปกับฟอร์ม เมื่อผู้ใช้ส่งฟอร์มกลับมา เซิร์ฟเวอร์จะเช็กว่า Token ตรงกันหรือไม่ ถ้าตรงกันถึงจะยอมให้ทำรายการ


ขั้นตอนการสร้างและตรวจสอบ CSRF Token ใน PHP

การทำงานแบ่งออกเป็น 3 ส่วนหลัก ๆ ดังนี้

1. การสร้าง Token (Generate Token)

เราจะสร้าง Token โดยใช้ฟังก์ชัน random_bytes() เพื่อความปลอดภัยสูง และเก็บไว้ใน $_SESSION

<?php
// ต้องเริ่ม Session ทุกครั้งก่อนใช้งาน
session_start();

// ฟังก์ชันสร้าง CSRF Token
function generateCsrfToken() {
    if (empty($_SESSION['csrf_token'])) {
        // สร้าง รหัสสุ่มความยาว 32 bytes แล้วแปลงเป็น hex (64 ตัวอักษร)
        $_SESSION['csrf_token'] = bin2hex(random_bytes(32));
    }
    return $_SESSION['csrf_token'];
}

$token = generateCsrfToken();
?>

2. การแนบ Token ไปกับ HTML Form

ฝัง Token ไว้ในฟอร์มโดยใช้ <input type="hidden"> เพื่อไม่ให้รบกวนหน้าตาของเว็บ

<form action="process.php" method="POST">
    <!-- แนบ CSRF Token ไว้ใน field แบบ hidden -->
    <input type="hidden" name="csrf_token" value="<?php echo htmlspecialchars($token); ?>">
    
    <label for="username">ชื่อผู้ใช้งาน:</label>
    <input type="text" id="username" name="username" required>
    
    <button type="submit">บันทึกข้อมูล</button>
</form>

3. การตรวจสอบ Token ฝั่ง Server (process.php)

เมื่อมีการกดส่งฟอร์ม เราจะนำ Token ที่ส่งมาผ่าน $_POST ไปเปรียบเทียบกับ Token ที่อยู่ใน $_SESSION โดยใช้ฟังก์ชัน hash_equals() เพื่อป้องกันการโจมตีแบบ Timing Attack

<?php
session_start();

if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    $userToken = $_POST['csrf_token'] ?? '';
    $sessionToken = $_SESSION['csrf_token'] ?? '';

    // ตรวจสอบความถูกต้องของ Token
    if (empty($userToken) || !hash_equals($sessionToken, $userToken)) {
        // ถ้า Token ไม่ตรงกัน ให้ปฏิเสธการทำรายการทันที
        http_response_code(403);
        die("Error: การตรวจสอบ CSRF Token ล้มเหลว (Invalid CSRF Token)");
    }

    // --- ผ่านการตรวจสอบ! สามารถประมวลผลข้อมูลฟอร์มต่อได้ปลอดภัย ---
    $username = $_POST['username'] ?? '';
    
    // (ตัวอย่าง) ทำการบันทึกข้อมูลลง Database
    echo "บันทึกข้อมูลสำเร็จ! ยินดีต้อนรับ " . htmlspecialchars($username);

    // คำแนะนำ: ควรลบหรือหมุนเวียน Token ใหม่หลังจากใช้งานเสร็จแล้ว
    unset($_SESSION['csrf_token']);
} else {
    // ปฏิเสธหากไม่ได้ส่งมาด้วย POST
    header("Location: index.php");
    exit;
}
?>

3 ข้อควรจำเพื่อความปลอดภัยสูงสุด

  1. ใช้ hash_equals() เสมอ: หลีกเลี่ยงการใช้ == หรือ === ในการเปรียบเทียบ Token เพราะอาจเปิดช่องโหว่ด้าน Timing Attack ได้
  2. ใช้ random_bytes(): อย่าใช้ฟังก์ชันสุ่มแบบเก่าอย่าง rand() หรือ uniqid() เพราะเดารูปแบบได้ง่าย
  3. regenerate token เมื่อสำคัญ: สำหรับฟอร์มที่สำคัญมากๆ เช่น เปลี่ยนรหัสผ่าน หรือโอนเงิน ควรทำการลบ Token เก่าทิ้ง (unset) แล้วสร้างใหม่ทุกครั้งหลังใช้งานเสร็จ

อ่านเพิ่มเติม

  • Cross-Site Scripting
  • Cross-Origin Resource Sharing
  • Pseudo-Random
Read MoreRead More

Posts pagination

ก่อนหน้า 1 … 1,011 1,012 1,013 … 1,196 ถัดไป

Projects

  • Statement Columns Mapping Helper
  • PlusMagi Site Search
  • jQuery Plus Repeater

Recent Posts

  • PHP: การอัปเดต PHP เวอร์ชันใหม่อยู่เสมอเพื่อรับ Patch ความปลอดภัย
  • PHP: การบีบอัด Output ด้วย Gzip/Deflate
  • SecDevOps: เปลี่ยนความปลอดภัยให้เป็นเนื้อเดียวกับ Code และ Operation
  • WordPress: ดูว่า post ทุก ๆ วันเสาร์ใช่มั๋ย
  • เทคนิคตั้งค่า umask 002 ให้กับทุก User บน Mac อัตโนมัติผ่าน Terminal (Batch Script)

Archives

Categories

  • AI (26)
  • Businesses (28)
  • Design (56)
    • UX/UI (22)
  • Histories (16)
  • Life (120)
    • Books (51)
    • Cartoon (6)
    • Movies (11)
    • Sci-Fi (20)
    • Tips and Tricks (26)
    • พุทธ (7)
  • Network (146)
    • Apache HTTP Server (17)
    • IOT (1)
    • Nginx (31)
    • Stalwart (6)
  • Operating Systems (280)
    • Unix-like (205)
      • Android (16)
        • F-Droid (5)
      • Homebrew (21)
      • iPhone (8)
      • Linux (119)
      • macOS (100)
        • OrbStack (11)
      • Oh My ZSH (4)
      • Shell Script (41)
      • SSH (11)
    • Windows (121)
      • PowerShell (26)
      • WSL (25)
  • Programming (811)
    • .NET (20)
      • .NET Core EF (6)
      • C# (18)
    • API (38)
      • REST (8)
      • Swagger (7)
    • Database (189)
      • DBeaver (3)
      • MariaDB (32)
      • MySql (69)
      • Oracle Database (6)
        • 10g (3)
      • PostgreSQL (9)
      • RDBMS (2)
      • SQL Server (85)
        • SSMS (8)
        • T-SQL (26)
      • SQLite (1)
    • PowerBuilder (11)
    • Python (6)
    • Rust (5)
    • System Analyst (SA) (37)
    • Testing (27)
      • Automated Testing (13)
        • Playwright (6)
    • UML (7)
    • Web (436)
      • Backend (292)
        • Golang (2)
        • Java (49)
          • Spring Boot (14)
        • Node.js (3)
        • PHP (243)
          • Laravel (50)
          • Yii (5)
      • Frontend (136)
        • CSS (18)
          • Tailwind CSS (5)
        • JavaScript (123)
          • Angular (3)
          • jQuery (62)
          • Tabulator (19)
          • Vue.js (5)
      • WordPress (26)
  • Programs (104)
    • Excel (12)
  • SecDevOps (95)
    • CI/CD (9)
    • Docker (41)
    • GIT (33)
  • Security (110)
  • Uncategorized (6)
  • กฎหมาย (9)

Sirat WordPress Theme By VWThemes

Scroll Up
Go to mobile version