Go ضد القراصنة: الحماية من حقن SQL و XSS عملياً

مدرب بايثون أونلاين للمبتدئين

تعلم Python بسهولة دون إرهاق نظري. حل مهام عملية مع التحقق التلقائي واكتب الكود مباشرة في المتصفح.

ابدأ الدورة

لماذا يقع حتى مطوري Go في فخ القراصنة؟

\n\n

تشتهر Go بسرعتها وبساطتها وأدوات الأمان المدمجة فيها. لكن تهدئة النفس بعبارة «أنا أكتب بلغة Go، إذن أنا بأمان» هي وهم خطير. حقن SQL وهجمات XSS ليست من بقايا الماضي. فهي لا تزال تسقط المواقع وتسرق قواعد البيانات يومياً، وGo ليست استثناءً.

\n\n

المشكلة هي أن Go تمنح المطور أدوات قوية، لكنها لا تستخدمها نيابة عنك. يمكنك عن طريق الخطأ لصق استعلام SQL باستخدام fmt.Sprintf أو عرض تعليق مستخدم دون ترميز - وسيحصل المهاجم على وصول إلى قاعدة بياناتك أو يسرق ملفات تعريف الارتباط للزوار.

\n\n

في هذه المقالة، سنحلل أخطر نوعين من الهجمات - حقن SQL و البرمجة النصية عبر المواقع (XSS) - ونوضح كيفية منعهما باستخدام Go الأصلي والمكتبات الشائعة. ستحصل ليس على نظرية، بل على قوالب كود جاهزة يمكنك إدراجها في مشروعك اليوم.

\n\n

حقن SQL في Go: كيف تنشأ وكيف تقضي عليها من الجذور

\n\n

الخطأ النموذجي: ربط السلاسل النصية

\n\n

تخيل أن لديك نقطة نهاية لجلب مستخدم بواسطة المعرف. الطريقة الأكثر سذاجة (وخطورة) لكتابة الاستعلام تبدو هكذا:

\n\n
package main\n\nimport (\n    "database/sql"\n    "fmt"\n    "log"\n    _ "github.com/lib/pq"\n)\n\nfunc getUserByID(db *sql.DB, userID string) {\n    // خطير! ربط السلاسل النصية\n    query := fmt.Sprintf("SELECT id, name, email FROM users WHERE id = '%s'", userID)\n    rows, err := db.Query(query)\n    if err != nil {\n        log.Fatal(err)\n    }\n    defer rows.Close()\n    // ... معالجة\n}
\n\n

إذا قام المهاجم بتمرير السلسلة 1' OR '1'='1 في userID، سيتحول الاستعلام إلى:

\n\n
SELECT id, name, email FROM users WHERE id = '1' OR '1'='1'
\n\n

وفويلا - سيحصل على جميع مستخدمي قاعدة البيانات. وإذا أدخل 1'; DROP TABLE users; --، فستفقد الجدول.

\n\n

الحل: الاستعلامات المعلمة (العبارات المحضرة)

\n\n

مشغل Go لقواعد البيانات PostgreSQL و MySQL و SQLite يدعم العبارات المحضرة. إنها تفصل كود SQL عن البيانات، ويقوم المشغل تلقائياً بترميز الأحرف الخطرة.

\n\n
func getUserByIDSafe(db *sql.DB, userID string) {\n    // آمن: استعلام معلم\n    query := "SELECT id, name, email FROM users WHERE id = $1"\n    rows, err := db.Query(query, userID)\n    if err != nil {\n        log.Fatal(err)\n    }\n    defer rows.Close()\n    // ... معالجة\n}
\n\n

لاحظ $1 - هذا هو مكان الحجز للوسيطة الأولى. في MySQL يُستخدم الرمز ?. الآن حتى لو كان userID يحتوي على 1' OR '1'='1، سيتعامل معه المشغل كقيمة نصية، وليس كجزء من كود SQL.

\n\n

العمل مع حزمة sqlx

\n\n

مكتبة github.com/jmoiron/sqlx تجعل الكود أنظف. إنها تدعم المعلمات المسماة والمسح التلقائي إلى الهياكل:

\n\n
import "github.com/jmoiron/sqlx"\n\ntype User struct {\n    ID    int    `db:"id"`\n    Name  string `db:"name"`\n    Email string `db:"email"`\n}\n\nfunc getUserByIDSqlx(db *sqlx.DB, userID string) (*User, error) {\n    user := &User{}\n    // معلمة مسماة :id\n    err := db.Get(user, "SELECT * FROM users WHERE id = :id", sqlx.Named("id", userID))\n    if err != nil {\n        return nil, err\n    }\n    return user, nil\n}
\n\n

هام: حتى إذا كنت تستخدم ORM مثل GORM أو Ent، تأكد من تكوينها لاستخدام العبارات المحضرة. بعض الإصدارات القديمة من ORM كانت تسمح باستعلامات «خام».

\n\n

XSS في Go: عندما يطلق موقعك النار على قدمه

\n\n

كيف يحدث هجوم XSS

\n\n

تحدث XSS (البرمجة النصية عبر المواقع) عندما تقوم بإدراج محتوى مستخدم على الصفحة دون ترميز. شر

المدونات

توصيات الكتب