[svn-upgrade] new version libjifty-dbi-perl (0.68)
Gregor Herrmann
13 years ago
0 | 0 | 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) | |
1 | 15 | |
2 | 16 | 0.67 2011-02-28 |
3 | 17 | - Features: |
46 | 46 | version: 0 |
47 | 47 | resources: |
48 | 48 | license: http://dev.perl.org/licenses/ |
49 | version: 0.67 | |
49 | version: 0.68 |
14 | 14 | Hash: SHA1 |
15 | 15 | |
16 | 16 | SHA1 418a58763132c9a476627cbdce5ff01395ce84d4 .gitignore |
17 | SHA1 45d9eaf8a622fdfc0bb9680396e2843eca5ec346 Changes | |
17 | SHA1 59a52f546dcd1cd87813bc59babf7b1cd32ac2d3 Changes | |
18 | 18 | SHA1 c2fb135f967d7093a6191d1b7e5e596e30040246 MANIFEST |
19 | SHA1 f21d5f2dc45943fbc09ac079b2b18d942a6f3f81 META.yml | |
19 | SHA1 da76cdd7f1c89f107d3d5c9608aff9f886e503f8 META.yml | |
20 | 20 | SHA1 48bd6ca8a37ec79b7cae91028d7e9489ad33a03b Makefile.PL |
21 | 21 | SHA1 e29d7b270f78a5a406921571b08290c46f2a42f6 README |
22 | 22 | SHA1 82d6ac3f6def48558d09f8b6e3b53ed4194d8c81 ROADMAP |
40 | 40 | SHA1 026cc0551a0ad399d195e395b46bdf842e115192 inc/Module/Install/Metadata.pm |
41 | 41 | SHA1 5457015ea5a50e93465bf2dafa29feebd547f85b inc/Module/Install/Win32.pm |
42 | 42 | 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 | |
45 | 45 | SHA1 503ca4cf6693580dedf8adee58267532f8467908 lib/Jifty/DBI/Collection/Union.pm |
46 | 46 | SHA1 bcba77fd2bacf0475aea1de97f57365c8de92ca6 lib/Jifty/DBI/Collection/Unique.pm |
47 | 47 | SHA1 3ff96d74a769439111fba7b42b0c100d180ba6cd lib/Jifty/DBI/Column.pm |
61 | 61 | SHA1 b043cbb2d750aa1b93e25718ec563d62b3cf13b8 lib/Jifty/DBI/Handle.pm |
62 | 62 | SHA1 719a11c911aac5306baa4b44f683aa76261100c7 lib/Jifty/DBI/Handle/Informix.pm |
63 | 63 | 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 | |
66 | 66 | SHA1 2f4c08340712bd21679282ebd669ce7b99d6d646 lib/Jifty/DBI/Handle/SQLite.pm |
67 | 67 | SHA1 bba2314c20fcc3ef71cc69090f1cd6bd515cd9b4 lib/Jifty/DBI/Handle/Sybase.pm |
68 | 68 | SHA1 cf80896a175702a157770f64ae469430678c3357 lib/Jifty/DBI/Handle/mysql.pm |
119 | 119 | SHA1 97e60dd523a74a886c170eeb05b813aa551f5efe t/testmodels.pl |
120 | 120 | SHA1 653c2f961d8b4f195e5391cd261f37815068e8d5 t/utils.pl |
121 | 121 | -----BEGIN PGP SIGNATURE----- |
122 | Version: GnuPG v1.4.10 (GNU/Linux) | |
122 | Version: GnuPG v1.4.10 (Darwin) | |
123 | 123 | |
124 | iD8DBQFNa8XhHdv9ZfNcOAcRAmUeAJ4zMQK4gRNn+i7pu3EzlZN2jhXkpQCfcgER | |
125 | Z8gawoecAhAUhGjBuFm0yAM= | |
126 | =1fkV | |
124 | iEYEARECAAYFAk2nHj0ACgkQsxfQtHhyRPrWkQCfc7CyLd/KO0JgsR6RKGRhlkkh | |
125 | gyYAnioe5ZVx9iTThRBm2gmhnDZEDgfy | |
126 | =JFMa | |
127 | 127 | -----END PGP SIGNATURE----- |
1252 | 1252 | |
1253 | 1253 | # }}} |
1254 | 1254 | |
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 | ||
1264 | 1255 | # $column_obj is undefined when the table2 argument to the join is a table |
1265 | 1256 | # name and not a collection model class. In that case, the class key |
1266 | 1257 | # doesn't exist for the join. |
1276 | 1267 | column => $column_obj, |
1277 | 1268 | value_ref => \$args{'value'}, |
1278 | 1269 | ) 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 | ||
1279 | 1307 | |
1280 | 1308 | # make passing in an object DTRT |
1281 | 1309 | my $value_ref = ref( $args{value} ); |
1307 | 1335 | #since we're changing the search criteria, we need to redo the search |
1308 | 1336 | $self->redo_search(); |
1309 | 1337 | |
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'} ); | |
1331 | 1360 | } |
1332 | 1361 | } |
1333 | 1362 | |
1666 | 1695 | } elsif ( ( defined $rowhash{'alias'} ) |
1667 | 1696 | and ( $rowhash{'column'} ) ) |
1668 | 1697 | { |
1698 | if ($rowhash{'column'} =~ /\W/) { | |
1699 | warn "Possible SQL injection in column '$rowhash{column}' in order_by\n"; | |
1700 | next; | |
1701 | } | |
1669 | 1702 | |
1670 | 1703 | $clause .= ( $clause ? ", " : " " ); |
1671 | 1704 | $clause .= $rowhash{'function'} . "(" if $rowhash{'function'}; |
1750 | 1783 | } elsif ( ( $rowhash{'alias'} ) |
1751 | 1784 | and ( $rowhash{'column'} ) ) |
1752 | 1785 | { |
1786 | if ($rowhash{'column'} =~ /\W/) { | |
1787 | warn "Possible SQL injection in column '$rowhash{column}' in group_by\n"; | |
1788 | next; | |
1789 | } | |
1753 | 1790 | |
1754 | 1791 | $clause .= ( $clause ? ", " : " " ); |
1755 | 1792 | $clause .= $rowhash{'alias'} . "."; |
250 | 250 | = [ @{ $collection->{group_by} || [] }, { column => 'id' } ]; |
251 | 251 | local $collection->{order_by} = [ |
252 | 252 | 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)" } | |
256 | 264 | } @{ $collection->{order_by} } |
257 | 265 | ]; |
258 | 266 | my $group = $collection->_group_clause; |
259 | 267 | my $order = $collection->_order_clause; |
260 | 268 | $$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)"; | |
262 | 272 | } else { |
263 | 273 | $$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) "; | |
265 | 277 | $$statementref .= $collection->_group_clause; |
266 | 278 | $$statementref .= $collection->_order_clause; |
267 | 279 | } |
209 | 209 | map { |
210 | 210 | my $alias = $_->{alias} || ''; |
211 | 211 | my $column = $_->{column}; |
212 | if ($column =~ /\W/) { | |
213 | warn "Possible SQL injection in column '$column' in order_by\n"; | |
214 | next; | |
215 | } | |
212 | 216 | $alias .= '.' if $alias; |
213 | 217 | |
214 | #warn "alias $alias => column $column\n"; | |
215 | 218 | ( ( !$alias or $alias eq 'main.' ) and $column eq 'id' ) |
216 | 219 | ? $_ |
217 | : { %{$_}, alias => '', column => "min($alias$column)" } | |
220 | : { %{$_}, column => undef, function => "min($alias$column)" } | |
218 | 221 | } @{ $collection->{order_by} } |
219 | 222 | ]; |
220 | 223 | my $group = $collection->_group_clause; |