I thought $Bin (or any variable) could only be untainted through a regular expression.
Correct. (Well, not quite. But I don't see how the other way documented in perlsec - see also Re: When not to use taint mode - could do anything to improve security.)
Is it something in lib that will be untainting it?
No, and lib would be the wrong place for automatic untainting. How should lib know which paths are secure and which ones aren't? How should lib know which string is a valid path, and which is not? At least lib would have to accept a regular expression to validate and untaint paths. (This is what File::Find does for the untaint and untaint_pattern options.)
Note the wording in the previous paragraph: a regular expression to validate and untaint. You don't just want to blindly untaint. You want to validate the input. Untainting of the input is just a welcome side effect of the validation.
By the way: you generally want a positive rule, describing how valid input looks like. You don't want negative rules that forbid invalid inputs. Simply because it is too easy to forget some invalid input.
Alexander
--
Today I will gladly share my knowledge and experience, for there are no sweeter words than "I told you so". ;-)
| [reply] [d/l] [select] |
You don't just want to blindly untaint. You want to validate the input.
That makes sense...thanks
So, would a sensible approach be to check that $Bin resembles one of the places I expect it to be run from?
Something like this (untested):
#!/usr/bin/perl -T
use CGI::Carp qw(fatalsToBrowser);
use FindBin qw($Bin);
if ($Bin =~ /^(\/home\/someuser\/somewebsite\/\w{2,4}\/cgi-bin)/) {
$Bin = $1;
}
use lib "$Bin";
use Site::HTML;
use strict;
use warnings;
The \w{2,4} allows for the different subdomains used for development, testing, etc.
I don't recall seeing anything like that in any other Perl code I've seen that uses FindBin and lib so I'm guessing there is a better way to do it... | [reply] [d/l] [select] |
#!/usr/bin/perl -T
use CGI::Carp qw(fatalsToBrowser);
use FindBin qw($Bin);
if ($Bin =~ /^(\/home\/someuser\/somewebsite\/\w{2,4}\/cgi-bin)/) {
$Bin = $1;
}
use lib "$Bin";
use Site::HTML;
use strict;
use warnings;
The \w{2,4} allows for the different subdomains used for development, testing, etc.
A few notes:
- \w can be problematic if you use locale, see perlsec. Better limit that more, e.g. lower-case ASCII letters.
- You could avoid the leaning toothpick syndrome by using different quotes for the match operator:
if ($Bin =~ m!^(/home/someuser/somewebsite/[a-z]{2,4}/cgi-bin/)!)
It's not a security thing per se, it just makes the code more readable.
- Your code lacks any handling for a failed validation. If $Bin does not match, you simply continue and hope that taint mode will kill your script. Make that explicit:
if ($Bin =~ m!^(/home/someuser/somewebsite/[a-z]{2,4}/cgi-bin/)! ) {
$Bin = $1;
} else {
die "Go away, stupid script kiddie!\n";
}
# or maybe:
$Bin =~ m!^(/home/someuser/somewebsite/[a-z]{2,4}/cgi-bin/)! or die "W
+here am I?\n";
$Bin = $1;
- You don't need to quote $Bin in use lib "$Bin".
- You are mixing compile time and runtime. FindBin sets up $FindBin::Bin (and all other exported variables) at compile time. use lib uses $FindBin::Bin at compile time. Way after that, at runtime, you are validating and untainting $FindBin::Bin. That won't work. The easiest way to work around that is to use an expression after use lib, as in Re^2: Calculations before using lib; or Re^6: @INC from $0, that evaluates to the untainted version of $FindBin::Bin.
- As explained in Re^5: Using relative paths with taint mode by ikegami, you should use $FindBin::RealBin instead of $FindBin::Bin.
Alexander
--
Today I will gladly share my knowledge and experience, for there are no sweeter words than "I told you so". ;-)
| [reply] [d/l] [select] |
That fails for a $0 of /tmp/script.cgi. Keep in mind that a caller can provide anything they want for $0; it doesn't need to have any relation to the script whatsoever. (While true for a binary executable, it's a bit different here...)
I think it's ok if you use $RealBin instead of $Bin (which you should be doing anyway[1]), but I wouldn't rule out me overlooking something.
$Bin fails when the program is launched using a symlink.
Seeking work! You can reach me at ikegami@adaelis.com
| [reply] [d/l] [select] |