Вы должны использовать все ключевые слова async
и await
, или вы не должны использовать async вообще.
Второй вариант не является асинхронным. Он вызывает асинхронную операцию и блокирует ее синхронно с task.GetAwaiter().GetResult()
. Кроме того, что он очень сложный, он не является асинхронным и может привести к взаимоблокировкам.
Это должно вам помочь: Маршалинг паролей SecureString в строку
Ключевые моменты статьи:
Вот класс, который я написал специально для этой цели. Это полностью, 100% взломостойкий? Нет - вы можете сделать очень мало, чтобы сделать приложение на 100% безопасным, но этот класс идет настолько далеко, насколько вы можете защитить себя, если вам нужно преобразовать SecureString
в String
.
Вот как вы используете класс:
using(SecureStringToStringMarshaler sm = new SecureStringToStringMarshaler(secureString))
{
// Use sm.String here. While in the 'using' block, the string is accessible
// but pinned in memory. When the 'using' block terminates, the string is zeroed
// out for security, and garbage collected as usual.
}
Вот класс
/// Copyright (C) 2010 Douglas Day
/// All rights reserved.
/// MIT-licensed: http://www.opensource.org/licenses/mit-license.php
using System;
using System.Collections.Generic;
using System.Text;
using System.Security;
using System.Runtime.InteropServices;
using System.Runtime.CompilerServices;
namespace DDay.Base
{
public class SecureStringToStringMarshaler : IDisposable
{
#region Private Fields
private string _String;
private SecureString _SecureString;
private GCHandle _GCH;
#endregion
#region Public Properties
public SecureString SecureString
{
get { return _SecureString; }
set
{
_SecureString = value;
UpdateStringValue();
}
}
public string String
{
get { return _String; }
protected set { _String = value; }
}
#endregion
#region Constructors
public SecureStringToStringMarshaler()
{
}
public SecureStringToStringMarshaler(SecureString ss)
{
SecureString = ss;
}
#endregion
#region Private Methods
void UpdateStringValue()
{
Deallocate();
unsafe
{
if (SecureString != null)
{
int length = SecureString.Length;
String = new string('\0', length);
_GCH = new GCHandle();
// Create a CER (Contrained Execution Region)
RuntimeHelpers.PrepareConstrainedRegions();
try { }
finally
{
// Pin our string, disallowing the garbage collector from
// moving it around.
_GCH = GCHandle.Alloc(String, GCHandleType.Pinned);
}
IntPtr stringPtr = IntPtr.Zero;
RuntimeHelpers.ExecuteCodeWithGuaranteedCleanup(
delegate
{
// Create a CER (Contrained Execution Region)
RuntimeHelpers.PrepareConstrainedRegions();
try { }
finally
{
stringPtr = Marshal.SecureStringToBSTR(SecureString);
}
// Copy the SecureString content to our pinned string
char* pString = (char*)stringPtr;
char* pInsecureString = (char*)_GCH.AddrOfPinnedObject();
for (int index = 0; index < length; index++)
{
pInsecureString[index] = pString[index];
}
},
delegate
{
if (stringPtr != IntPtr.Zero)
{
// Free the SecureString BSTR that was generated
Marshal.ZeroFreeBSTR(stringPtr);
}
},
null);
}
}
}
void Deallocate()
{
if (_GCH.IsAllocated)
{
unsafe
{
// Determine the length of the string
int length = String.Length;
// Zero each character of the string.
char* pInsecureString = (char*)_GCH.AddrOfPinnedObject();
for (int index = 0; index < length; index++)
{
pInsecureString[index] = '\0';
}
// Free the handle so the garbage collector
// can dispose of it properly.
_GCH.Free();
}
}
}
#endregion
#region IDisposable Members
public void Dispose()
{
Deallocate();
}
#endregion
}
}
Этот код требует, чтобы вы могли скомпилировать unsafe
код, но он работает как талисман.
С уважением,
-Дуг
Ссылка, предоставленная Марком, - это лучшее, что вы можете сделать, и это подход, который моя команда использовала для решения этой проблемы (хотя мы не вдавались в сложность использования CER). Я немного сомневался в том, чтобы использовать пиннинг, чтобы существенно сломать неизменность C # String, но он работает.
SecureStrings безопасны только до тех пор, пока вы их не используете. ) -;
Единственное, что вам не следует делать - это копировать в строку (независимо от метода). Строка неизменна и потенциально может оставаться в памяти в течение длительного времени.
Копирование его в char [] немного безопаснее, если вы принимаете меры предосторожности и обнуляете этот массив как можно скорее. Но массив присутствует в памяти какое-то время, и это угроза безопасности (нарушение).
К сожалению, в библиотеке очень мало поддержки SecureStrings. Наиболее распространенный способ работы с ними - по одному символу за раз.
Изменить:
массив char []
должен быть закреплен, и Марк Байерс предоставляет ссылку на статью, делающую то же самое. вещь с закрепленной шнурком. Это' Это вопрос выбора, но риск строки состоит в том, что ее очень легко скопировать (достаточно передать ее какому-либо методу, выполняющему Trim ()
).
Используйте Marshal.ZeroFreeBSTR :
РЕДАКТИРОВАТЬ: Да, при создании новой строки будет создана копия, поэтому вы потеряете контроль над очисткой содержимого. Вы можете получить доступ к char [], преобразовав указатель, возвращаемый IntPtr.ToPointer () в небезопасный контекст:
IntPtr ptr = Marshal.SecureStringToBSTR(str);
unsafe
{
char *cp = (char*)ptr.ToPointer();
//access char[] through cp
}
Marshal.ZeroFreeBSTR(ptr);