פתרון פשוט למניעת ספאם באתרים
11 באפריל, 2007, 18:30 IDT | מאת Tomer Cohen |הבטחתי ללא מעט אנשים לספר על הפתרון שלי לבעיות ספאם באתרים שאני מנהל, וכיצד באמצעות קוד פשוט אפשר לעצור לחלוטין כל תוכנה אוטומטית שמטרתה לזבל את האתר ולגרום למנהליו להשקיע את זמנם במחיקת הודעות ותגובות ולא בהשקעה בדברים קצת יותר חשובים.
נתחיל מההתחלה. במשך תקופה ארוכה שיחקתי במשחק חתול ועכבר מול מפיצי הספאם - הם שולחים ספאם, אנחנו מוסיפים שכבת הגנה לאתר. בשלב כלשהו הם מוצאים דרך לשלוח ספאם שיודע להתגבר על ההגנה שלנו, ואנחנו מוסיפים שכבה נוספת של הגנה. ניסינו הכל, החל מחיוב בהרשמה שרק גרם לספאמרים להירשם לאתר, כל מיני קאפאצ'ות שהתבררו כקלות לפיענוח לתוכנות, אימות בדוא"ל שהתברר כלא יעיל ועוד.
החלטתי לנסות את מזלי ולכתוב משהו משלי. רציתי משהו פשוט וקל, שלא ידרוש שינויים רבים בקוד התוכנה, ויהיה כמה שיותר אוניברסלי. משהו שידרוש מינימום התערבות מצד המשתמש אבל יהיה מודולרי כדי שאוכל לשנות ולשפר אותו בקלות בהתאם לבוטים שיצליחו לעקוף אותו בעתיד.במקום להוסיף את הקוד כתוסף למערכות קיימות במקרה הטוב או במקרה הפחות טוב לשנות את קוד המקור של המערכת, החלטתי שהתוכנה שלי צריכה להיות כמה שיותר מינימליסטית ולא לדרוש התקנה מסובכת.
איך זה עובד:
- המשתמש גולש בצורה רגילה באתר.
- ברגע שהוא מנסה לעשות פעולה מיוחדת כגון פרסום תגובה באתר, מופעל קוד אימות.
- אם המשתמש מורשה לגישה לדף הוא מועבר כלאחר כבוד לדף המתאים.
- אם המשתמש לא מצליח לעבור את האימות כנראה והוא רובוט והוא איננו מורשה לעבור לדף המבוקש.
מאחר ומנגנון האימות לא נחוץ במידה והמשתמש כבר אומת בעבר, אין צורך להציק לו שוב, ולכן מנגנון האימות משתיל לו עוגיית אימות במחשב ("אסימון"). קוד העוגיה אמור להיות שונה מאתר לאתר, אחרת הספאמרים ידעו תמיד להסתובב עם העוגייה המתאימה.
עוגיות ניתן להשתיל באמצעות תסריטים בצד השרת ובצד הלקוח. כאשר טוענים אותן בצד השרת הלקוח מקבל אותן בתור קוד HTTP/1.1 רגיל, ולכן מרבית הבוטים יודעים למשוך אותן כמו שצריך. כאשר מדובר בקוד בצד לקוח בשפת JavaScript, לבוט המחמד שלנו הרבה יותר קשה להבין מה הוא אמור לעשות, ולכן הוא לא מצליח לאכול את העוגייה. אם נדרשת פעולה מצד המשתמש המצב אפילו גרוע יותר, והבוט לא יוכל לעולם לבצע את הפעולה בצורה אוטומטית.
חסרונות השיטה
- חסימת דפים מסויימים תמנע יכולת קריאה שלהם על־ידי בוטים. גם הזחלנים של גוגל הם בוטים ולכן גם הם יתקעו בהגנה. לא כדאי להוסיף קוד שיאפשר להם להיכנס כדי לא להשאיר פתח לזבלנים להתחזות לבוטים ידידותיים ולחדור אלינו לאתר. כאשר מדובר רק בעמודי הרישום ופרסום התגובות באתר אין בכך נזק משמעותי שכן אין בעמודים אלו תוכן משמעותי.
- מאחר והפתרון מתבסס על Cookies, הדפדפנים של כלל המשתמשים חייבים לא לחסום את טעינת העוגיות מהאתר. אם המשתמש חוסם את העוגיות הוא יתקע יחד עם הבוטים בהסגר, ולא יצליח לעשות פעולות מסויימות באתר. אם עמוד ההסגר יסביר למשתמש שהוא אמור לא למנוע את טעינת העוגיות כולם יהיו מרוצים. לא שמעתי על הרבה אנשים שחוסמים עוגיות בימנו.
- המשתמש חייב להיות מצוייד בדפדפן שכולל תמיכה ב־JavaScript. משתמשי lynx יאלצו להישאר בחוץ.
הטמעה באתר
כאמור, רציתי להתבסס כמה שפחות על קוד בצד השרת, ועם שינויים מינימליים בתוכנות שרצות על השרת. החלטתי להשתמש ב־mod_rewrite של שרת Apache, כדי שלא אצטרך לגעת בשום רכיב באתר.
קובץ ה־.htaccess בתיקייה בה נמצאים הקבצים הבעיתיים יראה כך:
RewriteEngine on
RewriteCond %{HTTP_COOKIE} !nospam_token=welcome
RewriteRule posting.php|login.php|profile.php /spam_jail/index.html
הוראות אלו יגרמו לכל מי שמנסה לגשת לדפים posting.php, login.php או profile.php (שלושת הקבצים הבעיתיים ביותר במערכות פורומים מסוג phpbb) לקבל דף HTML מיוחד במקום הדף שהם ביקשו, כאשר אין להם עוגייה nospam_token עם הערך "welcome". תרגישו חופשיים לשנות את שם העוגיה (האסימון) ואת הערך (הסיסמה) שלה.
מאחר ומבחינת המשתמש לא העברנו אותו לדף אחר, ובשורת הכתובת עדיין נמצאת הכתובת של הדף אליו הוא מנסה להגיע, אנחנו יכולים להטעין את העוגיה בדפדפן ולאחר מכן לטעון מחדש את הדף כדי שהמשתמש יועבר לדף אותו הוא ביקש מראש.
דף ההסגר (שימו לב - אין שום תסריט בצד השרת) יכיל מינימום קוד כדי שהוא יעלה מהר, אבל גם הנחיות למשתמשים שנתקעים בו. כדאי להפנות אותם למקום בו יוכלו לקבל תמיכה נוספת כדי לא לאבד אותם בעקבות הגנה מסיבית או לא ידידותית.
אני משמיט את הקוד הלא רלוונטי לנושא, ומשאיר רק את החלקים החשובים.
טעינת העוגייה. הקוד יעלה את העמוד מחדש כאשר העוגייה קיימת בדפדפן, וינסה להטעין אותה שוב אם לא הצליח בפעם הראשונה. במידה והמשתמש מתבקש לאשר את טעינת העוגייה והוא עונה בסירוב, הוא יתבקש להטעין את העוגיה שוב.
<script language="JavaScript">
function main()
{
createCookie ("nospam_token", "welcome", 30);
if (readCookie("nospam_token")=="welcome")
window.setTimeout ("refresh (true);", 100);
else
window.setTimeout ("main();", 250);
}
</script>
טיפול בעוגיות -
<script language="JavaScript">
function createCookie(name,value,days) {
if (days) {
var date = new Date();
date.setTime(date.getTime()+(days*24*60*60*1000));
var expires = "; expires="+date.toGMTString();
}
else var expires = "";
document.cookie = name+"="+value+expires+"; path=/";
}
function readCookie(name) {
var nameEQ = name + "=";
var ca = document.cookie.split(';');
for(var i=0;i < ca.length;i++) {
var c = ca[i];
while (c.charAt(0)==' ') c = c.substring(1,c.length);
if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length,c.l
ength);
}
return null;
}
טעינת העמוד מחדש. מתברר שזה דבר מסובך, ויש צורך בשלוש פונקציות שונות כדי לתמוך בכל הגירסאות והדפדפנים.
<script language="JavaScript">
function refresh()
{
var sURL = unescape(window.location.pathname);
window.location.href = sURL;
}
</script>
<script language="JavaScript1.1">
function refresh()
{
var sURL = unescape(window.location.pathname);
window.location.replace( sURL );
}
</script>
<script language="JavaScript1.2">
function refresh()
{
window.location.reload( false );
}
</script>
קריאה לקוד מדף ה־HTML -
<body onload="main()">
הקוד הנ"ל יגרום לטעינת עוגיית המפתח עם תאריך תפוגה של שלושים יום לעתיד. החלפת פרטי העוגייה לא תגרום לנעילת משתמשים מחוץ למערכת, אלא לטעינה חוזרת שלה לדפדפן.
מאחר ו־mod_rewrite לא מאפשר העברת טפסים עם נתוני POST, לא ניתן יהיה להכניס את הקוד על מערכת ששולחת תגובות ישירות מדף ההודעה (פה למשל). הפתרון שמצאתי היה לשתול את קוד טעינת העוגיה בעמוד אחר שהמשתמש חייב לעבור בדרכו לעמוד החסום, ובכך לגרום למשתמש שלא יגיע לעולם לדף ההסגר.
עד היום (טפו טפו טפו) לא נתקלתי בשום בוט שהצליח לעקוף את ההגנה. ברגע שהם יצליחו, פשוט צריך להחליף את קוד טעינת העוגייה בכזה שידרוש את מוערבות המשתמש, כאשר תשובתו לשאלה תהיה קוד העוגייה, כך שהסיסמה כלל לא תהיה בדף שזמין למשתמש.
עוד באותו נושא
- שחר שמש מציע אתגר חישובי למניעת משלוח ספאם
- מרק קפלון מסנן הודעות בוורדפרס שאינן כוללות תווים בעברית
- זיו פוגטש מציע שימוש ב־AJAX כדי להקשות כניסת זבלנים
תגיות: Spam
שליחת טראקבק מהאתר שלך

7 תגובות עבור “פתרון פשוט למניעת ספאם באתרים”
מאת הומר בתאריך 12 באפריל, 2007 | תגובה
זה אמור לעבוד בבלוגלי, כלומר בבלוג שלך?
מאת תומר בתאריך 12 באפריל, 2007 | תגובה
הקוד לא דורש שינויים מיוחדים כדי לעבוד גם במערכות מבוססות Wordpress, אלא שבשרתי איחסון ציבוריים דוגמת בלוגלי המשתמש איננו מסוגל לגעת בקונפיגורצית השרת.
אלעד/תום/חנית - רוצים לעשות ניסוי קטן?
מאת אלעד בתאריך 12 באפריל, 2007 | תגובה
תומר - אנחנו עושים ניסיון עם משהו דומה. כמה תגובות ספאם אתה מקבל בבלוג שלך כאן?
מאת תומר בתאריך 12 באפריל, 2007 | תגובה
אלעד - לא מעט, אני משער שבסביבות ה־20 ביום, לפחות.
מאת אלעד בתאריך 12 באפריל, 2007 | תגובה
תגיד לי בבקשה במשך היום האם יש שינוי?
מאת עמרי בתאריך 16 בספטמבר, 2007 | תגובה
אז מספיק שספאמר אנושי יפתור את הקפצ'ה פעם אחת כדי שהאתר שלך יפתח לגמרי לבוטים שלו.
נשמע לי כמו שכבת הגנה די דקה.
מאת תומר בתאריך 16 בספטמבר, 2007 | תגובה
מניסיון שלי, אף בוט לא חדר הגנה כזו, גם כאשר הקוד שצריך להכניס לעוגיה נמצא ב־clear text בדף טעינת העוגיה.
בל נשכח שהבוטים שתוקפים אותנו הם בדרך־כלל ממוכנים לחלוטין, ואינני בטוח שיש למפעיל שלהם בכלל אפשרות להגדיר להם עוגיות כפרמטר. גם הגנות captcha ניתנות לעקיפה, מהסיבה הפשוטה שהם לא דורשות קוד חדש עבור כל פעולה. הספאמרים מעדיפים לשלם לטוקבקיסטים מאשר לשלם למפצחי קפאצ'ות מתמחים.