מודל האבטחה של כתיבה אנונימית
שלוש עובדות קובעות את הארכיטקטורה של כל פיצ’ר שבו גולש לא מזוהה כותב ל‑CRM. קראו לפני שמישהו “מתקן” הרשאות כדי שטופס יעבוד.
1 · ב‑REST כתיבה אנונימית נעצרת בשער ה‑CAPTCHA
Section titled “1 · ב‑REST כתיבה אנונימית נעצרת בשער ה‑CAPTCHA”# ✘ כתיבה אנונימית ישירה — נדחיתcurl -sS -X POST "https://api.mbapps.co.il/parse/classes/Accounts" \ -H "X-Parse-Application-Id: $APP_ID" \ -H "Content-Type: application/json" \ -d '{"Name":"ישראל ישראלי"}'// ✘ כתיבה אנונימית ישירה — נדחיתconst res = await fetch("https://api.mbapps.co.il/parse/classes/Accounts", { method: 'POST', headers: { 'X-Parse-Application-Id': APP_ID, 'Content-Type': 'application/json', }, body: JSON.stringify({ Name: 'ישראל ישראלי' }),});# ✘ כתיבה אנונימית ישירה — נדחיתimport requests
res = requests.post( "https://api.mbapps.co.il/parse/classes/Accounts", headers={ "X-Parse-Application-Id": APP_ID, "Content-Type": "application/json", }, json={"Name": "ישראל ישראלי"},)<?php// ✘ כתיבה אנונימית ישירה — נדחית$ch = curl_init();curl_setopt_array($ch, [ CURLOPT_URL => "https://api.mbapps.co.il/parse/classes/Accounts", CURLOPT_POST => true, CURLOPT_RETURNTRANSFER => true, CURLOPT_HTTPHEADER => [ "X-Parse-Application-Id: {$APP_ID}", "Content-Type: application/json", ], CURLOPT_POSTFIELDS => json_encode(["Name" => "ישראל ישראלי"], JSON_UNESCAPED_UNICODE),]);$response = curl_exec($ch);curl_close($ch);{ "code": 119, "error": "This action is not allowed without a valid CAPTCHA" }אותה תשובה חוזרת על Sales, על טבלה מותאמת, ואפילו על שם מחלקה שאינו קיים: השער לא מסתכל על הטבלה. הדחייה נשארת גם אחרי create: {"*": true} ב‑CLP, וגם POST /parse/users נעצר בה.
שדה טוקן מומצא, או טוקן של שירות CAPTCHA אחר, לא פותח את השער. השרת מקבל רק טוקן reCAPTCHA טרי (עד 2 דקות) של הפלטפורמה עצמה, וטוקן כזה מפיק רק טופס בדף של אתר ה‑CRM שלכם — המסלול השני בטבלה למטה. מקוד צד שרת, מאתר חיצוני או מ‑curl אין מסלול יצירה אנונימית ב‑REST.
שלושת המסלולים שכן עוברים
Section titled “שלושת המסלולים שכן עוברים”יצירה אנונימית עצמה אינה חסומה במוצר. יש לה שלושה מסלולים:
| המסלול | מי עובר את שער ה‑CAPTCHA | מה קובע מה מותר לכתוב |
|---|---|---|
פונקציות הטפסים: web2table, web2case, getlead |
הפונקציה רצה בצד שרת ואינה נדרשת לשער | דגל ה‑Config והוולידציה של הפונקציה. ה‑CLP של טבלת היעד אינו נבדק |
| טופס UI בדף ייעודי במערכת | ה‑CAPTCHA שבדף | הרשאות הטבלה (CLP) — הן ורק הן |
טופס בדף במערכת במצב capture-data (data-use-caputure-data="true") | ה‑reCAPTCHA הבלתי נראה שבדף; הפונקציה simbla-capture-data מאמתת אותו (רכיב גלוי לא עובד) | שורת Config בשם CaptureData<Table>: שדות חובה, זיהוי כפילויות וברירות מחדל. ה‑CLP של הטבלה אינו נבדק — היא נשארת סגורה |
2 · web2table רץ מוגבה ועוקף CLP
Section titled “2 · web2table רץ מוגבה ועוקף CLP”הפונקציה רצה עם Master Key מוזרק, ולכן ה‑CLP לא חוסם אותה. היא יוצרת שורות גם בטבלה שה‑CLP שלה הוא create: role:Admin בלבד.
| ההנחה השגויה | המציאות |
|---|---|
| “צריך לפתוח את הרשאות טבלת היעד כדי ש‑web2table יוכל לכתוב” | לא. הוא עוקף את ה‑CLP ממילא — גם מול CLP סגור לחלוטין |
| “אם הטופס מחזיר שגיאה, זו בעיית הרשאות” | לא. השגיאה היא 400 "… is Disabled" — דגל ה‑Config, לא CLP |
הפונקציה היא הגבול בין העולם האנונימי לנתונים: היא מחליטה מה מותר לכתוב, לאילו שדות ובאיזה טיפוס. אותה מגדירים, לא את ההרשאות.
הפונקציה כותבת לכל מחלקה ששמה נשלח ב‑table. קבעו את הערך בקוד או בשרת הביניים — לעולם לא מקלט של הגולש.
3 · web2table הוא create‑only
Section titled “3 · web2table הוא create‑only”objectId או table_objectId בבקשה לא מעדכנים אלא נזרקים, וכל קריאה מוסיפה שורה: קריאה שנייה עם ה‑objectId הקיים מחזירה מזהה חדש, בטבלה יהיו שתי שורות לאותו טלפון, והשורה המקורית לא משתנה.
גם המסלול הישיר סגור: PUT אנונימי על שורה קיימת נדחה, וכך גם DELETE (Permission denied for action delete on class …). בפונקציות הטפסים אין מסלול עדכון או מחיקה אנונימי, ואל תייצרו כזה בפתיחת update / delete ל‑* ב‑CLP. שער ה‑CAPTCHA אינו חל על עדכונים — ה‑CLP הוא שעוצר אותם, ולכן ההודעה כאן היא Permission denied. כל עוד update ו‑delete סגורים, אין מסלול כזה.
“שהלקוח יאשר את הפגישה מקישור במייל”, “שימלא דירוג אחרי שירות”, “שיעדכן כתובת מקישור”: לא נבנות כעדכון ישיר.
מה עושים כשצריך בכל זאת “עדכון מקישור ציבורי”
Section titled “מה עושים כשצריך בכל זאת “עדכון מקישור ציבורי””טבלת קליטה + טריגר השלכה:
דף ציבורי ──web2table──▶ טבלת קליטה ייעודית ──טריגר data-change──▶ אובייקט העסק(אנונימי) (יומן גולמי, (טבלה סגורה נפתחת לקליטה) לחלוטין)- הדף הציבורי יוצר שורה בטבלת ביניים שנועדה לקליטה בלבד — דרך web2table, או בטופס נייטיבי בדף של אתר ה‑CRM.
- טריגר data change על טבלת הקליטה משליך את הערכים על אובייקט העסק, פעולת
update-objectעםconnection: "source.<שדה Pointer>". - טבלת העסק נשארת סגורה לכתיבה אנונימית.
שלוש השלכות שכדאי לתעד מראש
Section titled “שלוש השלכות שכדאי לתעד מראש”- הקישור חייב לשאת
phone, שדה חובה ב‑web2table. טלפון של לקוח נוסע ב‑URL ונוחת בלוגים של שרתים, ב‑Referer ובהיסטוריית הדפדפן. החלטת פרטיות להעלות מול הלקוח; החלופה היא טוקן אטום לכל רשומה, שנפתר בצד שרת ומתורגם לטלפון לפני הקריאה. בטופס נייטיבי בדף של אתר ה‑CRM אין חובת טלפון: הקישור נושא רק את מזהה הרשומה, והדף מקשר אליה בשמירה בלי לקרוא אותה (נבדק 10.2026). - אינטראקציה דו‑שלבית מייצרת שתי שורות קליטה לתגובה אחת, דירוג עכשיו והערה כעבור רגע. זו התנהגות נכונה: טבלת הקליטה היא היומן הגולמי, ואובייקט העסק מחזיק את התשובה הסופית.
- טריגר שמגיב לקריאה הראשונה ירוץ לפני שהנתונים של השנייה קיימים. אל תרכיבו גוף הודעה, משימה או התראה משדה שמגיע בקריאה המאוחרת; הפנו את הקורא לרשומה.
CAPTCHA — הפרדת האחריות
Section titled “CAPTCHA — הפרדת האחריות”נקודות הקצה אינן מאמתות reCAPTCHA, Turnstile, hCaptcha או מלכודות דבש; הן לא רואות את הטוקן.
| השכבה | האחריות שלה |
|---|---|
| הדפדפן | מציג את ה‑widget, מקבל טוקן |
| השרת שלכם | מאמת את הטוקן מול ספק ה‑CAPTCHA — עם ה‑secret שלו — ורק אם עבר, מעביר הלאה |
getlead / web2table |
מקבלת גוף JSON נקי. היא לא יודעת שהיה CAPTCHA |
// Cloudflare Worker / Pages Function — מאמת Turnstile ואז מעביר ל-getleadexport async function onRequestPost({ request, env }) { const body = await request.json();
const verify = await fetch('https://challenges.cloudflare.com/turnstile/v0/siteverify', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ secret: env.TURNSTILE_SECRET, response: body.token }), }).then((r) => r.json());
if (!verify.success) return new Response('captcha failed', { status: 400 });
delete body.token; // הטוקן לא נשלח הלאה — הוא לא שדה בסכימה return fetch(`https://api.mbapps.co.il/functions/${env.APP_ID}/getlead`, { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-Parse-Application-Id': env.APP_ID }, body: JSON.stringify(body), });}מלכודת דבש היא החלופה הזולה: שדה מוסתר שאדם לא ימלא ובוט פשוט כן. לא מחליפה CAPTCHA מול תוקף ממוקד, אבל חינמית, בלי חיכוך ובלי סודות. דוגמה מלאה.
מה כן ומה לא נחשב סוד
Section titled “מה כן ומה לא נחשב סוד”| הערך | איפה מותר | למה |
|---|---|---|
| Application Id | גם בדפדפן, גם ב‑repository ציבורי | מזהה אפליקציה, לא אישור גישה. יצירה אנונימית בלי טוקן reCAPTCHA של הפלטפורמה נדחית ב‑code 119; עדכון ומחיקה — לפי ה‑CLP (סגורים כברירת מחדל). קריאה תלויה ב‑CLP של הטבלה: כש‑find סגור מתקבל code 119, וכשהוא פתוח ("*": true) הקריאה מחזירה נתונים. בדקו את ה‑CLP אצלכם |
| API Key | צד שרת בלבד | עוקף הרשאות בקריאה ובכתיבה. מספיק גם לקריאת סכימות — GET /parse/schemas/Accounts עם API Key מחזיר 200 (ראו סכימות) |
| Master Key | צד שרת בלבד, ורצוי מנהל סודות | גישה מלאה לכל טבלה, כולל Config והטבלאות החסומות: קריאה וכתיבה ל‑Config, שינוי CLP, קריאת סכימות |
| CAPTCHA secret | צד שרת בלבד | חשיפתו מבטלת את ההגנה |
רשימת בדיקה אבטחתית
Section titled “רשימת בדיקה אבטחתית”- אין Master Key ואין API Key בקוד שרץ בדפדפן או ב‑repository
- במסלול פונקציות הטפסים: ה‑CLP של טבלת היעד נשאר סגור
- במסלול דף ה‑CAPTCHA: ל‑
*ניתןcreateבלבד, ורק על טבלת קליטה ייעודית -
ValidatePhoneOrEmail: trueבתוך ה‑Valueשל שורת הדגל ב‑Config - אימות CAPTCHA נעשה בשרת שלכם, לפני ההעברה
- “עדכון מקישור ציבורי” מיושם כטבלת קליטה + טריגר
- טלפון שנוסע ב‑URL תועד ואושר מול הלקוח, או הוחלף בטוקן
- תועד שכל קריאה מוסיפה שורה, ושאין מסלול עדכון אנונימי
- הלקוח יודע שהנקודה ניתנת להפעלה גם ב‑
GET, ושהגבלת קצב באחריותו
- דגלי Config — השער האמיתי של נקודות הקצה
- אבחון תקלות —
code 119,code 111ושאר התסמינים - web2table — הפרטים המלאים של נקודת הקצה
- שגיאות ופתרון תקלות — קוד 119 בהקשר של כל השכבות