简体   繁体   English

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

[英]C# client - securing REST authentication tokens on client machine

Question i'd like to discuss about. 我想讨论的问题。

We have REST services (WCF) that after logon - a token is received and is sent to the client. 我们拥有REST服务(WCF),该服务在登录后-接收到令牌并将其发送给客户端。 HTTPS is of course defined. HTTPS当然是定义的。

each request sends this token in the "Authorization" header. 每个请求都会在“授权”标头中发送此令牌。

The thing is, that if someone dumps the memory, he will be able to get the token and use it as he wishes. 问题是,如果有人转储了内存,他将能够获取令牌并按自己的意愿使用它。

we can secure this token only until the send, as we need to convert it to a C# string - which, can't be explicitly disposed. 我们只能在发送之前确保此令牌的安全,因为我们需要将其转换为C#字符串-无法显式处理。

so, there are 2 problems with this approach: 因此,此方法存在两个问题:

  1. The garbage collector moves managed objects, and this string can be duplicated in memory 垃圾收集器移动托管对象,并且此字符串可以在内存中重复
  2. strings are managed with an internal table. 字符串由内部表管理。 they are immutable and can't be cleared on request. 它们是不可变的,不能应要求清除。

is there a recommended way of securing the token? 有建议的方法来保护令牌吗? maybe buffering the headers each request 1 character at a time? 也许缓冲标题每次一次请求1个字符?

Would love to hear your thoughts. 很想听听您的想法。

Your post is a little confusing, are you the client/consumer, or the service/provider? 您的帖子有点令人困惑,您是客户/消费者还是服务/提供商?

If you're the provider, you should be more concerned about having HTTPS enabled, you wouldn't believe how easy it is to steal tokens over the clear web and if your service is compromised, then having the memory dumped is still the least of your problems. 如果您是提供者,则应该更加关注启用HTTPS的情况,您不会相信在透明的网络上窃取令牌有多么容易,并且如果您的服务受到损害,那么转储内存仍然是最少的事情。你的问题。

That said, what you're looking for is SecureString you can find more information on it here 也就是说,您正在寻找的是SecureString您可以在此处找到更多信息。

And here's a small example of how to make it work.... 这是一个如何使其工作的小例子。

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);
    }
}

It's probably worth checking out the DPAPI whilst you're on the subject too... 当您也在研究该主题时,可能值得检查一下DPAPI ...

Here's one of my utility classes that makes use of it 这是我利用它的实用程序类之一

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;
   }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM