|
Lines 28-33
use base qw(Koha::Object);
Link Here
|
| 28 |
# Only 1 error is returned |
28 |
# Only 1 error is returned |
| 29 |
# TODO Koha::Report->store should check this before saving |
29 |
# TODO Koha::Report->store should check this before saving |
| 30 |
|
30 |
|
|
|
31 |
use constant FORBIDDEN_COLUMN_MATCHES => qw(password token uuid secret); |
| 32 |
use constant WHITELISTED_COLUMN_NAMES => |
| 33 |
qw(password_expiration_date password_expiry_days reset_password change_password min_password_length require_strong_password password_expiration_date); |
| 34 |
|
| 31 |
=head1 NAME |
35 |
=head1 NAME |
| 32 |
|
36 |
|
| 33 |
Koha::Report - Koha Report Object class |
37 |
Koha::Report - Koha Report Object class |
|
Lines 58-68
sub is_sql_valid {
Link Here
|
| 58 |
push @errors, { sqlerr => $1 }; |
62 |
push @errors, { sqlerr => $1 }; |
| 59 |
} elsif ($sql !~ /^\s*SELECT\b\s*/i) { |
63 |
} elsif ($sql !~ /^\s*SELECT\b\s*/i) { |
| 60 |
push @errors, { queryerr => 'Missing SELECT' }; |
64 |
push @errors, { queryerr => 'Missing SELECT' }; |
|
|
65 |
} else { |
| 66 |
push @errors, { passworderr => "Illegal column in results" } |
| 67 |
if $self->check_columns($sql); |
| 61 |
} |
68 |
} |
| 62 |
|
69 |
|
| 63 |
return ( @errors ? 0 : 1, \@errors ); |
70 |
return ( @errors ? 0 : 1, \@errors ); |
| 64 |
} |
71 |
} |
| 65 |
|
72 |
|
|
|
73 |
=head3 check_columns |
| 74 |
|
| 75 |
$self->check_columns('SELECT password from borrowers'); |
| 76 |
$self->check_columns( undef, [qw(password token)] ); |
| 77 |
|
| 78 |
Check if passed sql statement or column_names arrayref contains |
| 79 |
forbidden column names (credentials etc.). |
| 80 |
Returns all bad column names or empty list. |
| 81 |
|
| 82 |
=cut |
| 83 |
|
| 84 |
sub check_columns { |
| 85 |
my ( $self, $sql, $column_names ) = @_; |
| 86 |
|
| 87 |
# TODO When passing sql, we actually go thru the whole statement, not just columns |
| 88 |
|
| 89 |
my $regex; |
| 90 |
push my @columns, @{ $column_names // [] }; |
| 91 |
if ($sql) { |
| 92 |
|
| 93 |
# Now find all matches for e.g. password but also modulepassword or password_hash |
| 94 |
# Note that \w includes underscore, not hyphen |
| 95 |
$regex = '(\w*(?:' . ( join '|', FORBIDDEN_COLUMN_MATCHES ) . ')\w*)'; |
| 96 |
@columns = ( $sql =~ /$regex/ig ); |
| 97 |
} else { |
| 98 |
$regex = '(' . ( join '|', FORBIDDEN_COLUMN_MATCHES ) . ')'; |
| 99 |
@columns = grep { /$regex/i } @columns; |
| 100 |
} |
| 101 |
|
| 102 |
# Check for whitelisted variants |
| 103 |
$regex = '(^' . ( join '|', WHITELISTED_COLUMN_NAMES ) . ')$'; # should be full match |
| 104 |
@columns = grep { !/$regex/i } @columns; |
| 105 |
return @columns; |
| 106 |
} |
| 107 |
|
| 66 |
=head3 get_search_info |
108 |
=head3 get_search_info |
| 67 |
|
109 |
|
| 68 |
Return search info |
110 |
Return search info |