如果我的假设是错误的,请随意纠正我,但让我解释为什么我问。
取自MSDN,一个SecureString:
表示应保密的文本。在使用时,文本会被加密以保护隐私,当不再需要时,会从计算机内存中删除。
我明白了,在系统上的SecureString中存储密码或其他私人信息是完全有意义的。字符串,因为您可以控制它实际存储在内存中的方式和时间,因为System。字符串:
is both immutable and, when no longer needed, cannot be programmatically scheduled for garbage collection; that is, the instance is read-only after it is created and it is not possible to predict when the instance will be deleted from computer memory. Consequently, if a String object contains sensitive information such as a password, credit card number, or personal data, there is a risk the information could be revealed after it is used because your application cannot delete the data from computer memory.
然而,对于GUI应用程序(例如ssh客户端),SecureString必须从System.String构建。所有文本控件都使用字符串作为其底层数据类型。
因此,这意味着每当用户按下一个键时,旧的字符串就会被丢弃,并构建一个新字符串来表示文本框内的值,即使使用密码掩码也是如此。我们无法控制何时或是否将这些值从内存中丢弃。
现在是时候登录到服务器了。你猜怎么着?您需要在连接上传递一个字符串进行身份验证。让我们把SecureString转换为System.String....现在我们在堆上有一个字符串,没有办法强制它进行垃圾收集(或将0写入缓冲区)。
我的观点是:无论你做什么,在某个地方,那个SecureString会被转换成一个系统。字符串,这意味着它至少在某个时候存在于堆上(没有任何垃圾收集的保证)。
我的观点不是:是否有方法可以避免向ssh连接发送字符串,或者避免让控件存储字符串(创建自定义控件)。对于这个问题,您可以将“ssh连接”替换为“登录表单”、“注册表单”、“支付表单”、“你要喂你的小狗但不是你的孩子的食物表单”等等。
So, at what point does using a SecureString actually become
practical?
Is it ever worth the extra development time to completely eradicate
the use of a System.String object?
Is the whole point of SecureString to simply reduce the amount of time a System.String is on the heap (reducing its risk of moving to a physical swap file)?
If an attacker already has the means for a heap inspection, then he most likely either (A) already has the means to read keystrokes, or (B) already physically has the machine... So would using a SecureString prevent him from getting to the data anyways?
Is this just "security through obscurity"?
如果我的问题问得太过分了,对不起,我只是被好奇心控制了。请随意回答我的任何或所有问题(或者告诉我我的假设是完全错误的)。:)
前段时间,我必须为java信用卡支付网关创建一个c#接口,其中需要一个兼容的安全通信密钥加密。由于Java实现相当特定,我必须以特定的方式处理受保护的数据。
我发现这个设计非常容易使用,比使用SecureString更容易…对于那些喜欢使用…感觉自由,没有法律限制:-)。注意,这些类是内部的,您可能需要将它们设为公共的。
namespace Cardinity.Infrastructure
{
using System.Security.Cryptography;
using System;
enum EncryptionMethods
{
None=0,
HMACSHA1,
HMACSHA256,
HMACSHA384,
HMACSHA512,
HMACMD5
}
internal class Protected
{
private Byte[] salt = Guid.NewGuid().ToByteArray();
protected byte[] Protect(byte[] data)
{
try
{
return ProtectedData.Protect(data, salt, DataProtectionScope.CurrentUser);
}
catch (CryptographicException)//no reason for hackers to know it failed
{
#if DEBUG
throw;
#else
return null;
#endif
}
}
protected byte[] Unprotect(byte[] data)
{
try
{
return ProtectedData.Unprotect(data, salt, DataProtectionScope.CurrentUser);
}
catch (CryptographicException)//no reason for hackers to know it failed
{
#if DEBUG
throw;
#else
return null;
#endif
}
}
}
internal class SecretKeySpec:Protected,IDisposable
{
readonly EncryptionMethods _method;
private byte[] _secretKey;
public SecretKeySpec(byte[] secretKey, EncryptionMethods encryptionMethod)
{
_secretKey = Protect(secretKey);
_method = encryptionMethod;
}
public EncryptionMethods Method => _method;
public byte[] SecretKey => Unprotect( _secretKey);
public void Dispose()
{
if (_secretKey == null)
return;
//overwrite array memory
for (int i = 0; i < _secretKey.Length; i++)
{
_secretKey[i] = 0;
}
//set-null
_secretKey = null;
}
~SecretKeySpec()
{
Dispose();
}
}
internal class Mac : Protected,IDisposable
{
byte[] rawHmac;
HMAC mac;
public Mac(SecretKeySpec key, string data)
{
switch (key.Method)
{
case EncryptionMethods.HMACMD5:
mac = new HMACMD5(key.SecretKey);
break;
case EncryptionMethods.HMACSHA512:
mac = new HMACSHA512(key.SecretKey);
break;
case EncryptionMethods.HMACSHA384:
mac = new HMACSHA384(key.SecretKey);
break;
case EncryptionMethods.HMACSHA256:
mac = new HMACSHA256(key.SecretKey);
break;
case EncryptionMethods.HMACSHA1:
mac = new HMACSHA1(key.SecretKey);
break;
default:
throw new NotSupportedException("not supported HMAC");
}
rawHmac = Protect( mac.ComputeHash(Cardinity.ENCODING.GetBytes(data)));
}
public string AsBase64()
{
return System.Convert.ToBase64String(Unprotect(rawHmac));
}
public void Dispose()
{
if (rawHmac != null)
{
//overwrite memory address
for (int i = 0; i < rawHmac.Length; i++)
{
rawHmac[i] = 0;
}
//release memory now
rawHmac = null;
}
mac?.Dispose();
mac = null;
}
~Mac()
{
Dispose();
}
}
}
前段时间,我必须为java信用卡支付网关创建一个c#接口,其中需要一个兼容的安全通信密钥加密。由于Java实现相当特定,我必须以特定的方式处理受保护的数据。
我发现这个设计非常容易使用,比使用SecureString更容易…对于那些喜欢使用…感觉自由,没有法律限制:-)。注意,这些类是内部的,您可能需要将它们设为公共的。
namespace Cardinity.Infrastructure
{
using System.Security.Cryptography;
using System;
enum EncryptionMethods
{
None=0,
HMACSHA1,
HMACSHA256,
HMACSHA384,
HMACSHA512,
HMACMD5
}
internal class Protected
{
private Byte[] salt = Guid.NewGuid().ToByteArray();
protected byte[] Protect(byte[] data)
{
try
{
return ProtectedData.Protect(data, salt, DataProtectionScope.CurrentUser);
}
catch (CryptographicException)//no reason for hackers to know it failed
{
#if DEBUG
throw;
#else
return null;
#endif
}
}
protected byte[] Unprotect(byte[] data)
{
try
{
return ProtectedData.Unprotect(data, salt, DataProtectionScope.CurrentUser);
}
catch (CryptographicException)//no reason for hackers to know it failed
{
#if DEBUG
throw;
#else
return null;
#endif
}
}
}
internal class SecretKeySpec:Protected,IDisposable
{
readonly EncryptionMethods _method;
private byte[] _secretKey;
public SecretKeySpec(byte[] secretKey, EncryptionMethods encryptionMethod)
{
_secretKey = Protect(secretKey);
_method = encryptionMethod;
}
public EncryptionMethods Method => _method;
public byte[] SecretKey => Unprotect( _secretKey);
public void Dispose()
{
if (_secretKey == null)
return;
//overwrite array memory
for (int i = 0; i < _secretKey.Length; i++)
{
_secretKey[i] = 0;
}
//set-null
_secretKey = null;
}
~SecretKeySpec()
{
Dispose();
}
}
internal class Mac : Protected,IDisposable
{
byte[] rawHmac;
HMAC mac;
public Mac(SecretKeySpec key, string data)
{
switch (key.Method)
{
case EncryptionMethods.HMACMD5:
mac = new HMACMD5(key.SecretKey);
break;
case EncryptionMethods.HMACSHA512:
mac = new HMACSHA512(key.SecretKey);
break;
case EncryptionMethods.HMACSHA384:
mac = new HMACSHA384(key.SecretKey);
break;
case EncryptionMethods.HMACSHA256:
mac = new HMACSHA256(key.SecretKey);
break;
case EncryptionMethods.HMACSHA1:
mac = new HMACSHA1(key.SecretKey);
break;
default:
throw new NotSupportedException("not supported HMAC");
}
rawHmac = Protect( mac.ComputeHash(Cardinity.ENCODING.GetBytes(data)));
}
public string AsBase64()
{
return System.Convert.ToBase64String(Unprotect(rawHmac));
}
public void Dispose()
{
if (rawHmac != null)
{
//overwrite memory address
for (int i = 0; i < rawHmac.Length; i++)
{
rawHmac[i] = 0;
}
//release memory now
rawHmac = null;
}
mac?.Dispose();
mac = null;
}
~Mac()
{
Dispose();
}
}
}