Reputation: 35198
We have a module at work that is included in most scripts to create a logging event that includes who invoked the script and what command line args were passed to it. Currently this simply uses a dump of @ARGV.
However, we're wanting to include this functionality for scripts that potentially include secure information that is passed on the command line. We therefore still want to ledger the options passed to the script but masking the values. s/(?<=.{2})./X/sg
For example
#!/usr/bin/env perl
use strict;
use warnings;
use Data::Dump qw(dd);
use Getopt::Long qw(GetOptions);
local @ARGV = ( '-i', '--name' => 'value', '--password' => 'secure info', '--list' => 'foobar', '--list' => 'two' );
# The below GetOptions call specifics the allowed command line options
# to be parsed and validated.
#
# I want some way to accomplish the same but WITHOUT having to specify
# anything.
#
# Something like: GetOptinos( \my %hash ); # Just do it without validation
GetOptions( \my %hash, 'i', 'name=s', 'password=s', 'list=s@' );
for ( values %hash ) {
for ( ref($_) ? @$_ : $_ ) {
s/(?<=.{2})./X/sg;
}
}
dd \%hash; # The the command line options are generically logged to a file with the values masked.
Outputs:
{
i => 1,
list => ["foXXXX", "twX"],
name => "vaXXX",
password => "seXXXXXXXXX",
}
The module I'm used to using for CLI parsing is Getopt::Long.
Is there a way to get Getopt::Long to not validate, but simply generically parse the options into a hash without having to specify any of the allowed options? Alternatively, is there another module that would give this ability?
Upvotes: 3
Views: 142
Reputation: 66881
I am not sure how Getopt::Long
affects security, but I can think of a couple of ways to limit how much it works with provided arguments.
When a user subroutine is used to process options
It is up to the subroutine to store the value, or do whatever it thinks is appropriate.
I assume that the code just passes things to the sub. Then you can put them away as you wish
GetOptions(sensitive_opt => sub { $sensitive{$_[0]} = $_[1] }, ...) or usage();
Another way would be to not document the sensitive options for Getopt::Long
, but provide the argument callback <>
, which runs for each unrecognized thing on the command line; then those can be processed by hand. For this the pass_through configuration option need be enabled
use Getopt::Long qw(pass_through); # pre 2.24 use Getopt::Long::Configure()
GetOptions(opt => \$normal_opt, ... '<>' => \&process_sensitive) ...
Then the given options are handled normally while the (expected) sensitive ones are processed by hand in process_sensitive()
.
The drawback here is that the options unmentioned in GetOptions
are literally untouched and passed to the sub as mere words, and one at a time. So there would be some work to do.
Upvotes: 2