เนื่องจากความต้องการงานประจำวัน หน่วยจึงใช้ Serv-U เพื่อตั้งค่าเซิร์ฟเวอร์ FTP อย่างไรก็ตาม หลังจากเข้าควบคุมพบว่ามีปัญหาร้ายแรงมาก เซิร์ฟเวอร์ FTP นี้เปิดให้บุคคลทั่วไปเข้าชมได้ ไม่ได้ตั้งรหัสผ่าน หากทุกคนจำเป็นต้องตั้งรหัสผ่านและต้องตั้งบนเซิร์ฟเวอร์ ก็ไม่ได้หมายความว่าทุกคนจะต้องบอกรหัสผ่านของตนแก่ผู้ดูแลระบบใช่หรือไม่ ท้ายที่สุดแล้ว หลายๆ คนก็คุ้นเคยกับการใช้รหัสผ่านเดียวกัน จะทำอย่างไร? วิธีที่ดีที่สุดคือจัดให้มีเว็บเพจเพื่อจัดเตรียมฟังก์ชันแก้ไขรหัสผ่าน
เพียงไปข้างหน้าและตรวจสอบออนไลน์ วิธีหนึ่งคือการใช้ฟังก์ชัน ODBC ที่ Serv-U จัดทำขึ้นเอง ใช้ฐานข้อมูลเพื่อจัดเก็บรหัสผ่านและดำเนินการฐานข้อมูลโดยตรงเพื่อรับรู้ถึงฟังก์ชันการแก้ไขรหัสผ่าน อย่างไรก็ตาม หลังจากทดสอบวิธีนี้แล้ว ก็ไม่มากนัก เป็นไปได้ เนื่องจากเซิร์ฟเวอร์ FTP นี้เปิดใช้งานมาเป็นเวลาหนึ่งปีแล้วและมีผู้ใช้เกือบ 60 ราย ความน่าจะเป็นของข้อผิดพลาดเมื่อย้ายผู้ใช้เหล่านี้จากไฟล์ INI ไปยังฐานข้อมูลจึงยังค่อนข้างสูง
สิ่งแรกคือการพิจารณาว่าข้อมูลผู้ใช้ของ Serv-U ถูกบันทึกในไฟล์ INI อย่างไร และรหัสผ่านถูกเข้ารหัสอย่างไร โครงสร้างของไฟล์ INI นั้นค่อนข้างง่าย หากต้องการแก้ไขรหัสผ่าน เพียงค้นหาส่วนที่ขึ้นต้นด้วย [User=@UserID|1] และแก้ไขค่าของคีย์รหัสผ่านที่อยู่ด้านล่าง @UserID หมายถึง ID เข้าสู่ระบบของผู้ใช้
1[ทั่วโลก]
2เวอร์ชัน=6.1.0.5
3แพ็คเก็ตไทม์เอาต์=300
4
5
6
7[โดเมน1]
8User1=
9User2=
10ผู้ใช้3=
11
12
13
14[USER=เอบีซี|1]
15รหัสผ่าน=niE383DC3710266ECAE04A6B3A18A2966D
16HomeDir=D:
17อนุญาตการเข้าสู่ระบบเสมอ=1
18เปลี่ยนรหัสผ่าน=1
19หมดเวลา=600
20Note1="บัญชีที่สร้างโดยวิซาร์ด"
21การเข้าถึง1=D:
ยี่สิบสอง
ยี่สิบสาม
วิธีการเข้ารหัสรหัสผ่านผู้ใช้สามารถพบได้ในฐานความรู้ของเว็บไซต์อย่างเป็นทางการของ Ser-U
http://rhinosoft.com/KBArticle.asp?RefNo=1177&prod=su
การป้อนรหัสผ่านที่เข้ารหัสลงในไฟล์ ServUDaemon.ini ด้วยตนเอง
ในการสร้างรหัสผ่านที่เข้ารหัส อักขระสุ่มสองตัวแรก ('เกลือ' - ในช่วง a..z, A..Z) จะถูกเพิ่มที่จุดเริ่มต้นของรหัสผ่านข้อความธรรมดา ซึ่งจะถูกแฮชโดยใช้ MD5 และผลลัพธ์ แฮชมีการเข้ารหัสแบบ hex ผลลัพธ์นี้จะเขียนเป็นข้อความธรรมดาที่ขึ้นต้นด้วยอักขระเกลือ 2 ตัว ตามด้วยแฮชที่เข้ารหัสแบบ hex
สำหรับบัญชีผู้ใช้ในไฟล์ .ini จะมีลักษณะดังนี้:
รหัสผ่าน=cb644FB1F31184F8D3D169B54B3D46AB1A
The salt คือสตริง "cb" แฮช MD5 คือ "644FB1F31184F8D3D169B54B3D46AB1A"
เมื่อตรวจสอบรหัสผ่านของผู้ใช้ Serv-U จะทำเช่นเดียวกัน โดยจะแยกวิเคราะห์เกลือจากรหัสผ่านที่เก็บไว้ของผู้ใช้ (เช่น "cb" ในกรณีนี้) จะอยู่ข้างหน้า เป็นรหัสผ่านที่ผู้ใช้ส่งมาโดยไคลเอนต์ MD5 แฮชและเปรียบเทียบผลลัพธ์กับแฮชที่เก็บไว้ หากค่าเท่ากันแสดงว่ารหัสผ่านที่ป้อนนั้นถูกต้อง
วิธีการเข้ารหัสคือการสุ่มสร้างตัวอักษรสองตัว จากนั้นประกบตัวอักษรและรหัสผ่าน จากนั้นค้นหาค่า MD5 สุดท้าย ให้วางตัวอักษรสุ่มไว้หน้าค่า MD5 เพื่อรับรหัสผ่านที่เข้ารหัส
ถัดไป คุณสามารถเขียนโปรแกรมตามการวิเคราะห์ข้างต้นเพื่อดำเนินการแก้ไขแบบออนไลน์ได้
1 /***////// <สรุป>
2 /// รับค่า MD5 ของสตริงที่ระบุ
3 /// </สรุป>
4 /// <param name="strContent"></param>
5 /// <ส่งคืน></ส่งคืน>
6 สตริงสาธารณะ MD5 (สตริง strContent)
7 {
8 System.Security.Cryptography.MD5 md5 = System.Security.Cryptography.MD5CryptoServiceProvider ใหม่();
9 ไบต์ [] ไบต์ = System.Text.Encoding.UTF8.GetBytes (strContent);
10 ไบต์ = md5.ComputeHash (ไบต์);
11 md5.เคลียร์();
12 สตริง ret = "";
13 สำหรับ (int i=0; i<bytes.Length; i++)
14 {
15 ret += Convert.ToString(bytes[i],16).PadLeft(2,'0');
16}
17 กลับ ret.PadLeft(32,'0').ToUpper();
18}
19
20
21 /***//// <สรุป>
22 /// สร้างสตริงสุ่ม ความยาวของสตริงคือ 2
23 /// </สรุป>
24 /// <ส่งคืน></ส่งคืน>
25 สตริงสาธารณะ GetRandomString()
26 {
27 สตริง strReturn = "";
28 สุ่มวิ่ง = สุ่มใหม่ ();
29 strReturn += แปลง ToChar( ran.Next( 26 ) + 'a' ).ToString();
30 strReturn += แปลง ToChar( ran.Next( 26 ) + 'a' ).ToString();
31 กลับ strReturn;
32}
33
34 //สร้างรหัสผ่านที่เข้ารหัสจากตัวอักษรสุ่มและรหัสผ่านเข้าสู่ระบบที่ระบุ
35 สตริงสาธารณะ CreateCryPassword (สตริง strFrontChars, สตริง strPassword)
36 {
37 ส่งคืน strFrontChars + MD5( strFrontChars + strPassword ).ToUpper().Trim();
38 }
39
40 /***////// <สรุป>
41 /// คลิกเหตุการณ์ "เปลี่ยนรหัสผ่าน" ซึ่งมีการแก้ไขรหัสผ่าน
42 /// </สรุป>
43 /// <param name="sender"></param>
44 /// <ชื่อพารามิเตอร์ = "e" ></ พารามิเตอร์>
45 โมฆะส่วนตัว btnModifyPwd_Click (ผู้ส่งวัตถุ System.EventArgs e)
46 {
47 สตริง strUserID = txtLoginID.Text;
48 ถ้า (strUserID == String.Empty)
49 {
50 controlMessage.InnerHtml = "ชื่อผู้ใช้ไม่สามารถเว้นว่างได้";
51 กลับ;
52 }
53
54 //ตรวจสอบว่าอินพุตรหัสผ่านทั้งสองเหมือนกันหรือไม่
55 ถ้า( txtNewPassword.Text != txtConfirmPassword.Text )
56 {
57 controlMessage.InnerHtml = "รหัสผ่านที่ป้อนสองครั้งไม่สอดคล้องกัน โปรดป้อนใหม่";
58 กลับ;
59 }
60
61 IniFile ini = ใหม่ IniFile( _strServUDaemonPath );
62 สตริง strSectionValue = "USER=" + strUserID.Trim() + "|1";
63
64 //ตรวจสอบว่ามีผู้ใช้อยู่หรือไม่โดยการอ่าน HomeDir ของผู้ใช้ที่ระบุ
65 ถ้า( ini.ReadString( strSectionValue, "HomeDir", "" ) == "" )
66 {
67 controlMessage.InnerHtml = "ไม่มีผู้ใช้ที่ระบุ";
68 กลับ;
69 }
70
71 //เริ่มตรวจสอบว่ารหัสผ่านถูกต้องหรือไม่
72 สตริง strPassword = ini.ReadString( strSectionValue, "รหัสผ่าน", "" );
73
74 สตริง strPasswordFrontTwoChars;
75 บูล bPasswordRight = เท็จ;
76 ถ้า(strPassword.Length > 2)
77 {
78 // อ่านตัวอักษรสุ่มที่มีอยู่ในรหัสผ่าน
79 strPasswordFrontTwoChars = strPassword.Substring(0, 2);
80 ถ้า( CreateCryPassword( strPasswordFrontTwoChars, txtOldPassword.Text ) == strPassword )
81 {//รหัสผ่านตรงกัน
82 bPasswordRight = จริง;
83}
84 อื่น ๆ
85 {//รหัสผ่านไม่ตรงกัน
86 bPasswordRight = เท็จ;
87 }
88}
89 อื่น ๆ ถ้า ( strPassword == txtOldPassword.Text) // รหัสผ่านเดิมว่างเปล่า
90 {
91 bPasswordRight = จริง;
92 }
93 อื่น ๆ
94 {
95 bPasswordRight = เท็จ;
96 }
97
98 ถ้า( bPasswordRight )
99 {
100 //รหัสผ่านถูกต้อง เขียนรหัสผ่านใหม่ และตั้งค่าให้โหลดการตั้งค่าใหม่โดยอัตโนมัติ เพื่อให้ยังคงใช้ได้ในครั้งต่อไปที่มีการเปลี่ยนแปลง
101 ini.WriteString( strSectionValue, "รหัสผ่าน", CreateCryPassword( GetRandomString(), txtNewPassword.Text ) );
102 controlMessage.InnerHtml = "เปลี่ยนรหัสผ่านเสร็จสมบูรณ์";
103}
104 อื่น ๆ
105 {
106 controlMessage.InnerHtml = "รหัสผ่านเดิมไม่ถูกต้อง";
107 }
108
109 }
ตัวแปร _strServUDaemonPath ในโค้ดข้างต้นใช้เพื่อบันทึกเส้นทางที่มีไฟล์ ServUDaemon.ini สามารถรับค่านี้ได้ผ่านการตั้งค่า Web.Config ในเหตุการณ์ PageLoad
แต่มันไม่ได้จบเพียงแค่นั้น หลังจากการทดสอบพบว่ามีปัญหาร้ายแรง: หลังจากเปลี่ยนรหัสผ่านแล้ว เพียงรีสตาร์ท Serv-U เท่านั้นที่จะมีผลกับรหัสผ่านที่เปลี่ยน นั่นไม่ได้หมายความว่ามันไม่มีประโยชน์ใช่ไหม ผู้ดูแลระบบไม่สามารถรีสตาร์ทเซิร์ฟเวอร์เพื่อให้การเปลี่ยนรหัสผ่านมีผลได้เสมอไป
เมื่อกลับมาที่ฐานความรู้อย่างเป็นทางการของ Serv-U อีกครั้ง ฉันพบเนื้อหาดังต่อไปนี้:
การอัพเดตไฟล์ ServUDaemon.ini ด้วยตนเอง
เมื่อใดก็ตามที่มีการเปลี่ยนแปลงไฟล์ ServUDaemon.ini โดยตรง ให้เพิ่มบรรทัดต่อไปนี้ใต้พื้นที่ส่วนกลางในไฟล์ INI
ReloadSettings=True
Serv-U จะตรวจสอบไฟล์ INI สำหรับการตั้งค่านี้เป็นประจำ หากมีอยู่ Serv-U จะรีเฟรช การตั้งค่าที่เก็บไว้ทั้งหมดสำหรับทุกโดเมนบนเซิร์ฟเวอร์ ซึ่งจะทำให้ Serv-U รับรู้การเปลี่ยนแปลงโดยไม่ต้องรีสตาร์ท
หลังจากที่ Serv-U โหลดการเปลี่ยนแปลงแล้ว ระบบจะลบรายการ "ReloadSettings=True" ซึ่งจะช่วยให้คุณสามารถป้อนอีกครั้งได้ ครั้งถัดไปที่มีการเปลี่ยนแปลงใดๆ
กล่าวอีกนัยหนึ่ง ตราบใดที่คุณเพิ่มคีย์ ReloadSettings ในส่วน GLOBAL ของไฟล์ INI และตั้งค่าเป็น True คุณสามารถอัปเดตรหัสผ่านได้โดยอัตโนมัติหลังจากเปลี่ยนรหัสผ่าน เพียงแก้ไขโค้ดต้นฉบับและแทรกโค้ดต่อไปนี้ระหว่างบรรทัด 101 ถึง 102:
ini.WriteString( "GLOBAL", "ReloadSettings", "True" );
ณ จุดนี้ หน้าเว็บสำหรับเปลี่ยนรหัสผ่าน Serv-U ออนไลน์เสร็จสมบูรณ์แล้ว
IniFile ในโปรแกรมเป็นคลาสที่สรุปการทำงานของ API บนไฟล์ INI เพียงแต่ต้องใช้การอ่านและการเขียนสตริงเท่านั้น