How to avoid using System.String with Rfc2898DeriveBytes in C#

The .NET Core team specifically recommends against using SecureString for new development. See the SecureString documentation:

We don't recommend that you use the SecureString class for new development. For more information, see SecureString shouldn't be used on GitHub.

as well as the team's reasoning on GitHub:

Motivation

  • The purpose of SecureString is to avoid having secrets stored in the process memory as plain text.
  • However, even on Windows, SecureString doesn't exist as an OS concept.
    • It just makes the window getting the plain text shorter; it doesn't fully prevent it as .NET still has to convert the string to a plain text representation.
    • The benefit is that the plain text representation doesn't hang around as an instance of System.String -- the lifetime of the native buffer is shorter.
  • The contents of the array is unencrypted except on .NET Framework.
    • In .NET Framework, the contents of the internal char array is encrypted. .NET doesn't support encryption in all environments, either due to missing APIs or key management issues.

Using SecureString correctly is difficult, and protects against a threat surface that is unlikely for most use cases. As you say, if an attacker can read your memory, you have other problems. I would advise to use normal strings instead of SecureString, unless you are worried by attackers carrying liquid nitrogen with physical access to your server.

If you really want to use SecureStrings, you should P/Invoke the Windows crypto API so that you have control over memory. I have an example in my blog post Comparing secure strings in .NET.