פוסט שיתוף תוכן | יישום רשימה שחורה בשרתי node.js
-
לא מזמן נתקלתי בתכונה חמודה שנוספה לאובייקט net - המודול המובנה בnode.js לטיפול בתעבורת רשת.
האובייקט שנוסף נקרא BlockList, והוא מאפשר לשמור ולעדכן (באופן חד-כיווני) רשימה "שחורה" של מספרי IP או טווח של מספרים כאלו, בצמוד לאובייקט net.
ומה קורה כשמתקבלת בקשה בשרת ממספר שנמצא ברשימה הרשחורה? - טוב ששאלתם: כלום.. כלומר, קורה בדיוק מה שקורה כשמספר אחר שולח בקשה דומה.
לפי הנוסח המופיע באתר התיעוד, בתרגום חופשי, אפשר לנסח זאת כך: "האובייקט יכול לבוא לשימוש עם מערכות API כלשהן, כדי לבטל את האפשרות של חיבורים נכנסים או יוצאים עבור מספרי IP ספציפיים או טווח של מספרים".
אז איך זה יכול לעזור לנו לממש את החלומות על מערכת מפולטרת ומאובטחת שתמיד חלמנו לפתח?
אז זהו שלא ממש עוזר, אבל נחמד זה כן.קוד בסיסי לדוגמה עבור המודול HTTP:
const http = require('http'); const net = require('net'); let server = http.createServer((req, res) => { //console.log(`source ip: ${req.socket.remoteAddress} ,BlockList rules: ${res.socket.server.BlockList.rules} ,ip match rules: ${res.socket.server.BlockList.check(req.socket.remoteAddress)}`); if (server.BlockList.check(req.socket.remoteAddress)) { res.statusCode = 403; return res.end(); } res.end('hello FILTERED world!') }); const BlockList = new net.BlockList(); BlockList.addAddress('127.0.0.1', 'ipv4'); server.BlockList = BlockList; server.listen(8080, '0.0.0.0');
ובשימוש בexpress ניתן להוסיף middleware:
app.use((req, res, next) => { if (req.socket.server.BlockList.check(req.socket.remoteAddress)) { return res.status(403).end(); next(); });
כמה נקודות:
- עבור השימוש בתכונה יש צורך לעדכן את Node לגירסה 15.x באמצעות כלי האקרובטיקה האהוב עליכם.
- כדי שזה יעבוד, יש צורך להוסיף לפונקציה listen() מספר של host שמאזין לבקשות הנשלחות. אם לא תעשו את זה, אלא תשאירו את הפרמטר ריק, מה שיקרה הוא שמספרי IPV4 לא יתאימו לכללים שהוספתם, בגלל מנגנון שנקרא dual-stack support, שהופך מספרי IPV4 למשולבי IPV6 (ייתכן שזה באג, אבל זה המצב כעת).
- אם אתם משתמשים בnginx ודרכו הגישה לNode, בדרך כלל הגישה לIP של שולח הבקשה הוא דרך הheader x-forwarded-for.
- כפי שציינתי לפני כן, אין אפשרות להוציא מספר שנחסם מהרשימה. אבל סביר להניח שאפשר לפתור את זה איכשהו.. או אפילו לכתוב modoule חדש שיעשה בדיוק את זה, ולתרום אותו לאנושות.
- את החסימה בפועל תצטרכו לממש בעצמכם.
- בדוגמה שצורפה החסימה היא באמצעות הודעת שגיאה 403. אפשר גם להוסיף קאפצ'ה, ומנגנוני זיהוי לבוטים, ושמירה של המידע בDB לשימוש עתידי, ועוד ועוד כיד הדמיון..
לחסום את אלו שברשימה השחורה באופן "מקצועי", כלומר לחסום את האפשרות ליצור socket עם השרת (בשונה מהקמת סוקט ושליחת תוכן בתוך הסוקט, כשהתוכן כולל הודעת חסימה), באמצעות REJECT או DROP (מונחים שמתייחסים לתעבורת הTCP: שליחת הודעת ניתוק בעת ניסיון ליצור סוקט, או חוסר תגובה לניסיון כזה, בהתאמה) לא ניתן באמצעות הprocess של Node עצמו (וגם לא באמצעות python לדוגמה) בלי התממשקות עם מערכת ההפעלה באופן כלשהו (בlinux התממשקות עם netfilter, ובwin עם winsock), מכיון שמערכת ההפעלה היא זו שמקימה את החיבור, ומעבירה את השליטה בsocket שהוקם לnode לאחר שהחיבור כבר הוקם.
ניתן לקרוא בנושא למשל כאן.אמנם עדיין נוכל לטרוק להם את הדלת בצורה לא נעימה בכלל, עם הקוד הזה:
req.socket.destroy()
למהדרין ניתן בקלות להוסיף קוד שיריץ פקודה בiptables (או netsh עבור WIN) שתבצע את החסימה ולא תאפשר ל"שחורים" לפתוח סוקט עם השרת, אבל שני פרטים כדאי לזכור:
- לא קיימת דרך (יותר נכון לא מוכרת לי כזו) שבה תקבלו מידע מהמערכת על IP שחור שמנסה לבצע גישה.
- הרשימה תישאר חסומה כל עוד לא תמחקו אותה (למהדרין מן המהדרין אולי אפשר לבצע אינטגרציה אוטמטית עם fail2ban כדי להוציא אותם אוטומטית משם, אבל סביר להניח שעדיף כבר להתממשק עם netfilter).
השאלות שנשארו פתוחות:
- האם זה לא משהו שיכולתם לממש בעצמכם?
- איזה שירותים לדוגמה מאפשרים את השימוש בתכונה הזו?
אשמח למידע בתגובות.
-
תודה על השיתוף!
@5566brs אמר בפוסט שיתוף תוכן | יישום רשימה שחורה בשרתי node.js:
האם זה לא משהו שיכולתם לממש בעצמכם?
מה בעצם קוד זה מחדש לנו? להבנתי הקוד מביא לנו מבנה נתונים ששומרת רשימה של טווחי IP עם API בסיסי להוספת כתובות או טווחי כתובות ודרך לתשאל את הרשימה.
במחשבה ראשונה אני יכול לממש את זה בעצמי די בקלות. במחשבה שנייה, ואחרי שראיתי את קובץ הטסטים המקיף להחריד, החלטתי שאני בודאי מעדיף קוד שמישהו אחר כתב ובדק.
מהשאלות הראשונות שלי היו:
א) עם כל הכבוד לצורך, למה נוד החליטו לספק לנו את זה?
ב) מה שיותר הפריע לי הוא השם: blockList - רשימת חסימה. מבנה המידע הרי הוא מבנה ג'נרי לשמירת טווחי IP, אז מה הקשר לחסימה?
ג) עוד תמיה, למה אין אפשרות למחוק רשומות מהמבנה?התשובה לכל זה מרומז בתיעוד:
The BlockList object can be used with some network APIs
התרגום החפשי שלך למעלה לא מדוייק לגמרי. מרומז פה שהמבנה אמור למצוא שימוש בפונקציות API שנוד הולכים לספק.
יותר אריכות יש ב-PR שמממש את המבנה:
While the BlockList can be used on it's own, the intent is for the BlockList object to be passed into existing net APIs. For listen(), the BlockList will be checked as close to the libuv code that accepts the incoming connection as possible. For connect(), it would check as early as possible. These uses have not yet be implemented, however. Those would come in separate PRs.
ועיין שם עוד שמפורט איפה בדיוק מתכננים להשתמש בזה. עד כמה שאני רואה, כרגע זה לא בשימוש בשום מקום.
-
@5566brs אמר בפוסט שיתוף תוכן | יישום רשימה שחורה בשרתי node.js:
יש צורך לעדכן את Node לגירסה 15.x
מסיבה שלא ברורה לי יש עבודה פעילה להבאת המחלקה לגירסאות 14.X. נראה שזה אמור להשתחרר בימים הקרובים.
https://github.com/nodejs/node/pull/34625#issuecomment-894753506
אני לא מבין מה הצורך מכיון שזה לא בשימוש בשום מקום. אולי יש להם איזשהו מדיניות של הקטנת ההבדלים בין הגירסאות?בכל מקרה אחרי קריאה חוזרת של השיחה מסביב לנושא נראה שהרווח העיקרי של הוספת המחלקה לנוד הוא האפשרות לקטוע את החיבור בשלב הכי מוקדם שאפשר, דהיינו תוך מנוע נוד. מכיון שאין כיום אפשרות כזו לכן נראה שהתועלת העיקרי עוד לא קיים.