مقدمة: لماذا الأمان ليس خيارًا بل هو نظافة أساسية
\n\nتخيل: أنت تكتب خدمة ويب رائعة بلغة C#. كل شيء يعمل بشكل مثالي — المستخدمون يسجلون، يتركون تعليقات، يبحثون عن منتجات. ثم يأتي "هاكر فاسيا" (الذي في الحقيقة فقط نسخ سكريبت من الإنترنت) — ويسرب قاعدة البيانات بأكملها. أو الأسوأ من ذلك، يقوم بإدراج سكريبت في صفحتك يسرق ملفات تعريف الارتباط لجميع الزوار.
\n\nيبدو وكأنه سيناريو فيلم رعب؟ لكن هذا يحدث كل يوم. وفقًا لإحصائيات OWASP، فإن الحقن (SQL, XSS, LDAP) ضمن أهم 3 ثغرات خطيرة في تطبيقات الويب. و C#، بكل موثوقيتها، لا تمنحك درع حماية افتراضيًا.
\n\nفي هذه المقالة، سنحلل أكثر هجومين شيوعًا — SQL Injection و XSS (البرمجة النصية عبر المواقع). ستحصل ليس فقط على نظرية، بل على تقنيات دفاعية عملية بلغة C# مع أمثلة كود حقيقية. هيا بنا!
\n\nSQL Injection: عندما يصبح المستخدم هاكرًا
\n\nكيف يبدو ذلك عمليًا
\n\nلنفترض أن لديك نظام دخول بسيط. المستخدم يدخل اسم المستخدم وكلمة المرور، وأنت تقوم بتكوين الاستعلام هكذا:
\n\nstring login = txtLogin.Text;\nstring password = txtPassword.Text;\nstring query = "SELECT * FROM Users WHERE Login = '" + login + "' AND Password = '" + password + "'";\nSqlCommand cmd = new SqlCommand(query, connection);\n\nيبدو منطقيًا؟ خطأ! إذا أدخل المهاجم في حقل اسم المستخدم: ' OR 1=1 --، فإن الاستعلام يتحول إلى:
SELECT * FROM Users WHERE Login = '' OR 1=1 --' AND Password = '...'\n\nكل ما بعد -- هو تعليق. الشرط 1=1 صحيح دائمًا. الاستعلام سيعيد جميع المستخدمين، ويتم تجاوز المصادقة. وماذا لو تم إدراج DROP TABLE Users بدلاً من التعليق؟ وداعًا لقاعدة البيانات.
الحماية رقم 1: الاستعلامات المعلمة (درعك الرئيسي)
\n\nأفضل حماية من SQL Injection هي عدم دمج السلاسل النصية يدويًا أبدًا. استخدم المعلمات. خادم SQL نفسه يقوم بتعقيم الأحرف الخطرة، وتتلقى قاعدة البيانات البيانات كقيم وليس ككود.
\n\nstring login = txtLogin.Text;\nstring password = txtPassword.Text;\n\nstring query = "SELECT * FROM Users WHERE Login = @Login AND Password = @Password";\n\nusing (SqlConnection conn = new SqlConnection(connectionString))\n{\n SqlCommand cmd = new SqlCommand(query, conn);\n cmd.Parameters.AddWithValue("@Login", login);\n cmd.Parameters.AddWithValue("@Password", password);\n \n conn.Open();\n SqlDataReader reader = cmd.ExecuteReader();\n // معالجة النتيجة\n}\n\nلاحظ: @Login و @Password هما معلمات. حتى لو أدخل المستخدم '; DROP TABLE Users; --، سيتعامل معها نظام إدارة قواعد البيانات كسلسلة نصية عادية وليس ككود. آمن وأنيق.
الحماية رقم 2: الإجراءات المخزنة
\n\nأداة قوية أخرى — الإجراءات المخزنة. إنها لا تحمي فقط من الحقن، بل تحسن الأداء أيضًا (يتم تخزين خطط الاستعلام مؤقتًا).
\n\n-- SQL Server\nCREATE PROCEDURE GetUserByLogin\n @Login NVARCHAR(50)\nAS\nBEGIN\n SELECT * FROM Users WHERE Login = @Login\nEND\n\n// كود C#\nusing (SqlConnection conn = new SqlConnection(connectionString))\n{\n SqlCommand cmd = new SqlCommand("GetUserByLogin", conn);\n cmd.CommandType = CommandType.StoredProcedure;\n cmd.Parameters.AddWithValue("@Login", inputLogin);\n \n conn.Open();\n // ...\n}\n\nالحماية رقم 3: Entity Framework و ORM
\n\nإذا كنت تستخدم Entity Framework (أو أي ORM آخر)، فأنت محمي جزئيًا بالفعل. EF يقوم بإنشاء استعلامات معلمة تلقائيًا. لكن هناك فارق بسيط: استعلامات SQL الخام عبر EF (طريقة FromSqlRaw) — هي نفس عملية الدمج. كن يقظًا!
// سيء:\nvar users = context.Users.FromSqlRaw("SELECT * F