ข้ามไปที่เนื้อหาหลัก

PHP การล็อกอิน กับปัญหา SQL Injection

       หลังจากได้เข้าร่วมอบรม Website Security Monitoring ที่ทางสำนักวิทยบริการและเทคโนโลยีสารสนเทศ ของมหาวิทยาลัยจัดขึ้น ก็ได้ความรู้เรื่องการสร้างระบบล็อกอินเพื่อป้องกันปัญหา SQL Injection มาฝากกับผู้เริ่มต้นทุกท่าน
สำหรับการป้องกันนั้นจะมีอยู่หลายวิธี และวิธีหลักที่ใช้กันก็คือ
กรองด้วยฟังก์ชั่น mysql_real_escape_string() , mysqli_real_escape_string() ,
(ดูเพิ่มเติมได้ที่ http://php.net/manual/en/function.mysql-real-escape-string.php )

ในกรณีของ id ที่เป็นตัวเลขล้วน ก็สามารถใช้ (int) วางไว้ข้างหน้าตัวแปรเพื่อป้องกันข้อมูลในหน้าอื่นๆได้เช่นกัน

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

จากบทความที่เคยนำเสนอเกี่ยวกับการสร้างแบบฟอร์มล็อกอิน
จะใช้ SQL ในการตรวจสอบข้อมูลแบบเบื้องต้นดังนี้
$sql = "SELECT * FROM tb_user WHERE user_name = '$_POST[username]'
           AND user_password = '". $_POST['password'] ."' ";

ตัวอย่างฐานข้อมูลตารางผู้ใช้งาน


ฐานข้อมูล ตาราง ผู้ใช้งาน



เมื่อล็อกอินด้วยชื่อ sunzandesign และรหัสผ่าน abcd จะสามารถเข้าใช้งานได้

php login form

ก็จะได้ผลลัพธ์การล็อกอิน ดังนี้

php login corect



แต่ถ้าเรากรอกชื่อผู้ใช้งานผิด การล็อกอินก็จะแสดงข้อผิดพลาด และให้ล็อกอินใหม่

result login incorect


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

ตัวอย่างเช่น
ชื่อผู้ใช้ = sunzandesign
รหัสผ่าน = xxxx' OR 'A'='A


login with sql injection


ผลลัพธ์ที่ได้คือ ล็อกอินผ่าน!!! เพราะอะไร???
เพราะเราเพิ่มเงื่อนไขเข้าไปคือ นอกจากชื่อรหัสผ่านต้องตรงกับฐานข้อมูลแล้ว
OR 'A' = 'A' ถ้า A มีค่าเท่ากับ A ก็ให้ผ่านไปได้  ((ซึ่งมันก็ต้องตรงกันอยู่วันยังค่ำ = ='))


result is corect by sql injection
ถ้าลองนำโค๊ดที่ได้ไปลองใน phpMyAdmin จะได้ผลลัพธ์ดังนี้

result in phpmyadmin with sql injection


ตอนนี้ก็ทราบกันแล้วว่า SQL แบบที่นำเสนอไปนั้นไม่สามารถใช้กับระบบล็อกอินได้เลย
((รวมถึงหน้าอื่นๆทุกหน้าที่เขียน SQL แบบธรรมดาที่ไม่มีการป้องกันแบบตัวอย่างนี้ ล้วนเป็นช่องโหว่ทั้งหมด >O< ))


แล้วเราจะมีวิธีป้องกัน SQL injection อย่างไร???


ก็ใช้ฟังก์ชั่นดังที่ได้แนะนำไว้ก่อนหน้านี้นั่นก็คือ
ในกรณีรับข้อมูลที่เป็น string (หรือจะเป็น integer ก็ได้)
mysql_real_escape_string()
mysqli_real_escape_string() 



  $sql = "SELECT * FROM tb_user
            WHERE user_name = '". mysql_real_escape_string($_POST['username']) ."'
            AND user_password = '". mysql_real_escape_string($_POST['password']) ."' ";
fix SQL Injection with mysql_real_escape_string


หรือจะใช้วิธี md5() รหัสผ่านไปเลยก็ได้(ซึ่งจริงๆแล้วรหัสผ่านก็ควรจะเข้ารหัสไว้แล้ว) โค๊ดที่ใช้ก็จะเปลี่ยนไปเป็นดังนี้
  $sql = "SELECT * FROM tb_user
            WHERE user_name = '". $_POST['username'] ."'
            AND user_password = '". md5($_POST['password']) ."' ";


ก่อนอื่นก็เข้ารหัสให้กับรหัสผ่านเดิมทั้งหมดในฐานข้อมูลก่อน ก็จะได้ข้อมูลดังภาพ
password with md5 data

ทดลองกรอกข้อมูลที่ถูกต้องในการล็อกอินเพื่อทดสอบ
login with md5 password


จะได้ผลลัพธ์ที่ถูกต้อง
login is corect by md5()
abcd => md5() => e2fc714c4727ee9395f324cd2e7f331f
((ตรงกับข้อมูลในฐานข้อมูล))


แต่ถ้าลองกรอกข้อมูลเพื่อใช้เทคนิค SQL Injection ก็จะไม่สามารถล็อกอินได้
test login with sql injection

login is fail by sql injection

เพราะข้อมูลรหัสผ่านไม่ตรงกับในฐานข้อมูล

xxxx' OR 'A'='A => md5() => c47fef686224b37f5f3350dfae45ca15
((ไม่ตรงกับข้อมูลในฐานข้อมูล))


และวิธีสุดท้ายที่จะนำเสนอในบทความนี้ หากท่านไม่สามารถใช้งาน mysql_real_escape_string() และไม่พร้อมที่ md5() รหัสผ่าน (หรือเข้ารหัสผ่านแบบอื่นๆ) ให้ลองใช้วิธีแยกรหัสผ่านมาตรวจสอบต่างหากด้วยฟังก์ชั่น if else ของ PHP

    $sql = "SELECT user_password FROM tb_user
            WHERE user_name = '". $_POST['username'] ."'";
      $qry = mysql_query($sql) or die(mysql_error());
      $row = mysql_fetch_assoc($qry);
      if(!empty($row) && $row['user_password'] == $_POST['password']){
        echo "<h3 style='color:green'>Login OK!</h3>";
      }else{
        echo "<h3 style='color:red'>Login Fail!</h3>";
     }







"PHP ไม่ได้สร้างสุดยอดโปรแกรม แต่ PHP ช่วยให้งานคุณง่ายขึ้นต่างหาก"

PHP CI MANIA PHP Code Generator 
โปรแกรมช่วยสร้างโค้ด ลดเวลาการเขียนโปรแกรม

สนใจสั่งซื้อเพียง 4,500 บาท
http://fastcoding.phpcodemania.com/

สนับสนุนค่ากาแฟผู้เขียนได้ที่

PayPal

ความคิดเห็น

โพสต์ยอดนิยมจากบล็อกนี้

แจกฟรี!! ระบบต่างๆที่พัฒนาด้วย PHP สำหรับนำไปใช้ในงานต่างๆ

       สำหรับหลายท่านที่ขอโค้ดเข้ามาทาง Inbox ของเฟซบุ๊กแฟนเพจ หรือถามถึงระบบต่างๆหลังไมค์มานั้น ส่วนใหญ่ก็มีแจกอยู่แล้วในเว็บบอร์ด ThaiCreate.Com นะครับ และด้านล่างนี้ก็เป็นระบบต่างๆที่แจกให้นำไปลองใช้ลองศึกษากันครับ

สอนเขียน PHP แสดงการจองห้องประชุมแบบไฮไลท์ตามช่วงเวลา (แบบเชื่อมต่อฐานข้อมูล MySQL)

ตัวอย่าง ผลลัพธ์ที่ได้จากการจองในฐานข้อมูล ตาราง tb_room สร้างตารางรายชื่อห้องประชุม สำหรับ id นั้นเป็น Primarykey จะกำหนดให้สร้างอัตโนมัติ ทุกครั้งที่เราเพิ่มชื่อห้องประชุมใหม่ -- -- Database: `tobedev_example` -- -- -------------------------------------------------------- -- -- Table structure for table `tb_room` -- CREATE TABLE IF NOT EXISTS `tb_room` (   `id` int(11) NOT NULL,   `name` varchar(30) NOT NULL ) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8; -- -- Dumping data for table `tb_room` -- INSERT INTO `tb_room` (`id`, `name`) VALUES (1, 'ห้องประชุม 1'), (2, 'ห้องประชุม 2'), (3, 'ห้องประชุม 3'), (4, 'ห้องประชุม 4'), (5, 'ห้องประชุม 5'); -- -- Indexes for dumped tables -- -- -- Indexes for table `tb_room` -- ALTER TABLE `tb_room`   ADD PRIMARY KEY (`id`); -- -- AUTO_INCREMENT for dumped tables -- -- -- AUTO_INCREMENT for table `tb_room` -- ALTER TABLE `tb_room`   MODIFY `i...

การดึงข้อมูล MySQL มาแสดงในปฏิทิน Fullcalendar ด้วย PHP

หลักการทำงาน เรียกข้อมูลจากตาราง tb_event ด้วยฟังก์ชั่นของ MySQLi ข้อมูลจากฐานข้อมูลจะถูกวนลูปเก็บไว้ใน $data และจะถูกส่งไปที่ Fullcalendar ด้วยการแปลงข้อมูลจาก PHP ให้อยู่ในรูปแบบ JSON อาร์เรย์ด้วยฟังก์ชั่น json_encode() PHP Code <?php //Database $data = array(); $link = mysqli_connect("127.0.0.1", "tobedev", "1234", "tobedev_example"); mysqli_set_charset($link, 'utf8'); if (!$link) {     echo "Error: Unable to connect to MySQL." . PHP_EOL;     echo "Debugging errno: " . mysqli_connect_errno() . PHP_EOL;     echo "Debugging error: " . mysqli_connect_error() . PHP_EOL;     exit; } $query = "SELECT * FROM tb_event"; if ($result = $link->query($query)) {     /* fetch object array */     while ($obj = $result->fetch_object()) {        $data[] = array(                 ...