I am writing a library, and I have a method which takes in a Dictionary. The value of the dictionary is untrusted/insecure, but the key is trusted and if an end-user were given the ability to enter an arbitrary key name then "bad things" could happen.
So when other developers use this library function, I want to force them to know the key name at compile time. So something like this would be allowed:
string userInput = Console.ReadLine();
Dictionary<string, string> something = new Dictionary<string, string>();
something.Add("MyKey", userInput);
Because "MyKey" is a string literal, known at compile time. But something like this would either raise a compile or runtime exception:
string userInput = Console.ReadLine();
string userKey = Console.ReadLine();
Dictionary<string, string> something = new Dictionary<string, string>();
something.Add(userKey, userInput);
Because user input was used for the key (userKey) and thus it was unknown at compile time.
I've looked in GetType() and there is nothing that really distinguishes between a literal string and a string created at runtime.
You can use string.IsInterned
to determine if the string is interned. All compile time literals will be interned by default, but you can turn this off using a compiler flag.
This is a runtime check, not a compile time check.
Also note that non-compile time literals can be interned using the string.Intern
function, so technically you can have non-literal strings pass your test. But if your program is either not interning strings at any point, or only ever interning strings you know are safe, then this may work.
Another option, if all of your keys are supposed to be known at compile time, is to not have the key be a string at all. Make the key be an enumeration, for example, so that you know that the only values that can ever be used as keys are on a list you've fixed at compile time.
Not extensively tested, but by using expressions instead of direct values, you could test the type of value being passed. e.g.
void Add(Expression<Func<string>> fn)
{
if (fn.Body.NodeType != ExpressionType.Constant)
throw new ArgumentException("Only literal strings are allowed");
//and extra check if the value itself is interned
var val = fn.Compile()();
if (string.IsInterned(val) == null)
throw new ArgumentException("Only literal strings are allowed");
}
Then the developer has to pass the argument as a lambda:
Add(() => "Test"); //Valid
string somestring = "Test";
Add(() => somestring); //Error
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With