[ic] sql filter not 100% safe for MySQL

Mike Heins mike at perusion.com
Sat Jul 24 23:15:09 EDT 2004

Quoting Daniel Davenport (ddavenport at newagedigital.com):
> > [mailto:interchange-users-bounces at icdevgroup.org]On Behalf Of Mike Heins
> > Quoting John:
> > > Perhaps [query] won't execute 2 SQL statements separated by a semi-
> > > colon? So perhaps there is no risk of SQL injection?? But, it is
> > > possible to create a bad SQL statement in this way and so generate
> > > an error.
> >
> > Query will not execute two statements, but it would certainly be
> > possible to create a subquery situation.
> >
> > I wonder if MySQL has a way to ensure that \' is not interpreted as
> > a single quote? That would be the best way to solve this.
> It might be the easiest way outside of interchange, if it exists at
> all...but the mysql docs don't mention whether it exists, and my tests
> indicate that even "--sql-mode=ANSI_QUOTES" doesn't seem to disable
> backspace quoting (on mysql 4.0.17-max/win32...ymmv).

ANSI_QUOTES just means that you can't use double quotes to surround
a string literal.

> Would it be difficult to add a "table" parameter to the sql filter? If
> set, the parameter would indicate which table the query will end up
> going to. The filter could then tell the appropriate DB handler to
> quote the value, thereby making it safe for any DBI table that
> interchange knows about.

You could do [filter op="sql.table"]....

CodeDef sql Filter 1
CodeDef sql Routine <<EOR
sub {
	my($val, undef, $table) = @_;
	my $db;
	my $mysql = 1;
	if($table and $db = dbref($table)) {
		$mysql = $db->config('DSN') =~ /^dbi:+mysql/i;

	if($mysql) {
	    my %lit = ( '\\\\' => '\\', '\\\'' => "'" );
	    $val =~ s/(\\.)/$lit{$1} || $1/eg;
	$val =~ s/'/''/g;
	return $val;

That makes:

    [filter op=sql.products]'The don\'t will do'[/filter]<br>
    [filter op=sql.variable]'The don\'t will do'[/filter]<br>


    ''The don''t will do''
    ''The don\''t will do''

> Short of that, the only purely interchange solution might be to
> implement a mysql filter. That's ugly, though, as it requires that the
> coder always specify which tables are which types, and that could
> potentially make it a huge mess to move tables from one db type to
> another.
> There is another way, but it's not very pretty, and it's an all-or-
> nothing
> deal.
> $data =~ s/(['"\\<>&\[])(?{local $__ord = ord($1)})/&#$__ord;/;
> This will html-entity-ify quotes, backslashes, and HTML/ITL special
> characters all in one shot. You can change which characters are escaped by
> modifying the list inside the brackets.  (Don't mess with '&', though, or
> you won't be able to reliably unmangle your data.)  One side benefit of this
> type of escaping is that you can filter the HTML characters <>"& as well, so
> that's one problem to worry less about--all the browsers i've dealt with
> display the characters correctly, and even pass the unescaped sequence back
> when forms are submitted.
> To unmangle it...
> $data =~ s/&#(\d+);(?{local $__chr = chr($1)})/$__chr/;
> Data mangled in this fashion won't be easily searchable unless you can
> mangle your search strings the same way.

I don't think this is the issue so much as what the decoded variable
value comes out to.

Hmm. This is decidedly inconvenient behavior for MySQL -- a case of
a convenience method coming back to bite you.

I would like to allow

		sql="select field from table where foo = ? and bar = ?"
		arg.0="[cgi foo]"
		arg.1="[cgi bar]"

but unfortunately the array-based args don't handle included ITL.
This would be the safest way to do it -- to have DBI do the quoting
for you as needed.

I will think about this and see if an epiphany happens. Until then,
defining a mysql filter is probably the way to go.

Mike Heins
Perusion -- Expert Interchange Consulting    http://www.perusion.com/
phone +1.765.647.1295  tollfree 800-949-1889 <mike at perusion.com>

Prove you aren't stupid.  Say NO to Passport.

More information about the interchange-users mailing list