الفريق العربي للبرمجةأرشيف المنتديات · 2000 – 2023
نسخة أرشيفية للقراءة فقط — التسجيل والمشاركة مغلقان، والمحتوى محفوظ كما كان.

ما أفضل أسلوب لتأمين قواعد البيانات؟

بدأه magdy.ahmed في 26 ديسمبر 2012 · 3 رد · 1,086 مشاهدة · في قسم تكنولوجيا Microsoft .NET العام
مشاركة: واتساب X فيسبوك تيليجرام
#1 صاحب الموضوع

السلام عليكم ورحمة الله وبركاته ...

مقدمه:

منذ فتره طويله وانا استخدم لغة #C وقواعد بيانات MSSQL فى البرمجة بنمط Desktop Applications

وتعودت فى كتابة البرامج المعتمده على قواعد البيانات بالاسلوب النمطى الذى تعلمته من الكتب ومواقع الانترنت

وهو عمل Connection String ولزيادة الامان تكون مشفرة Encrypted Connection String تحتوى على عنوان الخادم واسم قاعدة البيانات واسم المستخدم وكلمة المرور

واقوم بتصميم جدول Users يحتوى على اسماء المستخدمين وكلمات المرور، وجدول اخر يحدد صلاحيات كل مستخدم.

فى بدء البرنامج، يقوم بالاتصال بخادم قواعد البيانات، ويطلب من المستخدم الاسم/كلمة المرور ، ثم بعد ادخالهم يتم عمل البرنامج وتحديد صلاحيات هذا المستخدم، وما هو مسموح وغير مسموح

المشكلة:

انا اشعر ان هذا الاسلوب يشوبه ضعف امنى:

1) ان البرنامج هو الذى يحدد الصلاحيات بناءاً على البيانات المخزنه فى قاعدة البيانات، وهنا يمكن عمل كراك للبرنامج يسمح للمستخدم ان يصل لكل ما يريد دون المرور على كود التحقق من الصلاحيات.

2) اذا تم عمل كراك للبرنامج، سيكون باستطاعة المستخدم تنفيذ جمل SQL على قاعدة البيانات، هذه الجمل قد تسمح له مثلاً بتغير وقت حضور وانصراف الموظفين المسجل بواسطة جهاز البصمة المرتبط بقاعدة البيانات.

ما هو افضل اسلوب للتغلب على مثل هذه التحديات ؟

#2

من أجل الأمن اجعل إدارة المستخدمين و الصلاحيات على مستوى السيرفر أقصد سيرفر قواعد البيانات بالأوامر المشهورة grant & revoke & create user............

وبعدها حتى ولو تم كركرة البرنامج فلن يتم الولوج إلى قاعدة البيانات

تم تعديل هذه المشاركة بواسطة أحمد أبو عبد البر في 27 ديسمبر 2012 في 09:28

vVIfFr.gif

مدونتي



إذا رأيتموني غبت فأطلت الغياب فربما أكون قد انتقلت عن الدنيا إلى الآخرة

فما أحوجني إلى دعوة صالحة من أخ لي كريم

 

http://www.tvquran.com/

 

LoGeCom

أول برنامج عربي للمحاسبة والتجارة وإدراة المخازن يعمل على اللينكس والماك والويندوز 

#3

تطبيق غير آمن إن كان كماوصفته، التطبيق يتصل بقاعدة البيانات (بيانات الإتصال في التطبيق). لايلزم عمل كراك أو حتى وجود البرنامج، كل مايزم هو إستخراج معلومات الإتصال بالقاعدة البيانات وبعض المعلومات عن الجدوال والمخترق ومهارته في الـsql.

يلزمك خادم يقوم بنفسه بالإتصال وكل البرامج العملية تتواصل مع الخادم، نموذج الخادم والعميل يمكنك من تحديد صلاحيات المستخدمين. بالنسبة للتطبيق فيمكنك عمل خدمة REST بسيطة، تعمل خادم http والعميل يتصل به ويتبادلان البيانات كـxml أو json.

هذا مثال بسيط كتبته لخادم بإسخدام HttpListener :

using System;
using System.IO;
using System.Net;
using System.Threading;
using System.Xml;
using System.Text;
using System.Text.RegularExpressions;

namespace CSharpServer
{
	class HttpService
	{
    	public bool logging = false;

    	private HttpListener listener = new HttpListener();
    	private HttpListenerContext context;
    	private HttpListenerRequest request;
    	private HttpListenerResponse response;
    	private string request_url;
    	private struct UserInfo
    	{
        	public string id;
        	public string username;
        	public string password;
    	};

    	public HttpService(string host, UInt32 port)
    	{
        	string url = String.Format("http://{0}:{1}/", host, port);
        	listener.Prefixes.Add(url);
    	}

    	public void start()
    	{
        	listener.Start();

        	Thread server_thread = new Thread(listen);
        	server_thread.Start();
    	}

    	public void stop()
    	{
        	listener.Stop();
    	}

    	private void listen()
    	{
        	while (listener.IsListening)
        	{
            	context = listener.GetContext();
            	request = context.Request;
            	response = context.Response;
            	request_url = request.Url.AbsolutePath;

            	process();

            	context.Response.OutputStream.Close();
            	context.Response.Close();

        	}
    	}

    	private void writeString(string data)
    	{
        	Byte[] buffer;
        	buffer = Encoding.UTF8.GetBytes(data);
        	context.Response.OutputStream.Write(buffer, 0, buffer.Length);
    	}

    	private UserInfo getUserInfo()
    	{
        	UserInfo userinfo;
        	StreamReader reader = new StreamReader(request.InputStream, request.ContentEncoding);
        	XmlDocument xml = new XmlDocument();
        	string xmlData = reader.ReadToEnd();

        	xml.LoadXml(xmlData);

        	userinfo.id = xml.SelectSingleNode("userinfo/id").InnerText;
        	userinfo.username = xml.SelectSingleNode("userinfo/username").InnerText;
        	userinfo.password = xml.SelectSingleNode("userinfo/password").InnerText;

        	return userinfo;
    	}

    	private void logError(int a)
    	{
        	if (logging)
        	{
            	Console.WriteLine("Log: access denied from ({0}{1})", request.UserHostAddress, a);
        	}
    	}

    	private void logLogin(string username)
    	{
        	if (logging)
        	{
            	Console.WriteLine("Log: user loged-in ({0}).", username);
        	}
    	}

    	private void logMessage(string message)
    	{
        	if (logging)
        	{
            	Console.WriteLine("Log: {0}", message);
        	}
    	}

    	private void sendAccessDenied()
    	{
        	writeString("access denied");
    	}

    	private void getAction()
    	{
        	Match m = Regex.Match(request_url, "^/([a-z]+)/.*");

        	if (!m.Success)
        	{
            	sendAccessDenied();
            	logError(4);
            	return;
        	}

        	string action = m.Groups[1].Value;

        	switch (action)
        	{
            	case "login":
                	action_login();
                	break;
            	default:
                	sendAccessDenied();
                	logError(5);
                	return;
        	}
    	}

    	private void action_login()
    	{
        	string loginUrl = "^/login/([a-z0-9]{8})-([a-z0-9]{4})-([a-z0-9]{4})-([a-z0-9]{4})-([a-z0-9]{12})/$";
        	string id = "698c1323-7120-4d96-b8ff-4d2c95a65fd2"; // UUID4
        	string username = "Barakat S.";
        	string password = "myPassword123";

        	if (request.HttpMethod == "POST" && Regex.IsMatch(request_url, loginUrl))
        	{
            	try
            	{
                	UserInfo userinfo = getUserInfo();

                	if (userinfo.id == id && userinfo.username == username && userinfo.password == password)
                	{
                    	writeString("Welcome " + userinfo.username + "!");
                    	logLogin(userinfo.username);
                	}
                	else
                	{
                    	sendAccessDenied();
                    	logError(1);
                	}
            	}
            	catch (XmlException)
            	{
                	logError(2);
            	}

        	}
        	else
        	{
            	sendAccessDenied();
            	logError(3);
        	}
    	}

    	private void process()
    	{
        	getAction();
    	}
	}

	class Program
	{
    	static void Main(string[] args)
    	{
        	HttpService server = new HttpService("localhost", 30000);
        	server.logging = true;
        	server.start();
    	}
	}
}

وهذا عميل:

using System;
using System.Net;
using System.IO;
using System.Xml;
using System.Text;

namespace CSharpClient
{
	class UserLogin
	{
    	private string host = "http://localhost:30000";
    	public string id;
    	public string username;
    	public string password;

    	public UserLogin(string id, string username, string password)
    	{
        	this.id = id;
        	this.username = username;
        	this.password = password;
    	}

    	private byte[] buidXml()
    	{
        	XmlDocument xml = new XmlDocument();
        	XmlNode userInfo = xml.CreateElement("userinfo");

        	XmlNode id = xml.CreateElement("id");
        	id.AppendChild(xml.CreateTextNode(this.id));
        	userInfo.AppendChild(id);

        	XmlNode username = xml.CreateElement("username");
        	username.AppendChild(xml.CreateTextNode(this.username));
        	userInfo.AppendChild(username);

        	XmlNode password = xml.CreateElement("password");
        	password.AppendChild(xml.CreateTextNode(this.password));
        	userInfo.AppendChild(password);

        	xml.AppendChild(userInfo);

        	return Encoding.Default.GetBytes(xml.OuterXml);
    	}

    	private string post(string url, byte[] data)
    	{
        	HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
        	request.Method = "POST";
        	request.ContentType = "application/x-www-form-urlencoded";
        	request.ContentLength = data.Length;
        	try
        	{
            	request.GetRequestStream().Write(data, 0, data.Length);
        	}
        	catch (WebException)
        	{
            	return "Error: unable to connect to " + host;
        	}
        	request.GetRequestStream().Close();
        	WebResponse response = request.GetResponse();
        	StreamReader reader = new StreamReader(response.GetResponseStream());
        	return (string)reader.ReadToEnd();
    	}

    	public string login()
    	{
        	byte[] xmlData = buidXml();
        	string loginUrl = String.Format("{0}/{1}/{2}/", host, "login", this.id);

        	string message = post(loginUrl, xmlData);
        	return message;
    	}
	}

	class Program
	{
    	static void Main(string[] args)
    	{
        	string id = "698c1323-7120-4d96-b8ff-4d2c95a65fd2"; // UUID4
        	string username = "Barakat S.";
        	string password = "myPassword123";

        	UserLogin user = new UserLogin(id, username, password);
        	Console.WriteLine(user.login());
        	Console.Read();
    	}
	}
}

المثال يمكن تحسينه (هذه أول تجربه لي مع c#)

يقوم العميل بإرسال xml يحتوي معرف المستخدم (مولد بإستخدام UUID4 - GUID) وإسم المستخدم وكلمة المرور في ملف xml على الرابط:

/login/XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX/

ويقرأ الخادم ملف الـxml المرسل ويتحقق حينها من هويته.

1
#4
أحمد أبو عبد البر كتب:

من أجل الأمن اجعل إدارة المستخدمين و الصلاحيات على مستوى السيرفر أقصد سيرفر قواعد البيانات بالأوامر المشهورة grant & revoke & create user............

وبعدها حتى ولو تم كركرة البرنامج فلن يتم الولوج إلى قاعدة البيانات

أنا في الواقع لم أفهم ما قاله الأخ Mr.B لكن أود أن أقول تعليق (أو سؤال على شكل تعليق) :

المسألة ليست فقط صلاحيات إنما context أيضاً ، سأعطيك مثال بسيط جدا ....

افترض أن لدينا قاعدة بيانات فيها جدول للمستودع وجدول للحسابات وجدول يعمل كـ log (اسف لا أعرف معنى هذه الكلمة بالعربية) ، فإذا أردنا إدخال كمية من البضاعة للمستودع - مثلا - فيجب أن يتم إدخاله في جدول الحسابات وفي جدول ال log أيضاً . فإذا أردنا أن يتمكن أي مستخدم من أن يدخل بضاعة لجدول الحسابات فيجب أن يكون لديه الصلاحية أيضا لإضافة بيانات في الجدولين الآخرين.

السؤال هو : ما الذي يمنع أي مستخدم (ممن لديهم هذه الصلاحيات) من أي يستعمل أي sql client مستخدماً الاسم وكلمة السر خاصته ويقوم بإضافة سجلات في أحد الجداول دون إضافتها للجداول الأخرى ، وبالتالي "تخريب" صحة قاعدة البيانات؟

مواضيع مشابهة

عدد الزوار حالياً

المتواجدون خلال آخر دقيقتين · يتحدّث كل ٣٠ ثانية

—الإجمالي—أعضاء مسجّلون—زوار بدون تسجيل

جارٍ التحقق من المتواجدين…