แปลง String เป็น SecureString


คำตอบ:


138

คุณไม่ทำ เหตุผลทั้งหมดในการใช้อ็อบเจ็กต์ SecureString คือการหลีกเลี่ยงการสร้างอ็อบเจ็กต์สตริง (ซึ่งโหลดลงในหน่วยความจำและเก็บไว้ในข้อความธรรมดาจนกว่าจะรวบรวมขยะ) อย่างไรก็ตามคุณสามารถเพิ่มอักขระใน SecureString ได้โดยการต่อท้าย

var s = new SecureString();
s.AppendChar('d');
s.AppendChar('u');
s.AppendChar('m');
s.AppendChar('b');
s.AppendChar('p');
s.AppendChar('a');
s.AppendChar('s');
s.AppendChar('s');
s.AppendChar('w');
s.AppendChar('d');

13
"การรวมกันคือ12345... นั่นคือสิ่งที่คนโง่มีอยู่ในกระเป๋าของเขา!"
Kolob Canyon

8
ทั้งหมดที่ฉันเห็นคือ*****
Ian Boyd

AppendCharไม่ดำเนินการจนกว่าจะถึงเวลารันดังนั้นอักขระเหล่านั้นยังสามารถอ่านได้จาก IL ถูกต้องหรือไม่? บางทีการสับสนในเวลาคอมไพล์อาจช่วยได้เช่นกัน ... นั่นคือถ้าคุณเข้ารหัสรหัสผ่านยาก
samis

5
นั่นเป็นข้อโต้แย้งที่ง่อย คุณได้รับรหัสผ่านจากที่ไหน? จากแบบฟอร์มหรือจากบรรทัดคำสั่ง จนกว่าพวกเขาจะสร้างวิธีการอ่านสตริงที่ปลอดภัยโดยตรงจากอุปกรณ์หรืออาร์กิวเมนต์บรรทัดคำสั่งเราจะต้องแปลงสตริงเป็น SecureString
Quarkly

1
@DonaldAirey คุณได้รับรหัสผ่านจากผู้จัดการความลับ โดยทั่วไปความลับที่เรากำลังพูดถึงนี้ไม่ใช่รหัสผ่านของผู้ใช้ แต่เป็นสิ่งที่อาจนำไปสู่การเพิ่มสิทธิ์หรือข้อมูลรั่วไหล นั่นหมายความว่ารหัสผ่านมีไว้สำหรับบริการอื่น ๆ และไม่ควรส่งผ่านบรรทัดคำสั่งหรือในช่องทางเครือข่ายที่ชัดเจน
Barry Kelly

161

นอกจากนี้ยังมีวิธีการแปลงระหว่างอื่นและSecureStringString

1. สตริงเป็น SecureString

SecureString theSecureString = new NetworkCredential("", "myPass").SecurePassword;

2. SecureString เป็น String

string theString = new NetworkCredential("", theSecureString).Password;

ที่นี่คือ ลิงค์


4
นี่เป็นทางออกที่ดีที่สุดสำหรับกรณีการใช้งานที่พบบ่อยที่สุด!
Dan Bechard

17
ไม่มีประเด็นในการใช้SecureStringif รหัสของคุณสร้างstringวัตถุด้วยค่าที่คุณต้องการรักษาความปลอดภัย เป้าหมายSecureStringคือการหลีกเลี่ยงการมีสตริงในหน่วยความจำที่มีการจัดการดังนั้นผู้โจมตีที่ตรวจสอบหน่วยความจำนั้นสามารถมองเห็นค่าที่คุณต้องการซ่อนได้ เนื่องจากตัวNetworkCredentialสร้างที่คุณเรียกใช้ต้องใช้สตริงจึงไม่ใช่วิธีที่จะไป ... แน่นอนว่ารหัสของคุณเป็นวิธีที่ง่ายในการแปลงไปยังและกลับจาก SecureString แต่การใช้งานจะทำให้รหัสของคุณปลอดภัยเท่ากับการใช้งานง่ายstring
Gian Paolo

15
@GianPaolo แม้ว่าจะถูกต้องในทางทฤษฎี แต่ในทางปฏิบัติเรายังคงต้องใช้SecureStringเมื่อทำงานกับห้องสมุดบางแห่ง และขอบอกตามตรงว่าหากมีคนกำลังสแกนหน่วยความจำของแอปพลิเคชันของคุณแสดงว่าคุณทำหายไปแล้ว แม้ว่าคุณจะใช้ SecureString อย่างถูกต้องซึ่งฉันไม่เคยเห็นมาก่อน แต่ก็มีข้อมูลที่มีค่าอื่น ๆ ให้ดึงออกมา
Jonathan Allen

1
@JonathanAllen: คุณอาจจะพูดถูก แต่เป็นเพียงเพราะเรามีวัฒนธรรมในการรักษาความปลอดภัยเป็นหลัก หากคุณกำลังสร้างเว็บไซต์สูตรอาหารเกาหลีเหนือไม่น่าจะลองสแกนหน่วยความจำของโปรแกรมของคุณ หากคุณกำลังเขียนซอฟต์แวร์ด้านการธนาคารภัยคุกคามนั้นเป็นเรื่องจริงมากขึ้น
Eric J.

58

วิธีการด้านล่างช่วยในการแปลงสตริงเป็นสตริงที่ปลอดภัย

private SecureString ConvertToSecureString(string password)
{
    if (password == null)
        throw new ArgumentNullException("password");

    var securePassword = new SecureString();

    foreach (char c in password)
        securePassword.AppendChar(c);

    securePassword.MakeReadOnly();
    return securePassword;
}

26
+1 แต่โปรดทราบว่าการส่งรหัสผ่านเป็นพารามิเตอร์สตริงจะสร้างอินสแตนซ์สตริงที่ไม่ได้เข้ารหัสในหน่วยความจำที่มีการจัดการและเอาชนะวัตถุประสงค์ของ 'SecureString' ในตอนแรก เพียงแค่ชี้ให้เห็นสิ่งนี้สำหรับคนในอนาคตที่เข้ามาและใช้รหัสนี้
Cody

19
@Cody นั่นเป็นความจริงและเป็นจุดที่ดี แต่พวกเราหลายคนไม่สนใจว่า SecureString จะปลอดภัยหรือไม่และใช้เพียงเพราะ Microsoft API บางตัวต้องการให้เป็นพารามิเตอร์
Dan Bechard

3
@Cody ปรากฎว่าแม้แต่คลาส SecureString ก็ไม่สามารถเข้ารหัสสตริงได้ ซึ่งเป็นเหตุผลที่ MS กำลังพิจารณา obsoleting ชนิดgithub.com/dotnet/platform-compat/blob/master/docs/DE0001.md
Martin Brown


11

นี่คือเคล็ดลับ linq ราคาถูก

            SecureString sec = new SecureString();
            string pwd = "abc123"; /* Not Secure! */
            pwd.ToCharArray().ToList().ForEach(sec.AppendChar);
            /* and now : seal the deal */
            sec.MakeReadOnly();

32
คำตอบนี้คือแบบฝึกหัดคือการดูว่าสามารถสร้างสำเนาชั่วคราวของข้อความธรรมดาได้กี่ชุดในหนึ่งช็อต
Mike Caron

1
ตามที่ @ john-dagg แนะนำแนวคิดคืออย่าตั้งค่าสตริงด้วยรหัสผ่านของคุณเพราะถ้าคุณทำจะไม่มีข้อได้เปรียบที่จะใช้ Securestring ในกรณีของคุณคุณได้ใส่รหัสผ่านเป็นข้อความธรรมดาคุณจะไม่ปลอดภัยอะไรเลยในภายหลังโดยใช้สายรัดที่ปลอดภัย ฉันหวังว่าคุณจะเข้าใจว่า securestring มีไว้เพื่อป้องกันสตริงของคุณจากคนที่กำลังมองหาการถอดชิ้นส่วนหรือตัวดีบั๊กดังนั้นดูว่ามีอะไรอยู่ใน IL / หน่วยความจำ
user734028

8

ฉันจะโยนสิ่งนี้ออกไป ทำไม?

คุณไม่สามารถเปลี่ยนสตริงทั้งหมดของคุณเพื่อรักษาความปลอดภัยสตริงและทันใดนั้นแอปพลิเคชันของคุณก็ "ปลอดภัย" สตริงที่ปลอดภัยได้รับการออกแบบมาเพื่อให้สตริงเข้ารหัสให้นานที่สุดเท่าที่จะเป็นไปได้และจะถูกถอดรหัสในช่วงเวลาสั้น ๆ เท่านั้นโดยจะเช็ดหน่วยความจำหลังจากดำเนินการไปแล้ว

ฉันจะบอกว่าคุณอาจมีปัญหาระดับการออกแบบที่ต้องจัดการก่อนที่จะกังวลเกี่ยวกับการรักษาความปลอดภัยสตริงแอปพลิเคชันของคุณ ให้ข้อมูลเพิ่มเติมเกี่ยวกับสิ่งที่คุณพยายามทำและเราอาจช่วยได้ดีขึ้น


1
ฉันแค่ต้องการใช้มันเพื่อตั้งรหัสผ่านสำหรับ ProcessStartInfo และเรียกใช้ exe ของฉันเป็นผู้ใช้อื่น .. ที่ได้ผลสำหรับฉัน ...
Developer404

4
แอปพลิเคชันของฉันได้รับการรักษาความปลอดภัยโดยใช้งานบนระบบที่ปลอดภัย ฉันไม่สนใจเลยว่าสายอักขระนี้จะถูกเข้ารหัสในหน่วยความจำ มีข้อมูลที่สำคัญมากขึ้นในระบบนี้ที่ต้องกังวลว่ามันจะถูกบุกรุกหรือไม่ SecureString จำเป็นต้องใช้โดย Microsoft API ที่โปรแกรมของฉันต้องใช้ โดยนัยว่านักพัฒนาจะพิจารณากรณีการใช้งานของตนเองและพิจารณาว่าการแปลงสตริงเป็น SecureStrings เป็นการดำเนินการที่ถูกต้องในบริบทหรือไม่
Dan Bechard

ดังนั้นวิธีนี้จะไม่ป้องกันไม่ให้ใครเห็นรหัสผ่านหากเขาใช้ตัวถอดรหัสเช่น DotPeek? มีวิธีซ่อนสตริงในกรณีนี้หรือไม่?
ปกครอง

มีสองสามวิธีขึ้นอยู่กับภัยคุกคามที่คุณพยายามเอาชนะ หากเป็นการปกป้องข้อมูลผู้ใช้จากใครก็ตามยกเว้นผู้ดูแลระบบภายในคุณสามารถใช้วิธี DPAPI บน windows เพื่อเข้ารหัสไฟล์และเก็บความลับไว้ที่นั่นอ่านเป็นสตริงที่ปลอดภัยแล้วทิ้งไป หากเป็นความลับของ บริษัท คำตอบสั้น ๆ ก็คือหากแอปพลิเคชันของคุณสามารถถอดรหัสได้ผู้ใช้ก็สามารถทำได้ในที่สุด
Spence


5

ไม่มี linq แฟนซีไม่ได้เพิ่มตัวอักษรทั้งหมดด้วยมือเพียงธรรมดาและเรียบง่าย:

var str = "foo";
var sc = new SecureString();
foreach(char c in str) sc.appendChar(c);

แม้แต่คนที่ชอบเล่นไม่จำเป็นต้องกำหนดตัวแปร
bigworld12

นี่คือซับเดียว:var sc = new SecureString(); foreach(char c in "foo") sc.appendChar(c);
bigworld12

4

ฉันเห็นด้วยกับ Spence (+1) แต่ถ้าคุณทำเพื่อการเรียนรู้หรือทดสอบการเทคุณสามารถใช้ foreach ในสตริงโดยต่อท้ายอักขระแต่ละตัวเข้ากับสตริงที่ปลอดภัยโดยใช้เมธอด AppendChar


3

ฉันแค่อยากจะชี้ให้ทุกคนเห็นว่า "นั่นไม่ใช่ประเด็นSecureString" ซึ่งหลาย ๆ คนที่ถามคำถามนี้อาจอยู่ในแอปพลิเคชันที่ไม่ว่าด้วยเหตุผลใดจะเป็นธรรมหรือไม่ก็ตามพวกเขาไม่ได้กังวลเป็นพิเศษเกี่ยวกับการมี สำเนาชั่วคราวของรหัสผ่านจะอยู่บนฮีปเป็นสตริงที่รองรับ GC แต่ต้องใช้ API ที่ยอมรับเฉพาะอSecureStringอบเจ็กต์ ดังนั้นคุณมีแอปที่คุณไม่สนใจไม่ว่ารหัสผ่านจะอยู่ในฮีปหรือไม่อาจเป็นรหัสผ่านสำหรับใช้งานภายในเท่านั้นและรหัสผ่านจะอยู่ที่นั่นเพียงเพราะต้องการโดยโปรโตคอลเครือข่ายพื้นฐานและคุณพบว่าไม่สามารถใช้สตริงนั้นที่เก็บรหัสผ่านเพื่อตั้งค่า PowerShell ระยะไกลได้ Runspace - แต่ไม่มีอะไรง่ายตรงไปตรงมาหนึ่งซับในการสร้างสิ่งSecureStringที่คุณต้องการ มันเป็นความไม่สะดวกเล็ก ๆ น้อย ๆ - แต่อาจจะคุ้มค่าที่จะให้แน่ใจว่าการใช้งานที่จริงๆทำต้องSecureStringไม่ล่อใจผู้เขียนจะใช้System.StringหรือSystem.Char[]ตัวกลาง :-)


2

หากคุณต้องการบีบอัดการแปลงstringa SecureStringเป็นLINQคำสั่งคุณสามารถแสดงได้ดังนี้:

var plain  = "The quick brown fox jumps over the lazy dog";
var secure = plain
             .ToCharArray()
             .Aggregate( new SecureString()
                       , (s, c) => { s.AppendChar(c); return s; }
                       , (s)    => { s.MakeReadOnly(); return s; }
                       );

อย่างไรก็ตามโปรดทราบว่าการใช้LINQไม่ได้ช่วยเพิ่มความปลอดภัยของโซลูชันนี้ มันทนทุกข์ทรมานจากข้อบกพร่องเช่นเดียวกับการแปลงใด ๆ จากการstring SecureStringตราบเท่าที่ต้นฉบับstringยังคงอยู่ในหน่วยความจำข้อมูลก็มีช่องโหว่

ดังที่กล่าวไว้สิ่งที่ข้อความข้างต้นสามารถนำเสนอได้คือการรวบรวมการสร้างการSecureStringเริ่มต้นด้วยข้อมูลและในที่สุดก็ล็อคไม่ให้แก้ไข


2

2 ส่วนขยายต่อไปนี้ควรทำเคล็ดลับ:

  1. สำหรับcharอาร์เรย์

    public static SecureString ToSecureString(this char[] _self)
    {
        SecureString knox = new SecureString();
        foreach (char c in _self)
        {
            knox.AppendChar(c);
        }
        return knox;
    }
  2. และสำหรับ string

    public static SecureString ToSecureString(this string _self)
    {
        SecureString knox = new SecureString();
        char[] chars = _self.ToCharArray();
        foreach (char c in chars)
        {
            knox.AppendChar(c);
        }
        return knox;
    }

ขอบคุณJohn DaggสำหรับAppendCharคำแนะนำ


0

คุณสามารถใช้สคริปต์ง่ายๆนี้

private SecureString SecureStringConverter(string pass)
{
    SecureString ret = new SecureString();

    foreach (char chr in pass.ToCharArray())
        ret.AppendChar(chr);

    return ret;
}

1
คำตอบนี้ถูกโพสต์ 15 เดือนที่ผ่านมา ไม่จำเป็นต้องโพสต์อีกครั้ง
GSerg
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.