Question

I got a database script that searches for duplicate IDs, when given a certain ID, last name, and first-name. Here are the meat and potatoes of it:

PSQL="psql -p $PGPORT -h $DBHOST -d $DB -tAc "

DUP_ID=$($PSQL "SELECT id FROM inmate WHERE id NOT SIMILAR TO '(0*)${1}' AND lastname ILIKE '${_LNAME}' AND firstname ILIKE '${_FNAME}' LIMIT 1")

Works great, except when either the last or first name has an apostrophe in it, such as "O'Neil". I've attempted to escape any instance of ' with \', and have not yet met with success. I've spent all day searching the forums, and tried different variations on my own, but it still will not add a \ in front of every '.

Here's what I got so far:

local _LNAME=`echo "${2}" | sed "s/'/\\\'/g"`
local _FNAME=`echo "${3}" | sed "s/'/\\\'/g"`
echo -e $_LNAME
echo -e $_FNAME

# Output

O'Neil
Robert

As always, thanks in advance!

Was it helpful?

Solution 2

This is the wrong way to pass a complex command:

PSQL="psql -p $PGPORT -h $DBHOST -d $DB -tAc "

Instead, use arrays:

single_quote="'"
escaped_single_quote="\\'"
quoted_fname=${1//$single_quote/$escaped_single_quote}
quoted_lname=${2//$single_quote/$escaped_single_quote}
psql=( psql -p "$PGPORT" -h "$DBHOST" -d "$DB" -tAc )
dup_id=( "${psql[@]}" "SELECT id FROM ... WHERE ... '${quoted_lname}'" )

...and then using "${dup_id[@]}" to run your command will protect you from shell injection bugs. It isn't guaranteed to protect you from SQL injection attacks (there are too many ways to perform those, and databases have too many idiosyncrasies around character set conversion, to trust the simple character-replacement-based escaping used here against hostile data), but, well, that's why folks who are concerned about correctness or security use languages that support bind parameters -- a set of which bash is not a member -- for generating SQL queries.

See also BashFAQ #50, and the BashWeaknesses page from the freenode.org #bash channel's wiki -- the latter of which explicitly calls out SQL generation as a task for which bash is unfit.

OTHER TIPS

QUERY=(
  SELECT id FROM inmate WHERE
  id NOT SIMILAR TO "'(0*)$1'" AND
  lastname ILIKE "'$_LNAME'" AND
  firstname ILIKE "'$_FNAME'" LIMIT 1
)
psql -p $PGPORT -h $DBHOST -d $DB -tAc "${QUERY[*]}"
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top