Web Development

Never use dynamic variable names

How to dynamically name variables is a common subject of programming questions. That's a great way to create security problems, though.

You have all probably seen it -- at least, all of you that pay any attention to online discussion of programming. Sometime, somewhere, somebody eventually crops up asking about how, in a particular language, to dynamically give an arbitrary name to a variable.

What usually this means is that the person wants something like the ability to take input from a user and use that input to name a variable. This seems to crop up more in PHP circles than anywhere else, in my experience, though it seems to come up everywhere eventually. It is usually possible, too, especially if your language of choice has eval. A rather ugly example in Ruby is:

var_name = gets.chomp          # get input from STDIN

var_value = gets.chomp # get more input from STDIN

eval("#{var_name} = var_value")

(Note: All code examples in this article are in Ruby. I chose Ruby because I think it is easy to read, which makes it useful for examples; because I like the language; and because I know Ruby well enough to provide relevant examples without having to think about it too hard. The principles are easily translatable to many other languages, however. Note that the chomp method just gets rid of the newline character at the end of a line of input.)

If you run the program and enter foo at the first prompt and bar at the second prompt, you'll end up with a variable named foo that contains the value bar. It's pretty simple, really -- but don't do it.

It is really not something you should ever do. Please, please don't do this. The best case scenario would generally be ugly code that is difficult to reason through and, as a result, difficult to maintain. I think most people who come to mailing lists and other online discussion venues asking this question don't realize how difficult it is going to be trying to work with variables whose names they do not know in advance, once they have dynamically named their variables.

The common use case is probably one where the programmer wants to be able to dredge up values based on input from the user. For instance, if a variable is named foo because that is what the user inputs as a value at some point, the program can get output by prompting the user so that the user inputs foo again. Right?

The proper way to do this sort of thing is usually to use scoping rules in the language, most likely in concert with some kind of looping construct, so that a value can be stored where needed. That way, the "special place" where the value is stored isn't a dynamically named variable; it is, instead, the current scope of the program, which vanishes when the program is done with that variable. In other cases, it might make more sense to just create a new sequential entry in some kind of database or programmatic data structure, and refer back to that based on stored values instead of on the names of the variables that store those values.

Consider, for instance, an array of arrays. Why not just create an array with an arbitrary number of entries in it, adding to those entries as needed -- and let each array element be a two-element array itself?

ar = [

[gets.chomp, gets.chomp],

[gets.chomp, gets.chomp]

]

If the user inputs foo, bar, baz, and qux in response to the input prompts, the above gives you the equivalent of:

ar = [

['foo', 'bar'],

['baz', 'qux']

]

You can iterate or recurse through the ar array, seeking out subarrays whose first element is 'foo', and getting the second element from that subarray, if you must:

user_call = gets.chomp

ar.each do |pair|

puts pair[1] if pair[0] == user_call

end

That will just print out the word bar, and it is pretty simple. It is also much easier to be sure you have secured properly than a bunch of eval expressions that take user input. If you actually use dynamically named variables, you will also have to dynamically determine how to call those variables, after all:

user_call = gets.chomp

puts eval("#{user_call}")

That may look simple, but it's an incredibly naive implementation. In order to even begin to pretend that code is secure, you will need to sanitize input, which means a lot more code. More on that in a moment.

Complex concepts that are used when simpler concepts will do just as well create maintenance problems. The more such problems you have, the more likely you are to introduce security issues into your software. This is not just a problem of making your life more difficult -- it is also a problem of making your users' lives less secure. Don't do it. Do not try to dynamically name your variables. There may be times you can get away with it, but you are playing with fire if you try. There may be times it is even a better idea to do it than some alternative, but I can almost guarantee you will never run across such a circumstance. If you think you have one of those circumstances facing you, chances are much better that you simply need to rethink your solution to the problem at hand.

As I pointed out in The safest way to sanitize input: avoid having to do it at all, using code others have written and -- more importantly -- that others have tested much more than you will test your own code before releasing it is a great way to minimize the likelihood of introducing security vulnerabilities to your code. In essence, using multidimensional arrays to approximate dynamically named variables is a case of using code (the array-handling code) someone else (the language implementation developer) has written, instead of writing your own dynamic variable implementation (using an eval expression) yourself.

Even simpler, though, is just using a one-dimensional array. Often enough, when someone thinks he needs dynamic variable naming, all he really needs is an array. Your array can be named whatever is appropriate for the array, and you can use numbers to keep track of the elements, since array elements are numbered. If need be, you can even maintain two arrays so there's some kind of correspondence maintained between two sets of values. For instance:

arkey[0] = gets.chomp

arval[0] = gets.chomp

That gives you two arrays, one which contains what you wanted to use as the variable name and the other which contains what you wanted to assign to it as a value. You can just iterate through the first array -- arkey -- to find the element number that corresponds with the user input term you wanted to use as a variable name, then use that same element number to get the corresponding value:

num = nil

(0..(arkey.length - 1)).each do |n|

num = n if arkey[n] == 'foo'

end

puts arval[num]

If the corresponding arval value is all you need, you can simplify it:

(0..(arkey.length - 1)).each do |n|

puts arval[n] if arkey[n] == 'foo'

end

If you want to get really fancy, you might think you could perhaps use a hash (if your language supports it), which should be a better idea at least than using an eval expression. For instance:

ha = Hash.new

ha[gets.chomp] = gets.chomp

If you enter foo first and bar second, you'll get a hash element with the key name foo that contains the value bar:

puts ha['foo']

That will output bar. Easy-peasy, no dynamic variable naming needed -- or so it seems. On the other hand, on closer examination, you will need to come up with some way to slot that foo in there dynamically if you want to call up values based on user input. Once again, you may need to use an eval expression. Perhaps you should just stick with arrays after all.

The point here is that there are ways to get the results you probably wanted to get out of dynamically naming a variable without having to use eval. Using an eval expression is a great way to get yourself in trouble if you're not very, very careful -- especially if there is any chance at all that there will be any user input in your eval expression anywhere! In much the same way that SQL injection vulnerabilities can let people run arbitrary SQL queries, eval expressions that include user input can potentially result in users running arbitrary code as well. Any time you are tempted to use an eval expression on user input, or otherwise execute arbitrary user input, you should rethink your approach.

Earlier, I mentioned a previous article, The safest way to sanitize input: avoid having to do it at all. The first time I brought it up was to touch on the importance of using others' code to solve your problems, when reasonable to do so, because the other code has probably been well-tested and had bugs (including potential security vulnerabilities) shaken out. In particular, that article's mention of this rule of thumb for programming referred to others' code for validating input. As you might have guessed from the article, though, the best approach is to avoid having to do it at all -- and not just to use others' code to do it.

One could make the argument that properly sanitized user input in an eval expression is no direct threat to security, and you'd be right. The problem is that you may never know for sure that all possible user input will be "properly sanitized". One reason to avoid using an eval expression for anything involving user input is, simply, because your best protection against unsanitized (or improperly sanitized) user input is to avoid having to sanitize that input at all. Any other approach to dynamically naming variables is likely to suffer similar problems to an explicit eval expression solution, and creating a situation where you need to sanitize input just creates more opportunity for security vulnerabilities to creep into your code.

In this case, taking the easy way out is the same as taking the cautious approach. If you do not use dynamic variable names, you will not have to deal with the problem at all, so just don't use dynamic variable names. It really is that simple.

About

Chad Perrin is an IT consultant, developer, and freelance professional writer. He holds both Microsoft and CompTIA certifications and is a graduate of two IT industry trade schools.

19 comments
BradutDima
BradutDima

Hi, I started recently learning PHP and found one way of reading variables from POST a little bit awkward: $isbn = $_POST['isbn']; $title = $_POST['title']; $author = $_POST['author']; $catid = $_POST['catid']; $price = $_POST['price']; ...... $description = $_POST['description']; So, since I do expect variables {isbn ? description} be sent by POST, I think that instead of typing them one by one in my code, over and over again in all pages, I would rather dynamically create them from POST like this: if ($_POST) { foreach (array_keys($_POST) as $key) { $$key = $_POST[$key]; } } For sanitization, this dynamic method could be improved by receiving a list of variables to be read from POST, etc. I might be wrong, and I acknowledge that I am a beginner in PHP, but at a first glance I see this approach useful in term of productivity. Bradut

jmgarvin
jmgarvin

Apparently this is taught as good coding technique (dynamic variables that is). This seems to be a common sense issue, but apparently is not.... You've verbalized everything that I couldn't! Thanks so much...

Tony Hopkinson
Tony Hopkinson

typed and compiled in development terms but I've never considered doing that. I mean a simple mapping structure will achieve the same thing in a far safer and much more maintainable manner. This sort of trick is for winning code obfuscation competitions, not deploying real world applications. Any developer who did, I'd have to put in the desperate category if they didn't think it was clever, or the muppet one if they did.

apotheon
apotheon

Users are evil. Just repeat that mantra to yourself while planning out how to code your application. It'll stand you in good stead when users start inputting data designed to make your program go "kablooey".

Sterling chip Camden
Sterling chip Camden

Someone could possibly craft a form to submit to your site that could modify the operation of your code, if they new what variables to plug.

apotheon
apotheon

Why not just use an associative array instead of reassigning all the values to individual scalar variables?

apotheon
apotheon

Who is teaching this kind of thing as good coding technique?

Tony Hopkinson
Tony Hopkinson

So clever i's stupid would be more accurate. The best bit is if you realise how weak it is, and decide to sanitise it, one thing you might use is a structure of allowable names.....

apotheon
apotheon

I've seen that question in the context of C and Java, too.

ian
ian

of the "Alter" verb in COBOL, whereby you could change the logic flow dependent on a variable value. In my first programming job I was determined to try this out despite the dire warnings of my (to me) elderly and staid colleagues. Turned out they were right. After far too many fruitless hours of debugging, had to call it quits.

JackOfAllTech
JackOfAllTech

Even from the example, I don't understand why anyone would want to, let alone need to do this. Can anyone pose a situation where a jr. programmer might consider doing this?

Sterling chip Camden
Sterling chip Camden

especially in a dynamic language like Ruby, you may not know what a particular language construct may do -- because some other package or programmer introduced a syntax not documented in the language itself. I'd never, ever do an eval on user input. I even get scared about doing an eval on code produced by a server (thinking JSON here) -- a parser that's looking for specific syntax is a much safer bet.

jmgarvin
jmgarvin

but the younger guys coming in sure do do it... I assume it's the universities, but I suppose it could be at boot camps or vendor courses???

apotheon
apotheon

If you're using a whitelist of allowable inputs, you might as well skip the eval statement. Why do all the coding for a different approach, then not use it?

Tony Hopkinson
Tony Hopkinson

might as well choose an unsuitable tool as well, just make it a real challenge.

D Walker
D Walker

I had never seen a COBOL ALTER used until recently (recent workplace not recent code)! ALTER was used for flow control (in spaghetti code). Instead of storing a value in a variable to indicate where to GOTO at a point in the logic flow it altered the GOTO code. I had worked with spaghetti code before but it took me more than a few minutes to trace the flow! Glad I did not have to modify the program flow ? just add a subroutine call. Dynamic variable naming is not something I would want to see. Using a table or array(s) would seem to about as simple and much easier to maintain. Dennis -- Mainframe COBOL programmer for over 15 years - some exposure to "modern" programming and still learning.

Justin James
Justin James

I spent a lot of time in dynamic languages. I was a big Perl user, and a major fan of eval.(). All the same, it never would have occured to me in a million years to do something like this, I never saw something like this, and I never heard of something like this. In my time in the industry, no one has ever asked me to do something like this or asked me how to do something like this. The closest I will ever come to something like this is to load up undefined user input into a hashtable/associative array, which is a common enough and safe enough practice. Even then, undefined names are pretty useless, because unless you want to do some giant mess of code, how do you even know what to look for in the input to take action on? In terms of running eval.()... I've always felt that one should never run eval.() on text unless it came from someone/somewhere that someone could have just changed the application code instead. In other words, Never eval.() user input, never eval.() text from a 3rd party service, be extremely cautious when eval.()'ing something from a database. Basically, be willing to eval stuff like templates and config files stored in the same file tree as the app, because anyone with access to those can mess with the app anyways. Now, making user input *available* to the eval.()'ed code is an entirely different matter, and entirely appropriate. I think maybe you know the wrong programmers! Even the worst ones I met would never think to do this! :) J.Ja

apotheon
apotheon

I guess the sunk cost fallacy does rear its ugly head, in one way or another, all too often.

Tony Hopkinson
Tony Hopkinson

I have a hard time rationalising that sort of foolishness. May be it's because of all the personal investment in 'your' great idea that turned out to be complete arse. A lot of 'devlopers' are really weak on dropping a bad idea.

Editor's Picks