In DBIx::Class case insensitve substring search., chrestomanci encounters a problem using LOWER(me.name) as a field name while using the quote_char (or perhaps newer quote_names) option. This inspired me to dig into escaping of identifiers (in particular, protection against injection) in DBIx::Class.

Consider a simple table "hash" with two text columns, "key" and "value". Simple code to set up an SQLite table and populate it with three rows below.

NOTE: unlinks and creates file called "test.sqlite" in current directory.

package MyApp::Schema::Result::Hash; use base qw/DBIx::Class::Core/; __PACKAGE__->table('hash'); __PACKAGE__->add_columns(qw/ key value /); __PACKAGE__->set_primary_key('key'); 1; package MyApp::Schema; use base qw/DBIx::Class::Schema/; __PACKAGE__->register_class(Hash => "MyApp::Schema::Result::Hash"); 1; package main; use warnings; use strict; use 5.010; use DBI; my $DB_FILE = "test.sqlite"; unlink $DB_FILE; my @DSN = ("dbi:SQLite:dbname=$DB_FILE","","", { AutoCommit => 1, Rais +eError => 1 }); DBI->connect(@DSN)->do($_) for split /\n/, <<'INIT'; CREATE TABLE hash (key text, value text); INSERT INTO hash VALUES ('foo', 'FOO'); INSERT INTO hash VALUES ('bar', 'BAR'); INSERT INTO hash VALUES ('baz', 123); INIT

We can see that, by default, DBIx::Class does not protect against SQL injection in identifiers:

my $schema = MyApp::Schema->connect(@DSN); my $hash = $schema->resultset("Hash"); my $good_key = "key"; say $hash->search({ $good_key => "foo" })->count; ## executes: SELECT COUNT( * ) FROM hash me WHERE ( key = ? ): 'foo' ## says 1 my $evil_key = "1 = 1 ) --"; say $hash->search({ $evil_key => "foo" })->count; ## executes: SELECT COUNT( * ) FROM hash me WHERE ( 1 = 1 ) -- = ? ): + 'foo' ## says 3

SQL::Abstract and DBIx::Class have a quote_char option (newer DBIx::Class recommends quote_names instead). These options will cause identifiers to be quoted. The intention is to protect against column names which may be keywords in SQL.

$schema->storage->sql_maker->quote_char('"'); say $hash->search({ $evil_key => "foo" })->count; ## executes: SELECT COUNT( * ) FROM "hash" "me" WHERE ( "1 = 1 ) --" += ? ): 'foo' ## says 0

The quote_*, however, do not provide injection protection (at least to my standards) as they simply perform the naïve quoting.

my $evil_key2 = 'key" = "key" ) -- '; say $hash->search({ $evil_key2 => "foo" })->count; ## executes: SELECT COUNT( * ) FROM "hash" "me" WHERE ( "key" = "key" + ) -- " = ? ): 'foo' ## says 3

Proper quoting for injection protection can only (as far as I can tell) be performed via quote_identifier on the DBI storage object

$schema->storage->sql_maker->quote_char(undef); my $Q_evil_key2 = $schema->storage->dbh->quote_identifier($evil_key2); say $hash->search({ $Q_evil_key2 => "foo" })->count; ## executes: SELECT COUNT( * ) FROM hash me WHERE ( "key"" = ""key"" +) -- " = ? ): 'foo' ## says 0

Is it true that there is no fully automated injection protection for identifiers in SQL::Abstract / DBIx::Class? Would it be reasonable to post a bug / wishlist item against SQL::Abstract and DBIx::Class requeesting a quote_identifiers option or some such (to be used like quote_names) that performs the more robust quoting? Am I dumb and just simply missing something?

Good Day,
    Dean


In reply to DBIx::Class field name (identifier) injections by duelafn

Title:
Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post, it's "PerlMonks-approved HTML":



  • Posts are HTML formatted. Put <p> </p> tags around your paragraphs. Put <code> </code> tags around your code and data!
  • Titles consisting of a single word are discouraged, and in most cases are disallowed outright.
  • Read Where should I post X? if you're not absolutely sure you're posting in the right place.
  • Please read these before you post! —
  • Posts may use any of the Perl Monks Approved HTML tags:
    a, abbr, b, big, blockquote, br, caption, center, col, colgroup, dd, del, details, div, dl, dt, em, font, h1, h2, h3, h4, h5, h6, hr, i, ins, li, ol, p, pre, readmore, small, span, spoiler, strike, strong, sub, summary, sup, table, tbody, td, tfoot, th, thead, tr, tt, u, ul, wbr
  • You may need to use entities for some characters, as follows. (Exception: Within code tags, you can put the characters literally.)
            For:     Use:
    & &amp;
    < &lt;
    > &gt;
    [ &#91;
    ] &#93;
  • Link using PerlMonks shortcuts! What shortcuts can I use for linking?
  • See Writeup Formatting Tips and other pages linked from there for more info.