2014-04-29 5 views
4

J'ai reçu un script de base de données qui recherche des ID en double, quand on lui donne un ID, un nom de famille et un prénom. Voici la viande et les pommes de terre de celui-ci:Bash - Échapper à des guillemets simples

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") 

fonctionne très bien, sauf quand la dernière ou le prénom a une apostrophe en elle, comme « O'Neil ». J'ai essayé d'échapper à une instance de «avec», et n'ont pas encore rencontré de succès. J'ai passé toute la journée à chercher sur les forums, et j'ai essayé différentes variantes, mais je n'ai toujours pas ajouté un \ devant chaque '.

Voici ce que je suis arrivé à ce jour:

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

# Output 

O'Neil 
Robert 

Comme toujours, merci à l'avance!

+0

Qu'est-ce que le 'echo | chose sed? Bash a intégré des opérateurs d'expansion de paramètre pour effectuer la manipulation de chaîne; par exemple, vous pouvez exécuter: 'in =" '"; out = "\\ '"; escaped_lname = $ {lname // $ in/$ out} ', et ce sera beaucoup plus rapide et efficace que d'essayer de jouer avec sed. –

+0

... Notez également que les majuscules et les minuscules sont classiques pour les variables d'environnement et les variables internes. Les variables locales à votre script doivent contenir au moins un caractère minuscule pour éviter les collisions d'espaces de noms avec ces classes. –

+1

Rappelez-vous [Little Bobby Tables] (http://xkcd.com/327/)! –

Répondre

1

Ceci est la mauvaise façon de passer une commande complexe:

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

Au lieu de cela, les tableaux d'utilisation:

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}'") 

... et puis en utilisant "${dup_id[@]}" pour exécuter votre commande vous protéger de la coquille bogues d'injection. n'est pas garanti pour vous protéger des attaques par injection SQL (il y a trop de façons de les effectuer, et les bases de données ont trop d'idiosyncrasies autour de la conversion du jeu de caractères pour faire confiance à l'échappement basé sur le remplacement des caractères), mais, bien, c'est pourquoi les gens qui sont préoccupés par l'exactitude ou la sécurité utilisent des langages qui prennent en charge les paramètres de liaison - un ensemble dont bash n'est pas un membre - pour générer des requêtes SQL. Voir aussi BashFAQ #50, et la page BashWeaknesses du wiki de la chaîne #bash de freenode.org - cette dernière appelle explicitement la génération SQL comme une tâche pour laquelle bash est inapte.

+0

Grande réponse sauf que vous devez échapper des guillemets simples en les doublant. – Jeff

+0

@ Jeff, hein? '' '' dans bash est exactement le même que de ne pas avoir de guillemets du tout. Essayez-le: 'printf '% s \ n' '' * ''' imprime tous les noms de fichiers dans le répertoire local, exactement comme 'printf '% s \ n' *', plutôt que d'imprimer un '*' entouré de littéral unique -quotes –

+0

@Jeff, ... si vous faites référence à la citation ** sql ** correcte par opposition à la citation de bash, vous pourriez bien avoir raison que 'escaped_single_quote =" '' "' serait plus correct - mais cela signifierait que la question elle-même demande la mauvaise chose, puisque le PO demande explicitement comment ajouter des barres obliques inversées, pas comment doubler les guillemets ou (plus généralement) générer des guillemets SQL corrects pour les chaînes. –

2
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[*]}" 
+1

Neat, et une des rares fois où il est correct d'utiliser '" $ {array [*]} "' plutôt que '" $ {array [@]} "'. –

+0

@JonathanLeffler bien que j'utilise toujours '*' quand je peux, c'est "plus simple" mais la plupart des gens ne comprennent pas la différence je pense –

+0

Vous pouvez protéger contre [Little Bobby Tables] (http://xkcd.com/327/) en utilisant '$ {_ LNAME // \ '/' '}' pour développer des guillemets simples dans le nom en guillemets simples doublés. Je vais travailler, un jour, pourquoi vous avez besoin de la barre oblique inverse dans la partie de recherche de cela et non dans la partie de remplacement. –

Questions connexes