in reply to variable interpolation from a filehandle

If you're planning on working with data being provided by an untrusted source (e.g. a CGI script), be very careful about blindly evaluating strings, as it's not hard to craft something rather malicious.

An alternative would be to do the interpolation by hand:

no strict 'refs'; # You are using strict, yes? for (@array) { s/\$(\w+)/${$1}/eg; }
You could even go so far as to force the variables to come from a specific package, by using, say, ${"${package}::$1"}. That should keep them out of your regular name space.

Replies are listed 'Best First'.
eval and security issues
by markjugg (Curate) on Oct 05, 2000 at 03:37 UTC
    I like the simplicity of simply 'eval'ing a template file for variables, and this suggestion of forcing the variables into a particular namespace sounds helpful, but is it enough? Is this a sufficient security system for untrusted data? What do other folks recommend? Would one of the templating modules from CPAN be a good choice?

      Just to emphasize what "something rather malicious" can mean:

      "This string, @{[system('echo rm -rf /')]} is almost evil."
      I put the "echo" in so any fool who wonders what that does and cuts-and-pastes it into Perl doesn't get too burnt. So, how far do you want to trust string interpolation now?

      Me, I don't trust string interpolation even if I'm not doing something obviously dangerous like CGI. It becomes very easy to forget to properly guard access to your templates and end up running code that you didn't want to.

      Now, as for the code (slightly rewritten, just for variety -- I don't claim my version is not worse):

      s#\$(\w+)#'$'.$1#gee
      we are quite safe. This code cannot create variables. It cannot even access variables from other packages (\w matches neither ":" nor the Perl4-ish "'") nor the built-in variables (unless you use English in your package).

      Even fairly nasty stuff like a tied variable whose FETCH routine sends threatening e-mail to your boss isn't a problem unless your script created such a tied variable before we interpolate the arbitrary string.

      So I don't see any use for the ${"${package}::$1"} suggestion in this particular case, since the same thing could be accomplished via (with yet another variation thrown in):

      { package SandBox; s/([\$\@]\w+)/"join' ',$1"/gee; }

      Finally, you can't throw a TCP/IP packet at CPAN without hitting yet another templating module. Some of these do "safe" templating. Some of them do "full power" templating where all the dangers of eval apply. Some support both modes and stuff in between. Just be careful.

              - tye (but my friends call me "Tye")
      Running Perl with taint-checking enabled (-T) does wonders. The mechanism I gave in the earlier post should be quite sufficient, and should satisfy taint checks, because I'm pulling word characters and explicitely specifying a package name. The user is unable to specify any special characters or anything that would allow their variables to be interpolated as anything but variables.

      Generally so long as you have taint checking enabled and those internal taint checks are satisfied with the way you're handling untrusted data ("Trust no one."), you will typically be OK. The only places you have to be careful is in untainting data, such as where I was using a regular expression to pull variable names out of the untrusted string. So long as you know what you're doing in cases like this and trust the mechanism enough to guarantee that the data you're pulling out is trustworthy (and untainted), you should be safe.