המלצות אבטחה על חוזים חכמים של Ethereum

בלוג 1חדשות מפתחיםיזם הסבר על בלוקצ’יין אירועים וכנסים לחץעלונים

Contents

הירשם לניוזלטר שלנו.

כתובת דוא”ל

אנו מכבדים את פרטיותך

HomeBlog פיתוח בלוקצ’יין

המלצות אבטחה על חוזים חכמים של Ethereum

מאופן הטיפול בשיחות חיצוניות לתוכניות התחייבות, להלן 10+ דפוסי אבטחה חכמים להתקשרות כאשר אתה בונה על Ethereum. מאת ConsenSys 10 ביולי 2020 הוצג ב -10 ביולי 2020

המלצות אבטחה על חוזים חכמים של Ethereum

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

  • היכונו לכישלון
  • השג בזהירות
  • שמור על חוזים פשוטים
  • הישאר מעודכן
  • היו מודעים לתחומי האישיות של ה- EVM

בפוסט זה, נצלול אל תוך האידיוטים של EVM ונעבור על רשימת דפוסים שעליכם לעקוב אחרי פיתוח מערכת חוזים חכמה כלשהי באת’ריום. יצירה זו מיועדת בעיקר למפתחי אתריום בינוניים. אם אתה עדיין בשלבי חקר מוקדמים, עיין בתוכנית מפתחי הבלוקצ’יין לפי דרישה של האקדמיה של ConsenSys. 

אוקיי, בואו נצלול פנימה.

שיחות חיצוניות

נזהר בעת ביצוע שיחות חיצוניות

קריאות לחוזים חכמים שאינם מהימנים עלולות לגרום לכמה סיכונים או טעויות בלתי צפויים. שיחות חיצוניות עשויות לבצע קוד זדוני בחוזה זה או בכל חוזה אחר שהוא תלוי בו. לכן, התייחס לכל שיחה חיצונית כאל סיכון ביטחוני פוטנציאלי. כאשר לא ניתן, או לא רצוי להסיר שיחות חיצוניות, השתמש בהמלצות בשאר חלק זה כדי למזער את הסכנה.

סמן חוזים לא מהימנים

בעת אינטראקציה עם חוזים חיצוניים, ציין את המשתנים, השיטות וממשקי החוזה שלך באופן שמבהיר כי האינטראקציה איתם עלולה להיות לא בטוחה. זה חל על פונקציות משלך המכנות חוזים חיצוניים.

// רע Bank.withdraw (100); // לא ברור אם פונקציה מהימנה או לא מהימנה makeWithdrawal (סכום קטן) {// לא ברור שהפונקציה הזו עשויה להיות לא בטוחה Bank.withdraw (סכום); } // UntrustedBank.withdraw טוב (100); // שיחה חיצונית לא מהימנה TrustedBank.withdraw (100); // חוזה בנק חיצוני אך מהימן המתוחזק על ידי פונקציית XYZ Corp makeUntrustedWithdrawal (סכום קטן) {UntrustedBank.withdraw (סכום); } שפת קוד: PHP (php)

הימנע משינויים במצב לאחר שיחות חיצוניות

בין אם משתמשים בשיחות גולמיות (בטופס someAddress.call ()) או בשיחות חוזה (בטופס ExternalContract.someMethod ()), נניח שקוד זדוני עלול להתבצע. גם אם ExternalContract אינו זדוני, קוד זדוני יכול להתבצע על ידי כל החוזים שהוא מכנה.

סכנה מסוימת אחת היא קוד זדוני עלול לחטוף את זרימת השליטה, ולהוביל לפגיעות בגלל כניסה חוזרת. (לִרְאוֹת כניסה חוזרת לדיון מלא יותר בבעיה זו).

אם אתה מתקשר לחוזה חיצוני לא מהימן, הימנע משינויים במצב לאחר השיחה. דפוס זה נקרא לפעמים גם דפוס בדיקות-אפקטים-אינטראקציות.

לִרְאוֹת SWC-107

אל תשתמש בהעברה () או בשליחה ().

.העבר () ו.שלח () העבר 2,300 גז בדיוק למקבל. מטרת מלגת הגז המקודדת הזו הייתה למנוע פגיעות של כניסה חוזרת, אבל זה רק הגיוני בהנחה שעלויות הדלק קבועות. EIP 1884, שהיה חלק מהמזלג הקשיח באיסטנבול, העלה את עלות הדלק של פעולת ה- SLOAD. זה גרם לתפקוד החזרת חוזה לעלות יותר מ- 2300 גז. אנו ממליצים להפסיק את השימוש ב-.transfer () ו-.send () ובמקום זאת להשתמש ב- call ().

// חוזה גרוע פגיע {פונקציית משיכה (כמות uint256) חיצונית {// פעולה זו מעבירה 2300 גז, מה שעשוי שלא להספיק אם הנמען // הוא חוזה ומשתנות עלויות הדלק. msg.sender.transfer (סכום); }} // חוזה טוב קבוע {פונקציה למשוך (סכום uint256) חיצוני {// זה מעביר את כל הגז הזמין. הקפידו לבדוק את ערך ההחזר! (bool הצלחה,) = msg.sender.call.value (סכום) (""); דורשים (הצלחה, "ההעברה נכשלה."); }} שפת קוד: JavaScript (javascript)

שים לב ש- call () אינו עושה דבר בכדי להקל על התקפות חוזרות, ולכן יש לנקוט באמצעי זהירות אחרים. כדי למנוע התקפות חוזרות, השתמש ב- דפוס בדיקות-אפקטים-אינטראקציות.

לטפל בשגיאות בשיחות חיצוניות

Solidity מציעה שיטות שיחה ברמה נמוכה שעובדות על כתובות גולמיות: address.call (), address.callcode (), address.delegatecall () ו- address.send (). שיטות ברמה נמוכה אלה לעולם אינן זורקות חריג, אלא יחזירו שקר אם השיחה נתקלת בחריג. מצד שני, קריאות חוזה (למשל, ExternalContract.doSomething ()) יפיץ באופן אוטומטי זריקה (למשל, ExternalContract.doSomething () תזרוק גם אם doSomething () זורק).

אם תבחר להשתמש בשיטות השיחה ברמה נמוכה, ודא לטפל באפשרות שהשיחה תיכשל, על ידי בדיקת ערך ההחזרה.

// רע someAddress.send (55); someAddress.call.value (55) (""); // זה מסוכן כפליים, מכיוון שהוא יעביר את כל הגז שנותר ולא יבדוק את התוצאה someAddress.call.value (100) (bytes4 (sha3 ("לְהַפְקִיד()"))); // אם ההפקדה משליכה חריג, השיחה הגולמית () תחזיר רק שקר והעסקה לא תוחזר // טוב (הצלחה של bool,) = someAddress.call.value (55) (""); אם (! הצלחה) {// מטפל בקוד כשל} ExternalContract (someAddress) .deposit.value (100) (); שפת קוד: JavaScript (javascript)

לִרְאוֹת SWC-104

דחיפת העדפה לטובת שיחות חיצוניות

שיחות חיצוניות עלולות להיכשל בטעות או במכוון. כדי למזער את הנזק שנגרם כתוצאה מכשלים כאלה, לעתים קרובות עדיף לבודד כל שיחה חיצונית לעסקה משלה שניתן ליזום על ידי מקבל השיחה. זה רלוונטי במיוחד לתשלומים, שם עדיף לתת למשתמשים למשוך כספים במקום לדחוף אליהם כספים באופן אוטומטי. (זה גם מקטין את הסיכוי ל בעיות במגבלת הגז.) הימנע משילוב העברות אתר מרובות בעסקה אחת.

// מכירה פומבית של חוזים גרועים {כתובת bestBidder; אתה לא הגבוה ביותר הצעת פונקציה () לתשלום {דרישה (msg.value >= הצעת המחיר הגבוהה ביותר); if (bestbidder! = כתובת (0)) {(bool הצלחה,) = bestbidder.call.value (hoogste הצעה) (""); דורשים (הצלחה); // אם שיחה זו נכשלת באופן עקבי, אף אחד אחר לא יכול להציע} bestBidder = msg.sender; maximumBid = msg.value; }} // מכירה פומבית של חוזים טובים {כתובת bestBidder; אתה לא הגבוה ביותר מיפוי (כתובת => uint) החזרים; הצעת מחיר () לפונקציה חיצונית לתשלום {דרישה (msg.value >= הצעת המחיר הגבוהה ביותר); אם (הגבוה ביותרמציע! = כתובת (0)) {מחזיר [המציע הגבוה ביותר] + = המכרז הגבוה ביותר; // רשמו את ההחזר שמשתמש זה יכול לתבוע עליו} הגבוההמציע = msg.sender; maximumBid = msg.value; } פונקציה pullRefund () חיצוני {uint refund = refunds [msg.sender]; החזרים [msg.sender] = 0; (bool הצלחה,) = msg.sender.call.value (החזר) (""); דורשים (הצלחה); }} שפת קוד: JavaScript (javascript)

לִרְאוֹת SWC-128

אל תאציל להתקשר לקוד לא מהימן

פונקציית ה- delegatecall קוראת לפונקציות מחוזים אחרים כאילו הם שייכים לחוזה המתקשר. לפיכך ה- callee עשוי לשנות את מצב הכתובת הקוראת. זה עשוי להיות לא בטוח. דוגמה שלהלן מראה כיצד שימוש בשיחת delegat יכול להוביל להרס החוזה ולאובדן יתרתו.

חוזה Destructor {פונקציה doWork () חיצוני {selfdestruct (0); }} עובד חוזה {פונקציה doWork (כתובת _internalWorker) ציבורי {// לא בטוח _internalWorker.delegatecall (bytes4 (keccak256 ("תעבוד()"))); }} שפת קוד: JavaScript (javascript)

אם נקרא Worker.doWork () עם הכתובת של חוזה ה- Destructor הפרוס כטיעון, חוזה העובד יהרוס את עצמו. האציל ביצוע רק לחוזים מהימנים, ו לעולם לא לכתובת שסופקה על ידי המשתמש.

אַזהָרָה

אל תניח שהחוזים נוצרים עם יתרה אפסית. תוקף יכול לשלוח אתר לכתובת החוזה לפני שהוא נוצר. אסור לחוזים להניח שמצבו ההתחלתי מכיל איזון אפס. לִרְאוֹת גיליון 61 לפרטים נוספים.

לִרְאוֹת SWC-112

זכרו כי ניתן לשלוח אתר בכוח לחשבון

היזהר מקידוד של משתנה הבודק בקפדנות את יתרת החוזה.

תוקף יכול לשלוח אתר בכוח לכל חשבון. לא ניתן למנוע זאת (אפילו לא עם פונקציית נפילה שעושה ביטול ()).

התוקף יכול לעשות זאת על ידי יצירת חוזה, מממן אותו באמצעות 1 wei, ומפעילה הרס עצמי (victimAddress). שום קוד אינו מופעל ב- victimAddress, כך שלא ניתן למנוע אותו. זה נכון גם לגבי תגמול חסימות שנשלח לכתובת הכורה, שיכולה להיות כל כתובת שרירותית.

כמו כן, מכיוון שניתן לחשב מראש את כתובות החוזה, ניתן לשלוח את האתר לכתובת לפני פריסת החוזה.

לִרְאוֹת SWC-132

זכור כי נתונים ברשת הם פומביים

בקשות רבות דורשות נתונים שהוגשו להיות פרטיים עד לנקודת זמן מסוימת על מנת לעבוד. משחקים (למשל, מספריים על נייר רוק ברשת) ומנגנוני מכירה פומבית (למשל הצעה אטומה מכירות פומביות של ויקרי) הן שתי קטגוריות עיקריות של דוגמאות. אם אתה בונה יישום שבו פרטיות היא בעיה, הקפד להימנע מלדרוש ממשתמשים לפרסם מידע מוקדם מדי. האסטרטגיה הטובה ביותר היא להשתמש תוכניות התחייבות עם שלבים נפרדים: התחל תחילה באמצעות חשיש הערכים ובשלב מאוחר יותר גילוי הערכים.

דוגמאות:

  • במספריים של נייר רוק, דרוש משני השחקנים להגיש חשיש למהלך המיועד שלהם, ואז לדרוש משני השחקנים להגיש את המהלך שלהם; אם המהלך שהוגש אינו תואם את החשיש זרוק אותו החוצה.
  • במכירה פומבית, דרוש מהשחקנים להגיש חשיש משווי הצעת המחיר שלהם בשלב ראשוני (יחד עם הפקדה הגדולה מערך הצעת המחיר שלהם), ואז להגיש את שווי הצעת המחיר שלהם במכירה פומבית בשלב השני..
  • כאשר מפתחים אפליקציה שתלויה במחולל מספרים אקראיים, על ההזמנה להיות (1) שחקנים מגישים מהלכים, (2) מספר אקראי שנוצר, (3) שחקנים שילמו. אנשים רבים חוקרים באופן פעיל מחוללי מספרים אקראיים; הפתרונות הנוכחיים הטובים ביותר כוללים כותרות חסימות ביטקוין (מאומתות באמצעות http://btcrelay.org), תוכניות hash-commit-reveal (כלומר, צד אחד מייצר מספר, מפרסם את ה- hash שלו כדי “להתחייב” לערך ואז חושף את הערך מאוחר יותר) RANDAO. מכיוון שאת’ריום הוא פרוטוקול דטרמיניסטי, אינך יכול להשתמש בשום משתנה בתוך הפרוטוקול כמספר אקראי בלתי צפוי. כמו כן, שים לב שכורים הם בשליטה מסוימת בערך block.blockhash ()*.

היזהר מהאפשרות שחלק מהמשתתפים עשויים “לרדת במצב לא מקוון” ולא לחזור

אל תהפוך תהליכי החזר או תביעה לתלויים בכך שצד מסוים יבצע פעולה מסוימת ללא דרך אחרת להוציא את הכספים. לדוגמא, במשחק מספריים בנייר רוק, טעות נפוצה אחת היא לא לבצע תשלום עד ששני השחקנים יגישו את המהלכים שלהם; עם זאת, שחקן זדוני יכול “להתאבל” על האחר פשוט על ידי כך שהוא לעולם לא מגיש את המהלך שלו – למעשה, אם שחקן רואה את המהלך שנחשף של השחקן האחר וקובע שהוא הפסיד, אין להם סיבה להגיש את המהלך שלו בכלל. נושא זה עשוי להתעורר גם בהקשר להסדר ערוצי המדינה. כאשר מצבים כאלה הם נושא, (1) מספק דרך לעקוף משתתפים שאינם משתתפים, אולי במגבלת זמן, (2) לשקול להוסיף תמריץ כלכלי נוסף למשתתפים למסור מידע בכל המצבים בהם הם נמצאים. אמור לעשות זאת.

היזהר משלילת המספר השלם החתום השלילי ביותר

מוצקות מספקת מספר סוגים לעבודה עם מספרים שלמים חתומים. כמו ברוב שפות התכנות, ב”סולידיטי “מספר שלם חתום עם ביטים N יכול לייצג ערכים מ -2 ^ (N-1) עד 2 ^ (N-1) -1. פירוש הדבר שאין מקבילה חיובית ל- MIN_INT. השלילה מיושמת כמציאת השלמת המספר של השניים, כך שלילת המספר השלילי ביותר יביא למספר זהה. זה נכון לגבי כל סוגי המספרים השלמים החתומים ב- Solidity (int8, int16,…, int256).

שלילת חוזה {פונקציה negate8 (int8 _i) תשואות ציבוריות טהורות (int8) {return -_i; } פונקציה negate16 (int16 _i) מחזירה טהורה ציבורית (int16) {return -_i; } int8 public a = negate8 (-128); // -128 int16 ציבור b = negate16 (-128); // 128 int16 ציבור c = negate16 (-32768); // -32768} שפת קוד: PHP (php)

אחת הדרכים להתמודד עם זה היא לבדוק את הערך של המשתנה לפני השלילה ולזרוק אם הוא שווה ל- MIN_INT. אפשרות נוספת היא לוודא שהמספר השלילי ביותר לעולם לא יושג על ידי שימוש בסוג בעל קיבולת גבוהה יותר (למשל int32 במקום int16).

בעיה דומה עם סוגי int מתרחשת כאשר MIN_INT מוכפל או מחולק ב- -1.

האם קוד הבלוקצ’יין שלך מאובטח? 

אנו מקווים שהמלצות אלה הועילו. אם אתה והצוות שלך מתכוננים להשקה או אפילו בתחילת מחזור החיים של הפיתוח וזקוקים לחוזים חכמים שלך לבדיקת שפיות, אנא אל תהסס לפנות לצוות מהנדסי האבטחה שלנו ב- ConsenSys Diligence. אנו כאן כדי לעזור לך להפעיל ולתחזק את יישומי ה- Ethereum שלך בביטחון של 100%. 

הזמינו בדיקת ספוט אבטחה

הזמן סקירה של יום אחד עם צוות המומחים שלנו לאבטחת בלוקצ’יין. הזמן את עצמך היום אבטחה חוזים חכמים ניוזלטר הירשם לניוזלטר שלנו לקבלת החדשות האחרונות של Ethereum, פתרונות ארגוניים, משאבי מפתח ועוד. כתובת דוא”ל תוכן בלעדיכיצד לבנות מוצר מצליח של בלוקצ'ייןוובינר

כיצד לבנות מוצר מצליח של בלוקצ’יין

כיצד להגדיר ולהפעיל צומת אתריוםוובינר

כיצד להגדיר ולהפעיל צומת אתריום

כיצד לבנות ממשק API משלך של Ethereumוובינר

כיצד לבנות ממשק API משלך של Ethereum

כיצד ליצור אסימון חברתיוובינר

כיצד ליצור אסימון חברתי

שימוש בכלי אבטחה בפיתוח חוזים חכםוובינר

שימוש בכלי אבטחה בפיתוח חוזים חכם

העתיד של נכסים דיגיטליים של פיננסים ו- DeFiוובינר

עתיד האוצר: נכסים דיגיטליים ו- DeFi

Mike Owergreen Administrator
Sorry! The Author has not filled his profile.
follow me
Like this post? Please share to your friends:
Adblock
detector
map