Bloggang.com : weblog for you and your gang

Group Blog

 
 
พฤศจิกายน 2552
 
1234567
891011121314
15161718192021
22232425262728
2930 
 
19 พฤศจิกายน 2552

 
All Blogs

 

 

เขียนโปรแกรมป้องกัน Spam-Comment บนเว็บไซท์

เขียนโปรแกรมป้องกัน Spam-Comment บนเว็บไซท์
Spam ถือเป็นปัญหาน่ารำคาญ และกำจัดได้ยากบนโลกอินเทอร์เน็ตสมัยนี้ ดังที่คุณเชกูเวรา เคยเขียนรายละเอียดทั้งหมดให้เราอ่านกันมาแล้วครั้งหนึ่ง ใน

Spam, Spim, Spit and Spandy ภาค 1,ภาค 2 และ ภาค 3

BioLawCom.De เอง ก็ประสบปัญหาสแปมบ้างเป็นครั้งคราว แต่เจอแต่ละครั้ง หนักหนาสาหัสไม่น้อย ต้องคอยตามล้างตามเช็ด หาวิธีป้องกันใหม่ ๆ อยู่เรื่อย เหมือนกันครับ ผมคิดว่าในหน้าเว็บไซท์หลาย ๆ แห่งก็ประสบปัญหาเช่นเดียวกัน เลยอยากแลกเปลี่ยนความรู้ในเรื่องนี้กับเพื่อน ๆ ดูบ้าง

ก็อย่างที่คุณเช เคยเขียนไว้ในบล็อกไปแล้วครับว่า การป้องกัน สแปมมีหลายวิธี อาทิ ...
เขียนโปรแกรม


bow_der_kleine



Canceln, UDP ,NoCeM แล้วก็สติ๊กเกอร์ ซึ่งสามวิธีแรกใช้ได้เฉพาะกับ Newsgroup และต้องติดตั้งโปรแกรม เพิ่มเติม ส่วนการติดสติ๊กเกอร์นั้นได้ผลในระดับหนึ่งเท่านั้น กล่าวคือหาก หุ่นยนต์ (Robot) (โปรแกรมที่เหล่า Spammer ใช้ในการหาลิ้งค์ตามหน้าเวบไซท์ต่าง ๆ) สามารถเก็บลิ้งก์ของเราไปได้เรียบร้อยแล้ว การติดสติ๊กเกอร์ก็จะไม่สามารถทำอะไรกับเจ้าหุ่นยนต์นั้นได้

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

ส่วนวิธีการอื่น ๆ ในการป้องกัน Spam-Comment ที่นิยมทำกันได้แก่ regular expression โดยการหารูปแบบ ข้อมูลที่หุ่นยนต์ส่งเข้ามา เมื่อมีการส่งความคิดเห็นไปยังเวบเซิพเวอร์โปรแกรมต้องตรวจสอบทุกครั้ง ว่าความคิดเห็นที่ส่งมาเป็น Spam หรือไม่ โดยใช้ regular expression ผลที่ได้จากวิธีนี้ ไม่คุ้มกับแรงงาน ที่เสียไป เพราะการหารูปแบบข้อมูลที่หุ่นยนต์ส่งเข้ามานั้น ต้องใช้ตรรกะและระยะเวลาในการคิดมาก แต่ Spammer สามารถเปลี่ยนแปลงข้อมูลเพียงเล็กน้อยก็สามารถเล็ดรอดระบบเข้าไปได้

วิธีที่นิยมใช้และได้ผลมากคือการแยกหุ่นยนต์ออกจากคน โดยใช้ robot.txt แต่วิธีการนี้จะใช้ไม่ได้ผล กับหุ่นยนต์ที่ปลอมตัวเก่ง สามารถปลอมเป็นคนเข้ามาส่ง spam ได้ วิธีการใช้วิธีแยกหุ่นยนต์ออกจากคน

อีกวิธีที่ได้ผลกว่าการใช้ robot.txt คือการสร้างไฟล์ภาพที่มีรหัสลับอยู่ในรูปภาพขึ้น จากนั้นก็ให้คนที่ต้องการ แสดงความคิดเห็นอ่านรหัสลับจากรูปภาพดังกล่าว แล้วส่งรหัสลับพร้อมกับความคิดเห็นไปยังเซิพเวอร์ หากรหัสลับถูกต้องความคิดเห็นก็จะได้รับการบันทึกลงในระบบ เนื่องจากหุ่นยนต์ไม่สามารถอ่านรหัสลับ จากรูปภาพได้ จึงไม่สามารถเล็ดรอดเข้าไปปล่อย Spam ในระบบได้ แต่วิธีการนี้เป็นการเพิ่มภาระให้ระบบ ในการสร้างไฟล์ภาพ และเพิ่มภาระอีกเล็กน้อยให้ผู้แสดงความคิดเห็นในการใส่รหัสลับ แต่ถือว่าเป็นวิธีการ ที่ดีมากอีกวิธีหนึ่ง

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

วิธีที่ใช้ในเวบ BioLawCom ของเราขณะนี้ เป็นวิธีที่นำหลักการของสติ๊กเกอร์มาปรับปรุงให้มีประสิทธิภาพ มากขึ้น โดยการเปลี่ยนชื่อลิ้งก์ที่นำไปสู่ส่วนที่ต้องแสดงความคิดเห็นในเวบไซท์อยู่ตลอดเวลา ทำให้หุ่นยนต์ ที่เข้ามาในเวบไซท์ต้องเก็บข้อมูลใหม่ทุกครั้งที่เข้ามา ทำให้หุ้นยนต์ทำงานมากขึ้น แต่ก็ไม่สามารถส่ง Spam เข้าสู่ระบบได้

สุดท้ายไม่ว่าเจ้าหุ่นยนต์ส่งสแปมจะยอมแพ้หรือไม่ ประสิทธิภาพการทำงานของมันก็จะลดลงไปเรื่อย ๆ โดยที่ระบบของเราแทบไม่ได้รับผลกระทบใด ๆ เลย เพื่อให้ง่ายต่อการเขียน ผมขอเรียกวิธีนี้ว่า Poison URL แล้วกันครับ

วิธีการนี้ตรงข้ามกับระบบ Friendly URL ที่ใช้บน CMS (Content Management System) หลาย ๆ ตัว Friendly URL ถูกพัฒนาขึ้นเพื่อให้ Search Engine ต่าง ๆ เก็บข้อมูลที่มีอยู่ในเวบไซท์ของเราได้ง่ายขึ้น

คำถามที่เกิดขึ้น คือ หากใช้ Poison URL แล้วจะส่งผลกระทบต่อ rating ของเวบไวท์บน Search Engine หรือไม่ ผมตอบอย่างไม่ลังเลครับว่า เกิดขึ้นอย่างแน่นอน แต่ที่สำคัญคือค่อนข้างน้อย เนื่องจาก Search Engine ใช้ meta-data พวก title, keywords และ description ในการเก็บข้อมูลมากกว่าการใช้ URL ซึ่งเท่าที่ผมทดลองใช้ Poison URL มาเป็นระยะเวลาเกือบสามเดือน ก็ไม่เห็นผลกระทบที่ชัดเจนสำหรับ rating ของเวบไซท์บน Search Engine (Google และ Yahoo! ยังคงเก็บข้อมูลจากเวบไซท์ของเราอย่างต่อเนื่อง)

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

ดังนั้นสิ่งสำคัญที่สุดสำหรับ Poison URL คือข้อมูลตรวจสอบที่ซ่อนอยู่ใน URL และ Form ต้องได้รบการ เปลี่ยนแปลงตลอดเวลา โดยที่ผู้ใช้งานไม่รับรู้ถึงการเปลี่ยนแปลงดังกล่าว และระบบสามารถตรวจสอบได้ว่า ข้อมูลตรวจสอบดังกล่าวถูกต้องหรือไม่ การเปลี่ยนแปลงข้อมูลตรวจสอบตลอดเวลา ทำให้สแปมที่สามารถ หลุดรอดเข้าสู่ระบบมาได้นั้นสามารถเข้ามาได้เพียงครั้งเดียว การเข้ามาครั้งต่อ ๆ ไป เจ้าหุ่นยนต์ส่งสแปม ต้องเก็บข้อมูลตรวจสอบไปอีกครั้ง ดังนั้น หุ่นยนต์สามารถทำได้อย่างมากเพียงแค่แลกหมัดกับเราเท่านั้น เพราะข้อมูลตรวจสอบที่หุ่นยนต์เก็บไปนั้น

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

สิ่งที่เราต้องการในการผลิตและเปลี่ยนแปลงข้อมูลตรวจสอบคือ เครื่องมือสำหรับสุ่มข้อมูล (random) ในผลิตข้อมูลตรวจสอบที่มีประสิทธิภาพ และ เครื่องมือสำหรับตรวจสอบเวลา (cron) เป็นเหมือนนาฬิกาปลุก เพื่อให้ระบบเปลี่ยนแปลงข้อมูลตรวจสอบได้ในระยะเวลาที่เหมาะสม

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


function generate_key($length){
$extrakey="";
for($j=0;$j<$length;$j++){
while(true){
mt_srand((double)microtime()*1000000);
$zufall=mt_rand(48,122);
if(($zufall>=48 && $zufall<=57) ||
($zufall>=65 && $zufall<=90) ||
($zufall>=97 && $zufall<=122)){
$extrakey.=chr($zufall);
break;
}
}
}
return $extrakey;
}plain code function generate_key($length){
$extrakey="";
for($j=0;$j<$length;$j++){
while(true){
mt_srand((double)microtime()*1000000);
$zufall=mt_rand(48,122);
if(($zufall>=48 && $zufall<=57) ||
($zufall>=65 && $zufall<=90) ||
($zufall>=97 && $zufall<=122)){
$extrakey.=chr($zufall);
break;
}
}
}
return $extrakey;
} highlighted code


พาราเมเตอร์ $length เป็นตัวกำหนดจำนวนตัวอักษรของข้อมูลตรวจสอบ และเพื่อไม่ให้เกิดปัญหาอื่น ๆ ตามมาภาพหลัง ฟังก์ชั่น generate_key จึงผลิตข้อมูลตรวจสอบเฉพาะ a-z, A-Z และ 0-9 เท่านั้น

ข้อมูลตรวจสอบที่ได้จะถูกเก็บไว้ในฐานข้อมูล เพื่อนำมาใช้ในภายหลัง ฐานข้อมูลนอกจากจะเป็นที่เก็บข้อมูล แล้ว ยังสามารถใช้เป็นนาฬิการปลุกในกำหนดเวลาเปลี่ยนข้อมูลตรวจสอบได้อีกด้วย


function generate_daykey(){
// create table daykey(
// `id` int(10) unsigned NOT NULL auto_increment,
// `key1` varchar(50),
// `key2` varchar(50),
// `key3` varchar(50),
// `key4` varchar(50),
// `key5` varchar(50),
// `generate_on` datetime,
// PRIMARY KEY (`id`)
// ) TYPE=MyISAM;
if(mysql_num_rows(three_query(
"SELECT id FROM daykey WHERE generate_on>(NOW()-1000);"))
== 0){
$key1=generate_key(5);
$key2=generate_key(5);
$key3=generate_key(5);
$key4=generate_key(5);
$key5=generate_key(5);
three_query("INSERT INTO
daykey(key1,key2,key3,key4,key5,generate_on)
VALUES('$key1','$key2','$key3','$key4','$key5',NOW());");
three_query("DELETE FROM daykey
WHERE generate_on<(NOW()-60000);");
three_query("OPTIMIZE TABLE `daykey`;");
}
}plain code function generate_daykey(){
// create table daykey(
// `id` int(10) unsigned NOT NULL auto_increment,
// `key1` varchar(50),
// `key2` varchar(50),
// `key3` varchar(50),
// `key4` varchar(50),
// `key5` varchar(50),
// `generate_on` datetime,
// PRIMARY KEY (`id`)
// ) TYPE=MyISAM;
if(mysql_num_rows(three_query(
"SELECT id FROM daykey WHERE generate_on>(NOW()-1000);"))
== 0){
$key1=generate_key(5);
$key2=generate_key(5);
$key3=generate_key(5);
$key4=generate_key(5);
$key5=generate_key(5);
three_query("INSERT INTO
daykey(key1,key2,key3,key4,key5,generate_on)
VALUES('$key1','$key2','$key3','$key4','$key5',NOW());");
three_query("DELETE FROM daykey
WHERE generate_on<(NOW()-60000);");
three_query("OPTIMIZE TABLE `daykey`;");
}
} highlighted code


โค้ดที่อยู่ในคอมเมนต์คือโค้ด mysql สำหรับสร้างตารางเก็บข้อมูลตรวจสอบ ฟังก์ชั่น three_query() เป็นฟังก์ชั่นที่ผมเขียนขึ้นมาเอง ซึ่งไม่ได้มีอะไรพิเศษมากมาย การทำงานเหมือนกับ mysql_query() ปกติทั่วไป

ฟังก์ชั่น generate_daykey() จะทำการตรวจสอบก่อนว่าถึงเวลาที่ต้องเปลี่ยนข้อมูล หรือไม่ โดยใช้คำสั่ง WHERE generate_on>(NOW()-1000) generate_on เป็นข้อมูลประเภท date_time บนฐานข้อมูล mysql สำหรับ NOW()-1000 คือเวลา 1000 วินาทีก่อนหน้านี้ ดังนั้นคำสั่ง WHERE generate_on>(NOW()-1000) จึงใช้ตรวจสอบว่ามีข้อมูลตรวจสอบที่มีอายุเกินกว่า 1000 วินาทีหรือไม่ หากมีให้ผลิตข้อมูลตรวจสอบใหม่ ลบข้อมูลตรวจสอบที่มีอายุเกิน 60000 วินาทีทิ้ง และ Optimize ตารางที่ใช้บันทึกข้มูลตรวจสอบ เนื่องจาก ตารางถูกเปลี่ยนแปลงข้อมูลบ่อย ดังนั้นการ Optimize จึงเป็นเรื่องที่จำเป็น

นั่นหมายความว่าข้อมูลตรวสอบจะถูกใช้งานภายในระยะเวลา 1000 พันวินาที และมีอายุการใช้งาน 60000 วินาที เราจึงมีข้อมูลตรวจสอบอยู่ในตารางประมาณ 60 ชุด โดยแต่ละชุดมีรูปแบบให้เลือกใช้งานแตกต่างกัน 5 รูปแบบ (key1 - key5)

การลดระยะเวลาการใช้งานของข้อมูลตรวจสอบจะทำให้ระบบถูกเจาะได้ยากขึ้น แต่ระบบต้องทำงานหนักขึ้น ส่วนการลดอายุของข้อมูลทำให้ระบบถูกเจอาะยากขึ้นแต่ผู้เยี่ยมชมเวบมีเวลาเขียนความคิดเห็นน้อยลง ส่วนการเพิ่มความยาวของข้อมูลตรวจสอบก็จะทำให้ระบบเก็บข้อมูลมากขึ้น

ดังนั้นไม่ว่าจะเป็นระยะเวลาการใช้งาน อายุการใช้งาน และความยาวของข้อมูลตรวจสอบต้องมากเท่าที่จำเป็น และน้อยที่สุดเท่าที่จะเป็นไปได้ เพื่อให้ระบบทำงานได้เต็มประสิทธิภาพมากที่สุด

เมื่อเราสามารถผลิตข้อมูลตรวจสอบได้แล้ว ขั้นต่อมาคือการนำมาใช้งาน การใช้งานข้อมูลตรวจสอบเราต้องการอีกสองฟังก์ชั่นคือ


function get_daykey($index){
return mysql_result(three_query(
"SELECT key$index FROM daykey ORDER BY id DESC LIMIT 1"),0,0);
}plain code function get_daykey($index){
return mysql_result(three_query(
"SELECT key$index FROM daykey ORDER BY id DESC LIMIT 1"),0,0);
} highlighted code


สำหรับเรียกข้อมูลตรวจสอบเพื่อนำมาใช้งาน และ


function exist_daykey($index,$key){
$day_key=three_query(
"SELECT id FROM daykey WHERE key$index='$key';");
(mysql_num_rows($day_key) !=0)?$exist=true:$exist=false;
return $exist;
}plain code function exist_daykey($index,$key){
$day_key=three_query(
"SELECT id FROM daykey WHERE key$index='$key';");
(mysql_num_rows($day_key) !=0)?$exist=true:$exist=false;
return $exist;
} highlighted code


สำหรับตรวจสอบว่าข้อมูลตรวจสอบถูกต้องหรือไม่

การส่งข้อมูลตรวจสอบเพื่อป้องกันสแปมนั้นมีสองขั้นตอนดังที่ได้กล่าวไปแล้ว คือ ในขั้นตอนของการตรวจสอบ ผ่านลิ้งก์ และขั้นตอนการตรวจสอบผ่าน Form ดังนั้นระบบ Poison URL จึงต้องไฟล์ php ทั้งหมดสามไฟล์

โดยไฟล์แรก เป็นไฟล์ที่แสดงลิ้งก์ไปยัง Form ที่ใช้กรอกข้อมูลสำหรับแสดงความคิดเห็น ไฟล์ที่สอง ใช้ตรวจสอบ URL และส่งข้อมูลตรวจสอบต่อไปยังไฟล์ที่สาม ส่วนไฟล์ที่สามมีหน้าที่ตรวจสอบข้อมูล และบันทึกความคิดเห็น

หน้าตาโค้ดของไฟล์แรกจะมีหน้าตาประมาณนี้


generate_daykey();
echo("guestbook");
?>plain code generate_daykey();
echo("guestbook");
?> highlighted code


ไฟล์แรกไม่มีหน้าที่อื่นใดนอกจากผลิตข้อมูลตรวจสอบด้วย generate_daykey() และรับข้อมูลจากฟังก์ชั่น get_daykey() ส่งไปให้ไฟล์ที่สอง คือ guestbook.php ทำการจรวสอบตัวแปร $GET[daykey] ดังนี้

if(exist_daykey(1,$_GET[daykey])){
echo("



  *ใช้ code html ตกแต่งข้อความได้เฉพาะสมาชิก
 
รหัสส่งข้อความ
กรุณายืนยันรหัสส่งข้อความ

nampuppa.nam

Location :
นครปฐม Thailand

[ดู Profile ทั้งหมด]


My FriendFlock
ฝากข้อความหลังไมค์
Rss Feed

 
Friends' blogs
[Add nampuppa.nam's blog to your weblog]
Links
 

 

 

Pantip-Cafe | Pantip-TechExchange | PantipMarket.com | Pantown.com | © 2004 BlogGang.com allrights reserved.