Chuyển đổi chuỗi thành SecureString


Câu trả lời:


137

Bạn không. Toàn bộ lý do để sử dụng đối tượng SecureString là để tránh tạo một đối tượng chuỗi (được tải vào bộ nhớ và giữ ở đó trong bản rõ cho đến khi thu gom rác). Tuy nhiên, bạn có thể thêm các ký tự vào SecureString bằng cách nối thêm chúng.

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
"Sự kết hợp là 12345... đó là thứ mà một thằng ngốc có trong hành lý của mình!"
Hẻm núi Kolob

8
Tất cả những gì tôi thấy là*****
Ian Boyd

AppendCharkhông thực thi cho đến khi chạy, vì vậy những ký tự đó vẫn có thể được đọc từ IL, đúng không? Có lẽ một số obfuscation thời gian biên dịch cũng sẽ giúp ... đó là, nếu bạn là mật khẩu mã hóa cứng.
samis

5
Đó là một lập luận khập khiễng. Bạn lấy mật khẩu ở đâu? Từ một hình thức hoặc từ một dòng lệnh. Cho đến khi họ tạo ra một phương thức để đọc một chuỗi bảo mật trực tiếp từ một đối số dòng thiết bị hoặc dòng lệnh, chúng ta sẽ cần chuyển đổi một chuỗi thành SecureString.
Quarkly

1
@DonaldAirey bạn nhận được mật khẩu từ người quản lý bí mật. Nói chung, những bí mật chúng ta đang nói ở đây không phải là mật khẩu người dùng, mà là những thứ có khả năng dẫn đến sự leo thang đặc quyền hoặc rò rỉ dữ liệu. Điều đó có nghĩa là mật khẩu dành cho các dịch vụ khác và không được truyền vào các dòng lệnh hoặc trong các kênh mạng rõ ràng.
Barry Kelly

159

Cũng có một cách khác để chuyển đổi giữa SecureStringString.

1. Chuỗi để SecureString

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

2. SecureString to String

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

Đây là liên kết


3
Đây là giải pháp tốt nhất cho đến nay cho trường hợp sử dụng phổ biến nhất!
Dan Bechard

16
Không có điểm nào trong việc sử dụng SecureStringnếu mã của bạn tạo một stringđối tượng với giá trị bạn muốn bảo mật. Mục tiêu của việc SecureStringtránh để có chuỗi trong bộ nhớ được quản lý, vì vậy kẻ tấn công kiểm tra bộ nhớ đó có thể phát hiện ra giá trị bạn muốn ẩn. Vì hàm NetworkCredentialtạo mà bạn đang gọi yêu cầu một chuỗi, đó không phải là cách để đi ... Chắc chắn, mã của bạn là một cách dễ dàng để chuyển đổi sang và từ SecureString, nhưng sử dụng nó giúp mã của bạn an toàn như sử dụng một cách đơn giảnstring
Gian Paolo

14
@GianPaolo trong khi đó là chính xác trong lý thuyết, trong thực tế chúng ta vẫn cần sử dụng SecureStringkhi làm việc với một số thư viện. Và hãy trung thực ở đây, nếu ai đó đang tích cực quét bộ nhớ ứng dụng của bạn thì bạn đã bị mất. Ngay cả khi bạn đã sử dụng SecureString một cách chính xác, điều mà tôi chưa từng thấy, sẽ có một dữ liệu có giá trị khác để trích xuất.
Jonathan Allen

1
@Jonathan ALLen: Có lẽ bạn đúng, nhưng chỉ vì chúng tôi có văn hóa coi an ninh là một suy nghĩ sau. Nếu bạn đang tạo một trang web công thức, Triều Tiên không có khả năng thử quét bộ nhớ chương trình của bạn. Nếu bạn đang viết phần mềm ngân hàng, mối đe dọa thực tế hơn nhiều.
Eric J.

58

Phương pháp dưới đây giúp chuyển đổi chuỗi thành chuỗi an toàn

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, nhưng lưu ý rằng việc truyền mật khẩu dưới dạng tham số chuỗi sẽ tạo ra một thể hiện chuỗi không được mã hóa trong bộ nhớ được quản lý và đánh bại mục đích của 'SecureString' ở vị trí đầu tiên. Chỉ cần chỉ ra điều này cho những người trong tương lai đến và sử dụng mã này.
Cody

19
@Cody Điều đó đúng và là một điểm tốt, nhưng nhiều người trong chúng ta không quan tâm liệu SecureString có an toàn hay không và chỉ sử dụng nó vì một số Microsoft API yêu cầu nó làm tham số.
Dan Bechard

3
@Cody Hóa ra ngay cả lớp SecureString cũng không thể giữ chuỗi được mã hóa. Đó là lý do tại sao MS đang xem xét việc lỗi thời loại github.com/dotnet/pl platform-compat/blob/master/docs/DE0001.md .
Martin Brown

19

Bạn có thể làm theo điều này:

string password = "test";
SecureString sec_pass = new SecureString();
Array.ForEach(password.ToArray(), sec_pass.AppendChar);
sec_pass.MakeReadOnly();

11

Đây là một mẹo linq giá rẻ.

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

32
Câu trả lời này là một bài tập đang xem có thể tạo ra bao nhiêu bản sao tạm thời của văn bản đơn giản trong một lần chụp
Mike Caron

1
như @ john-dagg đề xuất ý tưởng là KHÔNG đặt chuỗi bằng mật khẩu của bạn bởi vì nếu bạn làm như vậy thì không còn lợi thế nào để sử dụng bảo mật. Trong trường hợp của bạn, bạn đã đặt mật khẩu bằng văn bản thuần túy, bạn sẽ không bảo mật được gì sau này bằng cách sử dụng bảo mật. Tôi hy vọng bạn hiểu rằng việc bảo mật có nghĩa là bảo mật chuỗi của bạn khỏi những người đang xem phần tháo gỡ hoặc trình gỡ lỗi để xem những gì trong IL / bộ nhớ.
dùng734028

8

Tôi sẽ ném cái này ra khỏi đó. Tại sao?

Bạn không thể thay đổi tất cả các chuỗi của mình thành các chuỗi bảo mật và đột nhiên ứng dụng của bạn "an toàn". Chuỗi bảo mật được thiết kế để giữ cho chuỗi được mã hóa càng lâu càng tốt và chỉ được giải mã trong một khoảng thời gian rất ngắn, xóa sạch bộ nhớ sau khi một thao tác được thực hiện trên nó.

Tôi sẽ nguy hiểm khi nói rằng bạn có thể có một số vấn đề ở cấp thiết kế để giải quyết trước khi lo lắng về việc bảo mật chuỗi ứng dụng của bạn. Cung cấp cho chúng tôi thêm một số thông tin về những gì bạn đang cố gắng làm và chúng tôi có thể giúp đỡ tốt hơn.


1
Tôi chỉ muốn sử dụng nó để đặt mật khẩu cho ProcessStartInfo và chạy exe của tôi với tư cách là người dùng khác .. Điều đó hiệu quả với tôi ...
Developer404

4
Ứng dụng của tôi được bảo mật bằng cách chạy nó trên một hệ thống an toàn. Tôi không thể quan tâm ít hơn về chuỗi đặc biệt này được mã hóa trong bộ nhớ. Có rất nhiều thông tin quan trọng trên hệ thống này để lo lắng về việc liệu nó có bị xâm phạm hay không. SecureString được yêu cầu đơn giản bởi Microsoft API mà chương trình của tôi cần sử dụng. Nó được ngụ ý rằng nhà phát triển xem xét trường hợp sử dụng của chính mình và xác định xem việc chuyển đổi Chuỗi thành SecureStrings có phải là một hoạt động hợp lệ trong ngữ cảnh hay không.
Dan Bechard

Vì vậy, phương pháp này sẽ không ngăn ai đó xem mật khẩu nếu anh ta sử dụng trình dịch ngược như DotPeek? Có cách nào để ẩn chuỗi trong trường hợp này?
M.Parent

Có một vài phương pháp, tùy thuộc vào mối đe dọa mà bạn đang cố gắng đánh bại. Nếu đó là để bảo vệ thông tin người dùng khỏi bất kỳ ai trừ quản trị viên cục bộ, bạn có thể sử dụng các phương thức DPAPI trên windows để mã hóa tệp và lưu trữ bí mật ở đó, đọc nó thành một chuỗi bảo mật và sau đó ném nó đi. Nếu đó là một bí mật của công ty, thì câu trả lời ngắn gọn là liệu ứng dụng của bạn có thể giải mã được nó hay không, cuối cùng thì người dùng cũng có thể.
Spence

6
unsafe 
{
    fixed(char* psz = password)
        return new SecureString(psz, password.Length);
}

5

không có linq ưa thích, không thêm tất cả các ký tự bằng tay, chỉ đơn giản và đơn giản:

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

thậm chí fancier, không cần xác định một biến
bigworld12

đây là một lớp lót:var sc = new SecureString(); foreach(char c in "foo") sc.appendChar(c);
bigworld12

4

Tôi đồng ý với Spence (+1), nhưng nếu bạn đang làm điều đó để học hoặc kiểm tra các mục đích, bạn có thể sử dụng một lời nói trong chuỗi, nối thêm mỗi char vào cách bảo mật bằng phương thức AppendChar.


3

Tôi chỉ muốn chỉ ra cho tất cả mọi người nói, "Đó không phải là vấn đề SecureString", rằng nhiều người hỏi câu hỏi này có thể nằm trong một ứng dụng, vì lý do nào, có lý do hay không, họ không đặc biệt quan tâm đến việc có một bản sao tạm thời của mật khẩu nằm trên heap dưới dạng chuỗi có khả năng GC, nhưng chúng phải sử dụng API chỉ chấp nhận SecureStringcác đối tượng. Vì vậy, bạn có một ứng dụng mà bạn không quan tâmcho dù mật khẩu có ở trên heap hay không, có thể đó chỉ là sử dụng nội bộ và mật khẩu chỉ ở đó vì nó được yêu cầu bởi các giao thức mạng cơ bản và bạn thấy rằng chuỗi đó lưu trữ mật khẩu không thể được sử dụng để thiết lập PowerShell từ xa Runspace - nhưng không có một lớp lót đơn giản, dễ dàng để tạo raSecureStringđó là điều bạn cần. Đó là một sự bất tiện nhỏ - nhưng có lẽ giá trị của nó để đảm bảo rằng các ứng dụng thực sự làm cần SecureStringkhông điều kiện nhiệt độ các tác giả để sử dụng System.Stringhoặc System.Char[]trung gian. :-)


2

Nếu bạn muốn nén chuyển đổi từ a stringthành a SecureStringthành một LINQcâu lệnh, bạn có thể diễn đạt nó như sau:

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; }
                       );

Tuy nhiên, hãy nhớ rằng việc sử dụng LINQkhông cải thiện tính bảo mật của giải pháp này. Nó bị lỗ hổng giống như bất kỳ chuyển đổi từ stringsang SecureString. Miễn là bản gốc stringvẫn còn trong bộ nhớ, dữ liệu dễ bị tổn thương.

Điều đó đang được nói, những gì tuyên bố trên có thể cung cấp là kết hợp việc tạo ra SecureString, khởi tạo của nó với dữ liệu và cuối cùng khóa nó khỏi sửa đổi.


2

2 phần mở rộng sau đây nên thực hiện thủ thuật:

  1. Đối với một charmảng

    public static SecureString ToSecureString(this char[] _self)
    {
        SecureString knox = new SecureString();
        foreach (char c in _self)
        {
            knox.AppendChar(c);
        }
        return knox;
    }
  2. Va cho 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;
    }

Cảm ơn John Dagg cho lời AppendChargiới thiệu.


0

bạn có thể sử dụng tập lệnh đơn giản này

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

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

    return ret;
}

1
Câu trả lời này đã được đăng 15 tháng trước . Thực sự không cần phải đăng lại.
GSerg
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.