C# 客户端 - 保护客户端计算机上的 REST 身份验证令牌


我想

讨论的问题。

我们有 REST 服务 (WCF),在登录后 - 接收令牌并将其发送到客户端。HTTPS当然是定义的。

每个请求在"授权"标头中发送此令牌。

问题是,如果有人转储内存,他将能够获得令牌并随心所欲地使用它。

我们只能在发送之前保护此令牌,因为我们需要将其转换为 C# 字符串 - 无法显式释放。

因此,这种方法存在 2 个问题:

  1. 垃圾回收器移动托管对象,此字符串可以在内存中复制
  2. 字符串使用内部表进行管理。 它们是不可变的,无法根据请求清除。

是否有推荐的保护令牌的方法? 也许缓冲每个请求的标头一次 1 个字符?

很想听听你的想法。

你的帖子有点混乱,你是客户/消费者,还是服务/提供者?

如果您是提供商,您应该更关心启用HTTPS,您不会相信通过清晰的网络窃取令牌是多么容易,如果您的服务受到损害,那么转储内存仍然是您最少的问题。

也就是说,您正在寻找的是SecureString您可以在此处找到更多信息

这里有一个小例子说明如何让它工作......

public void Example()
{
    SecureString secureString = ConvertToSecureString("abc");
    string normalString = ConvertToString(secureString);
    Console.WriteLine (normalString);
}
// Secure it
public  SecureString  ConvertToSecureString(string password)
{
    SecureString secureString = new SecureString();
    foreach (char c in password.ToCharArray()) 
    {
        secureString.AppendChar(c);
    }
    return secureString;
}
// Unsecure it
public string ConvertToString(SecureString securePassword)
{
    IntPtr unmanagedString = IntPtr.Zero;
    try
    {
        unmanagedString = Marshal.SecureStringToGlobalAllocUnicode(securePassword);
        return Marshal.PtrToStringUni(unmanagedString);
    }
    finally
    {
        Marshal.ZeroFreeGlobalAllocUnicode(unmanagedString);
    }
}

当您讨论该主题时,可能也值得查看 DPAPI......

这是我使用它的实用程序类之一

public void DpapiExample()
{
    // Adds a level of entropy to our encryption making our encrypted data more secure
    string entropy = "603e0f3a0ef74faf93b5e6bc2c2f7c358107";
    var dpapi = new Dpapi(entropy);
    string textToEncrypt = "I'm a secret";
    string encryptedText;
    dpapi.TryEncrypt(textToEncrypt, out encryptedText);
    Console.WriteLine ("Encrypting");
    Console.WriteLine (textToEncrypt);
    Console.WriteLine (encryptedText);
    string decryptedText;
    dpapi.TryDecrypt(encryptedText, out decryptedText);
    Console.WriteLine ("rnDecrypting");
    Console.WriteLine (encryptedText);
    Console.WriteLine (decryptedText);  
}
public class Dpapi
{
   private readonly byte[] entropy;
   public Dpapi(string entropy)
   {
       this.entropy = Encoding.UTF8.GetBytes(entropy);
   }
   public Dpapi(string entropy, Encoding encoding)
   {
       this.entropy = encoding.GetBytes(entropy);
   }
    public bool TryDecrypt(string encryptedString, out string decryptedString)
   {
       if (string.IsNullOrWhiteSpace(encryptedString))
       {
           throw new ArgumentNullException("encryptedString");
       }
       decryptedString = string.Empty;
       try
       {
           byte[] encryptedBytes = Convert.FromBase64String(encryptedString);
           byte[] decryptedBytes = ProtectedData.Unprotect(encryptedBytes, this.entropy, DataProtectionScope.LocalMachine);
           decryptedString = Encoding.UTF8.GetString(decryptedBytes);
       }
       catch
       {
           return false;
       }
       return true;
   }
   public bool TryEncrypt(string unprotectedString, out string encryptedString)
   {
       if (string.IsNullOrWhiteSpace(unprotectedString))
       {
           throw new ArgumentNullException("unprotectedString");
       }
       encryptedString = string.Empty;
       try
       {
           byte[] unprotectedData = Encoding.UTF8.GetBytes(unprotectedString);
           byte[] encryptedData = ProtectedData.Protect(unprotectedData, this.entropy, DataProtectionScope.LocalMachine);
           encryptedString = Convert.ToBase64String(encryptedData);
       }
       catch
       {
           return false;
       }
       return true;
   }
}

最新更新