منتدى فيجوال بيسك لكل العرب | منتدى المبرمجين العرب
تشفير الأسرار للمستخدم الحالي - نسخة قابلة للطباعة

+- منتدى فيجوال بيسك لكل العرب | منتدى المبرمجين العرب (http://vb4arb.com/vb)
+-- قسم : قسم لغة الفيجوال بيسك VB.NET (http://vb4arb.com/vb/forumdisplay.php?fid=182)
+--- قسم : قسم مقالات VB.NET (http://vb4arb.com/vb/forumdisplay.php?fid=184)
+--- الموضوع : تشفير الأسرار للمستخدم الحالي (/showthread.php?tid=4964)



تشفير الأسرار للمستخدم الحالي - RaggiTech - 03-10-12

كاتب الموضوع : samerselo

يحتاج التطبيق في كثير من الأحيان إلى تخزين بيانات خصوصية في ملف أو في الذاكرة والحل الواضح هو التشفير المتماثل الذي يشفر البيانات باستخدام سلسة عشوائية من البايتات تدعى بالمفتاح السري. وتكمن المشكلة عندما تريد فك تشفير البيانات المشفرة في أنك ستحتاج لنفس المفتاح السري الذي استخدمته للتشفير مما يؤدي إلى سلسلة من التعقيدات فإما أنك ستحتاج إلى مكان آمن لتخزين المفتاح السري وهذا أمر صعب أو أنك ستحتاج لاستخلاصه من معلومات أخرى مثل كلمة سر مزودة من قبل المستخدم والتي تكون في الغالب غير آمنة وستنهار كليا عندما ينسى المستخدم كلمة السر الخاصة به.

و الحل المثالي هو جعل نظام الويندوز يقوم بتشفير البيانات من أجلك ولتحقيق هذا ستحتاج إلى ما يسمى بـ DPAPI أو Data Protection API والذي يقوم بتشفير البيانات باستخدام مفتاح متماثل مبني على معلومات خاصة بالمستخدم والآلة وبهذه الطريقة لم تعد تقلق بخصوص تخزين المفتاح ووثوقيته وبدلا عن ذلك يتأكد نظام التشغيل من وثوقية المستخدم عندما يدخل إلى النظام وتكون البيانات المخزنة من قبل مستخدم غير ممكنة الوصول بالنسبة للمستخدمين الآخرين.
في النسخ السابقة من الدوت نيت لايوجد فئات مدارة لاستخدام DPAPI وتم تصحيح هذا في الدوت نيت 2.0 بالفئة الجديدة ProtectData في مجال الأسماء System.Security.Cryptography

كيف يمكنني فعل ذلك

الفئة ProtectData تقدم طريقتان مشتركتان Shared Methods الأولى ProtectData تأخذ مصفوفة بايتات تمثل البيانات المراد تشفيرها وتعيد مصفوفة بايتات بالبيانات المشفرة والثانية UnprotectData تقوم بالعملية المعاكسة حيث تأخذ مصفوفة بايتات بالبيانات المشفرة وتعيد مصفوفة بايتات بالبيانات المفكوك تشفيرها. وباستخدام ProtectData و UnprotectData يمكنك فقط التعامل مع مصفوفات بايتات Byte Array وهذا يعني أنك عندما تريد تشفير بيانات من أي نوع عليك القيام بتحويلها إلى مصفوفة بايتات قبل القيام بالتشفير.

مثال عملي


كود :
Imports System.Security.Cryptography
Imports System.IO

Module ProtectData

Sub Main()

' Get the data.
Console.WriteLine("Enter a secret message and press enter.")
Console.Write(">")
Dim Input As String = Console.ReadLine()
Console.WriteLine()

If Input <> "" Then
Dim Data(), EncodedData() As Byte

' Write the data to a new MemoryStream.
Dim DataStream As New MemoryStream()
Dim Writer As New StreamWriter(DataStream)
Writer.Write(Input)
Writer.Close()

' Convert the MemoryStream into a byte array,
' which is what you need to use the ProtectData() method.
Data = DataStream.ToArray()

' Encrypt the byte array.
EncodedData = ProtectedData.Protect(Data, Nothing, _
DataProtectionScope.CurrentUser)

' Store the encrypted data in a file.
My.Computer.FileSystem.WriteAllBytes("c:\secret.bin", _
EncodedData, False)

End If
End Sub

End Module
عندما تقوم بتشغيل التطبيق سيطلب من إدخال نص والذي سيقوم بتشفيره باستخدام الحساب الحالي للمستخدم ويقوم بتخزين البيانات في الملف secret.bin والبيانات الموجودة فيه لن يستطيع قراءتها أي مستخدم آخر. وللتأكد من أن البيانات مشفرة فعلا لديك خياران قم بفتح الملف وألقي نظرة بنفسك أو يمكنك تعديل الكود ليقرأ البيانات مباشرة من مجرى الذاكرة Memory Stream و الكود التالي يحاول القيام بالخيار الثاني ونتيجة إظهاره ستتكون سلسة نصية لا معنى لها


كود :
' Verify the data is encrypted by reading and displaying it
' without performing any decryption.
DataStream = New MemoryStream(EncodedData)
Dim Reader As New StreamReader(DataStream)
Console.WriteLine("Encrypted data: " & Reader.ReadToEnd())
Reader.Close()
ولتفكيك تشفير البيانات يجب عليك وضعها في مصفوفة بايتات ثم استخدام الطريقة UnprotectData لاستخلاص البيانات من مصفوفة البايتات ويمكنك إضافة StreamReader لإضافة دعم لتفكيك التشفير للمثال السابق مثلا يمكنك إضافة الكود التالي ليقرأ البيانات من الملف ويظهر الجملة التي أدخلتها سابقا


كود :
If My.Computer.FileSystem.FileExists("c:\secret.bin") Then
Dim Data(), EncodedData() As Byte

EncodedData = My.Computer.FileSystem.ReadAllBytes("c:\secret.bin")
Data = ProtectedData.Unprotect(EncodedData, Nothing, _
DataProtectionScope.CurrentUser)

Dim DataStream As New MemoryStream(Data)
Dim Reader As New StreamReader(DataStream)

Console.WriteLine("Decoded data from file: " & Reader.ReadToEnd())
Reader.Close()
Console.WriteLine()
End If
تذكر بما أن البيانات تم تشفيرها بواسطة حساب المستخدم الحالي يمكنك تفكيك تشفيرها في أي وقت والقيد الوحيد هو انك يجب أن تدخل باستخدام نفس حساب المستخدم ولاحظ أنك عندما تقوم بحماية البيانات يجب عليك اختيار واحدة من القيم من التعداد DataProtectionScope Enumeration ويكون بذلك لديك خياران:

LocalMachine

سيقوم ويندوز بتشفير البيانات بمفتاح خاص بالآلة وبهذا تضمن أن لا أحد يستطيع قراءة البيانات إلا على نفس الجهاز. وهذا يعمل جيدا بالنسبة للتطبيقات التي تعمل على المخدم Server Side Application والتي تعمل بدون تدخل المستخدم

CurrentUser

سيقوم ويندوز بتشفير البيانات بمفتاح خاص بالمستخدم وبالتالي لا يمكن قراءتها من قبل المستخدمين الآخرين

في المثال المذكور يتم تخزين بيانات خاصة بالمستخدم ومع ذلك يمكنك تغيير مجال حماية البيانات DataProtectionScope ليتم تخزين البيانات بشكل يستطيع جميع مستخدمي الجهاز الوصول إليها.


وفيما يلي سرد للمثال كاملا وهو تطبيق من نوع Console Application



كود :
Imports System.Security.Cryptography
Imports System.IO

Module ProtectData
Sub Main()

' Get the data.
Console.WriteLine("Enter a secret message and press enter.")
Console.Write(">")
Dim Input As String = Console.ReadLine()
Console.WriteLine()

If Input <> "" Then
Dim Data(), EncodedData() As Byte

' Write the data to a new MemoryStream.
Dim DataStream As New MemoryStream()
Dim Writer As New StreamWriter(DataStream)
Writer.Write(Input)
Writer.Close()

' Convert the MemoryStream into a byte array,
' which is what you need to use the ProtectData() method.
Data = DataStream.ToArray()

' Encrypt the byte array.
EncodedData = ProtectedData.Protect(Data, Nothing, _
DataProtectionScope.CurrentUser)

' Store the encrypted data in a file.
My.Computer.FileSystem.WriteAllBytes("c:\secret.bin", _
EncodedData, False)

' Verify the data is encrypted by reading and displaying it
' without performing any decryption.
DataStream = New MemoryStream(EncodedData)
Dim Reader As New StreamReader(DataStream)
Console.WriteLine("Encrypted data: " & Reader.ReadToEnd())
Reader.Close()
Console.WriteLine()
End If

If My.Computer.FileSystem.FileExists("c:\secret.bin") Then
Dim Data(), EncodedData() As Byte

EncodedData = My.Computer.FileSystem.ReadAllBytes("c:\secret.bin")
Data = ProtectedData.Unprotect(EncodedData, Nothing, _
DataProtectionScope.CurrentUser)

Dim DataStream As New MemoryStream(Data)
Dim Reader As New StreamReader(DataStream)

Console.WriteLine("Decoded data from file: " & Reader.ReadToEnd())
Reader.Close()
Console.WriteLine()
End If

Console.ReadLine()
End Sub

End Module

ماذا عن ...

حماية البيانات قبل تخزينها في قاعدة البيانات؟ طالما أنك استخدمت الفئة ProtectedData لتشفير بياناتك يمكنك وضعها في أي مكان تريده ففي المثال السابق قمت بكتابة البيانات المشفرة إلى ملف ومع ذلك يمكنك كتابة البيانات الثنائية إلى سجل قاعدة البيانات ولفعل ذلك ستحتاج ببساطة إلى حقل ثنائي binary في جدولك بمساحة كافية ليتسع لمصفوفة البايتات المشفرة وفي الـ Sql Server تستخدم نوع البيانات varbinary لهذا الغرض