-
Notifications
You must be signed in to change notification settings - Fork 1.2k
User SecureString for Basic and Proxy passwords #3806
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
This commit changes the BasicAuthenticationCredentials and ProxyPassword types to use SecureString for holding the passwords in memory, as opposed to as a plain text string. A plain text string is retrieved from SecureString only at the point at which it is required. This prevents plain text passwords from being automatically emitted in cases where properties may be enumerated and captured e.g. logging frameworks.
Return of SecureString 🍰 we left it out for a reason for a long time no less because the https://github.com/dotnet/platform-compat/blob/master/docs/DE0001.md was always a reason for us not to implement it.
Is reason enough to add it in though 👍 |
In some cases the createstring method returns a value that looks like chinese instead of the original string. I still have to investigate why. Is this a known issue? I think it is a threading issue. Secure string does not seem thread safe, it encrypts and decrypts the buffer in place on Read actions without a lock. Elasticclient is now no longer threadsafe, which does not comply to the docs |
@RolfDeVries could you provide more detail about
There should be just a single instance of elasticsearch-net/src/Elasticsearch.Net/Connection/SecureStrings.cs Lines 15 to 33 in 0584f8d
which allocates an unmanaged binary string each time and copies the contents of |
A quick test with var secureString = "password".CreateSecureString();
var count = 10000;
var tasks = new List<Task<string>>(count);
for (int i = 0; i < count; i++)
tasks.Add(new Task<string>(() =>
{
var s = secureString.CreateString();
Console.WriteLine(s);
return s;
}));
tasks.ForEach(t => t.Start());
Task.WaitAll(tasks.ToArray()); returns the expected results, but I may be missing something. |
When i use 4 parallel thread to read the password 1000 times it will fail: using System; namespace SecureStringTest
} Running on .net core 2.2 windows server 2016 with 6 virtual processors. |
Thanks @RolfDeVries, can replicate on .NET Core 2.2. |
Looks to be related to public static string CreateString(this System.Security.SecureString secureString)
{
var num = IntPtr.Zero;
if (secureString != null && secureString.Length != 0)
{
try
{
num = Marshal.SecureStringToGlobalAllocUnicode(secureString);
return Marshal.PtrToStringUni(num);
}
finally
{
if (num != IntPtr.Zero)
Marshal.ZeroFreeGlobalAllocUnicode(num);
}
}
return string.Empty;
} |
Looks like its working |
Relates: #3806 (comment) This commit updates the SecureStrings implementation to use the cross platform Marshal methods that deal with unmanaged unicode strings. Implement IDisposable on BasicAuthenticationCredentials and dispose of SecureString instances when ConnectionConfiguration is disposed.
@RolfDeVries I've opened #3825 to address |
Thanks very much for the quick response! |
* Use Marshal.SecureStringToGlobalAllocUnicode Relates: #3806 (comment) This commit updates the SecureStrings implementation to use the cross platform Marshal methods that deal with unmanaged unicode strings. Implement IDisposable on BasicAuthenticationCredentials and dispose of SecureString instances when ConnectionConfiguration is disposed.
This commit changes the BasicAuthenticationCredentials and ProxyPassword types
to use SecureString for holding the passwords in memory, as opposed to as a plain text string.
A plain text string is retrieved from SecureString only at the point at which it is required.
This prevents plain text passwords from being automatically emitted in cases where properties
may be enumerated and captured e.g. logging frameworks.
Closes #2505