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

时间:2015-04-19 12:30:35

标签: c# wcf security rest

问题我想讨论。

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

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

问题是,如果有人转储内存,他将能够获得令牌并按照自己的意愿使用它。

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

所以,这种方法存在两个问题:

  1. 垃圾收集器移动托管对象,此字符串可以在内存中复制
  2. 字符串使用内部表进行管理。它们是不可变的,不能根据要求清除。
  3. 是否有推荐的方法来保护令牌?也许缓冲标题每次请求1个字符?

    很想听听你的想法。

1 个答案:

答案 0 :(得分:0)

您的帖子有点令人困惑,您是客户/消费者,还是服务/提供商?

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

那就是说,您正在寻找的是SecureString您可以找到有关它的更多信息here

这是一个如何使其发挥作用的小例子。

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 ("\r\nDecrypting");
    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;
   }
}