דלגו לתוכן

או התחילו מנקודה בטוחה: אינדקס הכלים המלא · מפת הטבלאות המרכזיות

מערכת חדשה — 14 יום חינם

מודל האבטחה של כתיבה אנונימית

עודכן 10.10.2026

שלוש עובדות קובעות את הארכיטקטורה של כל פיצ’ר שבו גולש לא מזוהה כותב ל‑CRM. קראו לפני שמישהו “מתקן” הרשאות כדי שטופס יעבוד.

1 · ב‑REST כתיבה אנונימית נעצרת בשער ה‑CAPTCHA

Section titled “1 · ב‑REST כתיבה אנונימית נעצרת בשער ה‑CAPTCHA”
Bash
# ✘ כתיבה אנונימית ישירה — נדחית
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":"ישראל ישראלי"}'
JavaScript
// ✘ כתיבה אנונימית ישירה — נדחית
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: 'ישראל ישראלי' }),
});
Python
# ✘ כתיבה אנונימית ישירה — נדחית
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
<?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);
JSON
{ "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. קבעו את הערך בקוד או בשרת הביניים — לעולם לא מקלט של הגולש.

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──▶ אובייקט העסק
(אנונימי) (יומן גולמי, (טבלה סגורה
נפתחת לקליטה) לחלוטין)
  1. הדף הציבורי יוצר שורה בטבלת ביניים שנועדה לקליטה בלבד — דרך web2table, או בטופס נייטיבי בדף של אתר ה‑CRM.
  2. טריגר data change על טבלת הקליטה משליך את הערכים על אובייקט העסק, פעולת update-object עם connection: "source.<שדה Pointer>".
  3. טבלת העסק נשארת סגורה לכתיבה אנונימית.

שלוש השלכות שכדאי לתעד מראש

Section titled “שלוש השלכות שכדאי לתעד מראש”
  • הקישור חייב לשאת phone, שדה חובה ב‑web2table. טלפון של לקוח נוסע ב‑URL ונוחת בלוגים של שרתים, ב‑Referer ובהיסטוריית הדפדפן. החלטת פרטיות להעלות מול הלקוח; החלופה היא טוקן אטום לכל רשומה, שנפתר בצד שרת ומתורגם לטלפון לפני הקריאה. בטופס נייטיבי בדף של אתר ה‑CRM אין חובת טלפון: הקישור נושא רק את מזהה הרשומה, והדף מקשר אליה בשמירה בלי לקרוא אותה (נבדק 10.2026).
  • אינטראקציה דו‑שלבית מייצרת שתי שורות קליטה לתגובה אחת, דירוג עכשיו והערה כעבור רגע. זו התנהגות נכונה: טבלת הקליטה היא היומן הגולמי, ואובייקט העסק מחזיק את התשובה הסופית.
  • טריגר שמגיב לקריאה הראשונה ירוץ לפני שהנתונים של השנייה קיימים. אל תרכיבו גוף הודעה, משימה או התראה משדה שמגיע בקריאה המאוחרת; הפנו את הקורא לרשומה.

נקודות הקצה אינן מאמתות reCAPTCHA, Turnstile, hCaptcha או מלכודות דבש; הן לא רואות את הטוקן.

השכבה האחריות שלה
הדפדפן מציג את ה‑widget, מקבל טוקן
השרת שלכם מאמת את הטוקן מול ספק ה‑CAPTCHA — עם ה‑secret שלו — ורק אם עבר, מעביר הלאה
getlead / web2table מקבלת גוף JSON נקי. היא לא יודעת שהיה CAPTCHA
JavaScript
// Cloudflare Worker / Pages Function — מאמת Turnstile ואז מעביר ל-getlead
export 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 מול תוקף ממוקד, אבל חינמית, בלי חיכוך ובלי סודות. דוגמה מלאה.

הערך איפה מותר למה
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 צד שרת בלבד חשיפתו מבטלת את ההגנה
  • אין Master Key ואין API Key בקוד שרץ בדפדפן או ב‑repository
  • במסלול פונקציות הטפסים: ה‑CLP של טבלת היעד נשאר סגור
  • במסלול דף ה‑CAPTCHA: ל‑* ניתן create בלבד, ורק על טבלת קליטה ייעודית
  • ValidatePhoneOrEmail: true בתוך ה‑Value של שורת הדגל ב‑Config
  • אימות CAPTCHA נעשה בשרת שלכם, לפני ההעברה
  • “עדכון מקישור ציבורי” מיושם כטבלת קליטה + טריגר
  • טלפון שנוסע ב‑URL תועד ואושר מול הלקוח, או הוחלף בטוקן
  • תועד שכל קריאה מוסיפה שורה, ושאין מסלול עדכון אנונימי
  • הלקוח יודע שהנקודה ניתנת להפעלה גם ב‑GET, ושהגבלת קצב באחריותו