2009-05-15 29 views
5

Tôi đang cập nhật một ứng dụng web ASP/MySql cũ lên ASP.NET/SQL SQL.Mô phỏng mật khẩu() của MySql bằng cách sử dụng .NET hoặc MS SQL

Chúng tôi muốn giữ thông tin đăng nhập từ trang web cũ hoạt động trong ứng dụng mới.

Thật không may mật khẩu đã được lưu trữ trong MySql DB bằng cách sử dụng hàm MySql().

Có thể mô phỏng hàm mật khẩu MySql() trong .NET hoặc MS SQL không?

Mọi trợ giúp/liên kết đều được đánh giá cao.

+1

Bạn đang sử dụng phiên bản MySQL nào? Có vẻ như điều này có thể xảy ra nếu bạn biết bạn đang sử dụng phiên bản nào. MySQL sử dụng thuật toán băm SHA1 kép để mã hóa mật khẩu. –

+0

Sẽ kiểm tra điều này khi tôi có quyền truy cập vào DB mysql. Cảm ơn bạn đã đăng giải pháp! –

Trả lời

12

Theo tài liệu MySQL, thuật toán là hàm băm SHA1 kép. Khi kiểm tra mã nguồn MySQL, bạn tìm thấy một hàm gọi là make_scrambled_password() trong libmysql/password.c. Hàm được định nghĩa như sau:

/* 
    MySQL 4.1.1 password hashing: SHA conversion (see RFC 2289, 3174) twice 
    applied to the password string, and then produced octet sequence is 
    converted to hex string. 
    The result of this function is used as return value from PASSWORD() and 
    is stored in the database. 
    SYNOPSIS 
    make_scrambled_password() 
    buf  OUT buffer of size 2*SHA1_HASH_SIZE + 2 to store hex string 
    password IN NULL-terminated password string 
*/ 

void 
make_scrambled_password(char *to, const char *password) 
{ 
    SHA1_CONTEXT sha1_context; 
    uint8 hash_stage2[SHA1_HASH_SIZE]; 

    mysql_sha1_reset(&sha1_context); 
    /* stage 1: hash password */ 
    mysql_sha1_input(&sha1_context, (uint8 *) password, (uint) strlen(password)); 
    mysql_sha1_result(&sha1_context, (uint8 *) to); 
    /* stage 2: hash stage1 output */ 
    mysql_sha1_reset(&sha1_context); 
    mysql_sha1_input(&sha1_context, (uint8 *) to, SHA1_HASH_SIZE); 
    /* separate buffer is used to pass 'to' in octet2hex */ 
    mysql_sha1_result(&sha1_context, hash_stage2); 
    /* convert hash_stage2 to hex string */ 
    *to++= PVERSION41_CHAR; 
    octet2hex(to, (const char*) hash_stage2, SHA1_HASH_SIZE); 
} 

Với phương pháp này, bạn có thể tạo đối tác .NET về cơ bản cũng làm như vậy. Đây là những gì tôi đã đưa ra. Khi tôi chạy SELECT PASSWORD ('test'); chống lại bản sao cục bộ của tôi về MySQL, giá trị trả về là:

*94BDCEBE19083CE2A1F959FD02F964C7AF4CFC29

Theo mã nguồn (một lần nữa trong password.c), dấu hoa thị bắt đầu chỉ ra rằng đây là phương pháp 4.1 hậu MySQL của mã hóa mật khẩu. Khi tôi mô phỏng các chức năng trong VB.Ví dụ: net, đây là những gì tôi đưa ra:

Public Function GenerateMySQLHash(ByVal strKey As String) As String 
    Dim keyArray As Byte() = Encoding.UTF8.GetBytes(strKey) 
    Dim enc = New SHA1Managed() 
    Dim encodedKey = enc.ComputeHash(enc.ComputeHash(keyArray)) 
    Dim myBuilder As New StringBuilder(encodedKey.Length) 

    For Each b As Byte In encodedKey 
     myBuilder.Append(b.ToString("X2")) 
    Next 

    Return "*" & myBuilder.ToString() 
End Function 

Hãy nhớ rằng SHA1Managed() nằm trong không gian tên System.Security.Cryptography. Phương thức này trả về kết quả đầu ra giống như lời gọi PASSWORD() trong MySQL. Tôi hy vọng điều này sẽ giúp ích cho bạn.

Edit: Đây là cùng mã trong C#

public string GenerateMySQLHash(string key) 
{ 
    byte[] keyArray = Encoding.UTF8.GetBytes(key); 
    SHA1Managed enc = new SHA1Managed(); 
    byte[] encodedKey = enc.ComputeHash(enc.ComputeHash(keyArray)); 
    StringBuilder myBuilder = new StringBuilder(encodedKey.Length); 

    foreach (byte b in encodedKey) 
     myBuilder.Append(b.ToString("X2")); 

    return "*" + myBuilder.ToString(); 
} 
+0

Tuyệt vời, cảm ơn! Sẽ thử nếu nó hoạt động cho phiên bản mysql của tôi (không thể kiểm tra nó vào lúc này) và cho bạn biết. Rất cám ơn cho nghiên cứu và giải pháp tuyệt vời. –

+0

Nếu bạn đang sử dụng phiên bản trước 4.1.1, có phương pháp mã hóa cũ hơn. Tôi cũng có thể giúp bạn viết ra phương pháp đó. Hãy cho tôi biết và tôi sẽ sẵn lòng hỗ trợ. Chúc may mắn! –

+0

Tôi thực sự tìm thấy một cách để làm điều này với T-SQL quá. Nó trông khá xấu xí, nhưng nó hoạt động! SELECT '*' + SUBSTRING (master.dbo.fn_varbintohexstr (HASHBYTES ('SHA1', HASHBYTES ('SHA1', 'VALUE-TO-ENCRYPT-GOES-HERE'))), 1,42) –

1

Bạn có thể mã hóa chuỗi bằng MD5 hoặc SHA1 bằng .Net, nhưng thuật toán thực tế được MySQL sử dụng có lẽ khác với hai phương pháp này. Tôi nghi ngờ nó dựa trên một số loại 'muối' dựa trên trường hợp của máy chủ, nhưng tôi không biết.

Về lý thuyết, vì tôi tin rằng MySQL là nguồn mở, bạn có thể điều tra nguồn và xác định cách thực hiện điều này.

http://dev.mysql.com/doc/refman/5.1/en/encryption-functions.html#function_password

Sửa 1: Tôi tin rằng các thuật toán sử dụng là một SHA1 đôi với khác 'chỉnh' (theo this bài viết trên blog).

+0

Tôi biết, tôi biết ... Đã có thể nghiên cứu thông tin đó nhưng nó không thực sự trả lời câu hỏi của tôi :-) Cảm ơn mọi người. –

+0

Tôi nhìn vào nguồn, và tôi nghĩ rằng nó dựa trên SHA1, nhưng với nhiều công nghệ muối và ngẫu nhiên. Không phải là rất hữu ích tôi biết, vì vậy tôi nghĩ rằng câu trả lời là để tìm nơi khác: ( – samjudson

+0

cảm ơn 1 để kiểm tra nguồn :-) –

-3

Bạn sẽ không thể mô phỏng hàm mySql password(). ít nhất là không có nhiều công việc và may mắn. Là MySql sử dụng thuật toán riêng của họ để chuỗi mã hóa một chiều, họ sẽ không tiết lộ những thuật toán mà họ sử dụng; có nghĩa là bạn sẽ phải làm thử và sai, so sánh chuỗi kết quả vv

Để khắc phục vấn đề của bạn:

tôi muốn tái tạo DB nhưng duy trì kết nối với MySql. Sử dụng cờ để xác định lần đăng nhập đầu tiên. Yêu cầu họ sử dụng mật khẩu hiện tại của họ; xác minh mật khẩu bằng hàm MySql password(). Nếu mật khẩu hợp lệ; yêu cầu họ đặt lại, bằng cách nhập lại cùng một mật khẩu hoặc một mật khẩu mới; tại thời điểm này sử dụng thuật toán mã hóa yêu thích của bạn và lưu trữ kết quả trong MS Sql DB của bạn.

Tôi biết nó nghe có vẻ như là một nỗi đau, nhưng tốt nhất bạn nên cố gắng tìm cách giải mã thuật toán mã hóa MySql.

Chúc may mắn!

+0

Cảm ơn thông tin.Tôi sẽ sử dụng một phần giải pháp của bạn: Bước đầu tiên, nhập người dùng vào MS SQL và đặt bit "HasMysqlPassword" thành "1". Bước thứ hai, khi đăng nhập, tôi lấy các chi tiết người dùng MS SQL và kiểm tra xem HasMysqlPassword = 1. Nếu không, tôi kiểm tra trường "Mật khẩu" trong MS SQL. Nếu có, tôi sẽ kiểm tra mật khẩu trong mysql. Nếu nó khớp, tôi mã hóa mật khẩu đã nhập bằng SHA1, lưu trữ nó trong MS SQL trong khi thiết lập HasMysqlPassword thành 0. Sau một thời gian tôi có thể tách cơ sở dữ liệu mysql và thông báo cho người dùng còn lại rằng mật khẩu mới của họ là * autogenerated * –

+0

tốt đẹp về cách tiếp cận đó là người dùng sẽ không nhận thấy điều gì. –

+0

Điều này không đúng. Tôi đã viết một phương thức để chuyển đổi thành các băm mật khẩu hợp lệ trong .NET ... post để theo dõi –

0

Đối ròng VB, miếng đệm này với 0 của sang trái để khi mã hex là [ví dụ] 'E', chức năng này sẽ nối một cách chính xác '0E' đến chuỗi kết quả. Vì vậy mà vào cuối, bao gồm cả tiền pended '*' chuỗi kết quả sẽ là 41 nhân vật dài, như là cần thiết trong MySQL

Public Function GenerateMySQLHash(ByVal strKey As String) As String 

    Dim keyArray As Byte() = System.Text.UTF8Encoding.UTF8.GetBytes(strKey) 
    Dim enc = New Security.Cryptography.SHA1Managed() 
    Dim encodedKey = enc.ComputeHash(enc.ComputeHash(keyArray)) 
    Dim myBuilder As New System.Text.StringBuilder(encodedKey.ToString.Length) 

    For Each b As Byte In encodedKey 
     myBuilder.Append(Strings.Right("0" & b.ToString("X"), 2)) 
    Next 

    Return "*" & myBuilder.ToString() 
End Function 
1

"họ sẽ không tiết lộ gì thuật toán họ sử dụng"

erm ... ai đó nên đánh thức và nói với bạn rằng MySQL là MỞ nGUỒN ... họ không cần phải "tiết lộ" một cái gì đó bởi vì tất cả mọi người có thể đọc các cấu trúc của cơ sở dữ liệu - chỉ cần tải về nguồn, tìm kiếm các chức năng mã hóa (tôi đoán chúng đang sử dụng C++) và bắt đầu inve stigating ... SHA1 dường như khá không an toàn - chỉ gần đây một vài nhà khoa học đã chứng minh rằng có thể chọn tối đa 20% dữ liệu không hạn chế và sản xuất cùng một mã băm. hoặc SHA2 (do đó không phải là MySQL- pASSWORD -func)

0

các chức năng mật khẩu mysql là không đặc biệt an toàn (ví dụ như không có muối hoặc các phương pháp khác bảo vệ chống lại tìm kiếm băm phù hợp) những lý do duy nhất tôi có thể nhìn thấy vì muốn sao chép thuật toán là 1: bạn có danh sách/bảng người dùng có mật khẩu mysql() s 2: bạn muốn crack mật khẩu mysql từ băm trong bảng người dùng.

Khác sử dụng thứ gì đó khác, ví dụ: băm kết hợp cả tên của người dùng (và/hoặc một số bất biến hàng khác) và mật khẩu của họ. thay thế nếu hai người dùng chọn cùng một mật khẩu thì sẽ không rõ ràng. và nếu bảng được tiếp xúc, bảo mật sẽ không giảm ở cùng tốc độ (ví dụ: google cho 446a12100c856ce9 là mật khẩu() của mật khẩu rất phổ biến)

1

Phiên bản C# được sửa đổi để sửa vấn đề đệm.
[Kiểm tra] khoảng trống công khai GenerateMySQLHashX2() { mật khẩu chuỗi = "20iva05";

 byte[] keyArray = Encoding.UTF8.GetBytes(password); 
     SHA1Managed enc = new SHA1Managed(); 
     byte[] encodedKey = enc.ComputeHash(enc.ComputeHash(keyArray)); 
     StringBuilder myBuilder = new StringBuilder(encodedKey.Length); 

     foreach (byte b in encodedKey) 
     { 
      log.Debug(b.ToString() + " -> " + b.ToString("X2")); 
      myBuilder.Append(b.ToString("X2")); 
     } 

     Assert.AreEqual("*8C2029A96507478FD1720F6B713ADD57C66EED49", "*" + myBuilder.ToString()); 
    } 
Các vấn đề liên quan