Codebase list libjifty-dbi-perl / upstream/0.68
[svn-upgrade] new version libjifty-dbi-perl (0.68) Gregor Herrmann 13 years ago
7 changed file(s) with 115 addition(s) and 49 deletion(s). Raw diff Collapse all Expand all
00 Revision history for Perl extension Jifty::DBI.
1
2 0.68 2011-04-14
3 - Security:
4 * Prevent SQL injection in column names, operators, order and group by
5 (Alex Vandiver)
6 * Fix distinct_query to catch injection and correctly rewrite to
7 function => '' (Alex Vandiver)
8 * Prevent SQL injection via IS
9
10 - Fixes:
11 * There is no need to check $args{column} around our LIKE adjustments
12 (Alex Vandiver)
13 * Slightly unify nigh-identical codepaths between Pg and Oracle
14 (Alex Vandiver)
115
216 0.67 2011-02-28
317 - Features:
4646 version: 0
4747 resources:
4848 license: http://dev.perl.org/licenses/
49 version: 0.67
49 version: 0.68
1414 Hash: SHA1
1515
1616 SHA1 418a58763132c9a476627cbdce5ff01395ce84d4 .gitignore
17 SHA1 45d9eaf8a622fdfc0bb9680396e2843eca5ec346 Changes
17 SHA1 59a52f546dcd1cd87813bc59babf7b1cd32ac2d3 Changes
1818 SHA1 c2fb135f967d7093a6191d1b7e5e596e30040246 MANIFEST
19 SHA1 f21d5f2dc45943fbc09ac079b2b18d942a6f3f81 META.yml
19 SHA1 da76cdd7f1c89f107d3d5c9608aff9f886e503f8 META.yml
2020 SHA1 48bd6ca8a37ec79b7cae91028d7e9489ad33a03b Makefile.PL
2121 SHA1 e29d7b270f78a5a406921571b08290c46f2a42f6 README
2222 SHA1 82d6ac3f6def48558d09f8b6e3b53ed4194d8c81 ROADMAP
4040 SHA1 026cc0551a0ad399d195e395b46bdf842e115192 inc/Module/Install/Metadata.pm
4141 SHA1 5457015ea5a50e93465bf2dafa29feebd547f85b inc/Module/Install/Win32.pm
4242 SHA1 051e7fa8063908befa3440508d0584a2497b97db inc/Module/Install/WriteAll.pm
43 SHA1 84ab56168fb14f1530c035b549c2af0750f0fd60 lib/Jifty/DBI.pm
44 SHA1 e0375edf9f501e6b9c723fced70431108188419b lib/Jifty/DBI/Collection.pm
43 SHA1 3a442252053b99436c8cdd084ced4801e4e22381 lib/Jifty/DBI.pm
44 SHA1 fcab228fade86231a4a6024bd2c06813bbe4e555 lib/Jifty/DBI/Collection.pm
4545 SHA1 503ca4cf6693580dedf8adee58267532f8467908 lib/Jifty/DBI/Collection/Union.pm
4646 SHA1 bcba77fd2bacf0475aea1de97f57365c8de92ca6 lib/Jifty/DBI/Collection/Unique.pm
4747 SHA1 3ff96d74a769439111fba7b42b0c100d180ba6cd lib/Jifty/DBI/Column.pm
6161 SHA1 b043cbb2d750aa1b93e25718ec563d62b3cf13b8 lib/Jifty/DBI/Handle.pm
6262 SHA1 719a11c911aac5306baa4b44f683aa76261100c7 lib/Jifty/DBI/Handle/Informix.pm
6363 SHA1 338116a45f8eb6bfca5e76e8d3be78fb61fffe81 lib/Jifty/DBI/Handle/ODBC.pm
64 SHA1 960fd0b63f3de11924c5d47a3c0c6d1db105ed5b lib/Jifty/DBI/Handle/Oracle.pm
65 SHA1 d1757e2c992ead86f70f0dfc9c659387dc9600cf lib/Jifty/DBI/Handle/Pg.pm
64 SHA1 8281a163b21bb4a5cb0f2b24ce4a55dab716c408 lib/Jifty/DBI/Handle/Oracle.pm
65 SHA1 754666e0c41143aec23a34ea3326bf4fd1b8a24e lib/Jifty/DBI/Handle/Pg.pm
6666 SHA1 2f4c08340712bd21679282ebd669ce7b99d6d646 lib/Jifty/DBI/Handle/SQLite.pm
6767 SHA1 bba2314c20fcc3ef71cc69090f1cd6bd515cd9b4 lib/Jifty/DBI/Handle/Sybase.pm
6868 SHA1 cf80896a175702a157770f64ae469430678c3357 lib/Jifty/DBI/Handle/mysql.pm
119119 SHA1 97e60dd523a74a886c170eeb05b813aa551f5efe t/testmodels.pl
120120 SHA1 653c2f961d8b4f195e5391cd261f37815068e8d5 t/utils.pl
121121 -----BEGIN PGP SIGNATURE-----
122 Version: GnuPG v1.4.10 (GNU/Linux)
122 Version: GnuPG v1.4.10 (Darwin)
123123
124 iD8DBQFNa8XhHdv9ZfNcOAcRAmUeAJ4zMQK4gRNn+i7pu3EzlZN2jhXkpQCfcgER
125 Z8gawoecAhAUhGjBuFm0yAM=
126 =1fkV
124 iEYEARECAAYFAk2nHj0ACgkQsxfQtHhyRPrWkQCfc7CyLd/KO0JgsR6RKGRhlkkh
125 gyYAnioe5ZVx9iTThRBm2gmhnDZEDgfy
126 =JFMa
127127 -----END PGP SIGNATURE-----
12521252
12531253 # }}}
12541254
1255 # Set this to the name of the column and the alias, unless we've been
1256 # handed a subclause name
1257
1258 my $qualified_column
1259 = $args{'alias'}
1260 ? $args{'alias'} . "." . $args{'column'}
1261 : $args{'column'};
1262 my $clause_id = $args{'subclause'} || $qualified_column;
1263
12641255 # $column_obj is undefined when the table2 argument to the join is a table
12651256 # name and not a collection model class. In that case, the class key
12661257 # doesn't exist for the join.
12761267 column => $column_obj,
12771268 value_ref => \$args{'value'},
12781269 ) if $column_obj && $column_obj->encode_on_select && $args{operator} !~ /IS/;
1270
1271 # Ensure that the column has nothing fishy going on. We can't
1272 # simply check $column_obj's truth because joins mostly join by
1273 # table name, not class, and we don't track table_name -> class.
1274 if ($args{column} =~ /\W/) {
1275 warn "Possible SQL injection on column '$args{column}' in limit at @{[join(',',(caller)[1,2])]}\n";
1276 %args = (
1277 %args,
1278 column => 'id',
1279 operator => '<',
1280 value => 0,
1281 );
1282 }
1283 if ($args{operator} !~ /^(=|<|>|!=|<>|<=|>=
1284 |(NOT\s*)?LIKE
1285 |(NOT\s*)?(STARTS|ENDS)_?WITH
1286 |(NOT\s*)?MATCHES
1287 |IS(\s*NOT)?
1288 |IN)$/ix) {
1289 warn "Unknown operator '$args{operator}' in limit at @{[join(',',(caller)[1,2])]}\n";
1290 %args = (
1291 %args,
1292 column => 'id',
1293 operator => '<',
1294 value => 0,
1295 );
1296 }
1297
1298
1299 # Set this to the name of the column and the alias, unless we've been
1300 # handed a subclause name
1301 my $qualified_column
1302 = $args{'alias'}
1303 ? $args{'alias'} . "." . $args{'column'}
1304 : $args{'column'};
1305 my $clause_id = $args{'subclause'} || $qualified_column;
1306
12791307
12801308 # make passing in an object DTRT
12811309 my $value_ref = ref( $args{value} );
13071335 #since we're changing the search criteria, we need to redo the search
13081336 $self->redo_search();
13091337
1310 if ( $args{'column'} ) {
1311
1312 #If it's a like, we supply the %s around the search term
1313 if ( $args{'operator'} =~ /MATCHES/i ) {
1314 $args{'value'} = "%" . $args{'value'} . "%";
1315 } elsif ( $args{'operator'} =~ /STARTS_?WITH/i ) {
1316 $args{'value'} = $args{'value'} . "%";
1317 } elsif ( $args{'operator'} =~ /ENDS_?WITH/i ) {
1318 $args{'value'} = "%" . $args{'value'};
1319 }
1320 $args{'operator'} =~ s/(?:MATCHES|ENDS_?WITH|STARTS_?WITH)/LIKE/i;
1321
1322 #if we're explicitly told not to to quote the value or
1323 # we're doing an IS or IS NOT (null), don't quote the operator.
1324
1325 if ( $args{'quote_value'} && $args{'operator'} !~ /IS/i ) {
1326 if ( $value_ref eq 'ARRAY' ) {
1327 map { $_ = $self->_handle->quote_value($_) } @{ $args{'value'} };
1328 } else {
1329 $args{'value'} = $self->_handle->quote_value( $args{'value'} );
1330 }
1338 #If it's a like, we supply the %s around the search term
1339 if ( $args{'operator'} =~ /MATCHES/i ) {
1340 $args{'value'} = "%" . $args{'value'} . "%";
1341 } elsif ( $args{'operator'} =~ /STARTS_?WITH/i ) {
1342 $args{'value'} = $args{'value'} . "%";
1343 } elsif ( $args{'operator'} =~ /ENDS_?WITH/i ) {
1344 $args{'value'} = "%" . $args{'value'};
1345 }
1346 $args{'operator'} =~ s/(?:MATCHES|ENDS_?WITH|STARTS_?WITH)/LIKE/i;
1347
1348 # Force the value to NULL (non-quoted) if the operator is IS.
1349 if ($args{'operator'} =~ /^IS(\s*NOT)?$/i) {
1350 $args{'quote_value'} = 0;
1351 $args{'value'} = 'NULL';
1352 }
1353
1354 # Quote the value
1355 if ( $args{'quote_value'} ) {
1356 if ( $value_ref eq 'ARRAY' ) {
1357 map { $_ = $self->_handle->quote_value($_) } @{ $args{'value'} };
1358 } else {
1359 $args{'value'} = $self->_handle->quote_value( $args{'value'} );
13311360 }
13321361 }
13331362
16661695 } elsif ( ( defined $rowhash{'alias'} )
16671696 and ( $rowhash{'column'} ) )
16681697 {
1698 if ($rowhash{'column'} =~ /\W/) {
1699 warn "Possible SQL injection in column '$rowhash{column}' in order_by\n";
1700 next;
1701 }
16691702
16701703 $clause .= ( $clause ? ", " : " " );
16711704 $clause .= $rowhash{'function'} . "(" if $rowhash{'function'};
17501783 } elsif ( ( $rowhash{'alias'} )
17511784 and ( $rowhash{'column'} ) )
17521785 {
1786 if ($rowhash{'column'} =~ /\W/) {
1787 warn "Possible SQL injection in column '$rowhash{column}' in group_by\n";
1788 next;
1789 }
17531790
17541791 $clause .= ( $clause ? ", " : " " );
17551792 $clause .= $rowhash{'alias'} . ".";
250250 = [ @{ $collection->{group_by} || [] }, { column => 'id' } ];
251251 local $collection->{order_by} = [
252252 map {
253 ( $_->{alias} and $_->{alias} ne "main" )
254 ? { %{$_}, column => "min(" . $_->{column} . ")" }
255 : $_
253 my $alias = $_->{alias} || '';
254 my $column = $_->{column};
255 if ($column =~ /\W/) {
256 warn "Possible SQL injection in column '$column' in order_by\n";
257 next;
258 }
259 $alias .= '.' if $alias;
260
261 ( ( !$alias or $alias eq 'main.' ) and $column eq 'id' )
262 ? $_
263 : { %{$_}, column => undef, function => "min($alias$column)" }
256264 } @{ $collection->{order_by} }
257265 ];
258266 my $group = $collection->_group_clause;
259267 my $order = $collection->_order_clause;
260268 $$statementref
261 = "SELECT main.* FROM ( SELECT main.id FROM $$statementref $group $order ) distinctquery, $table main WHERE (main.id = distinctquery.id)";
269 = "SELECT "
270 . $collection->query_columns
271 . " FROM ( SELECT main.id FROM $$statementref $group $order ) distinctquery, $table main WHERE (main.id = distinctquery.id)";
262272 } else {
263273 $$statementref
264 = "SELECT main.* FROM ( SELECT DISTINCT main.id FROM $$statementref ) distinctquery, $table main WHERE (main.id = distinctquery.id) ";
274 = "SELECT "
275 . $collection->query_columns
276 . " FROM ( SELECT DISTINCT main.id FROM $$statementref ) distinctquery, $table main WHERE (main.id = distinctquery.id) ";
265277 $$statementref .= $collection->_group_clause;
266278 $$statementref .= $collection->_order_clause;
267279 }
209209 map {
210210 my $alias = $_->{alias} || '';
211211 my $column = $_->{column};
212 if ($column =~ /\W/) {
213 warn "Possible SQL injection in column '$column' in order_by\n";
214 next;
215 }
212216 $alias .= '.' if $alias;
213217
214 #warn "alias $alias => column $column\n";
215218 ( ( !$alias or $alias eq 'main.' ) and $column eq 'id' )
216219 ? $_
217 : { %{$_}, alias => '', column => "min($alias$column)" }
220 : { %{$_}, column => undef, function => "min($alias$column)" }
218221 } @{ $collection->{order_by} }
219222 ];
220223 my $group = $collection->_group_clause;
11 use warnings;
22 use strict;
33
4 $Jifty::DBI::VERSION = '0.67';
4 $Jifty::DBI::VERSION = '0.68';
55
66 =head1 NAME
77