2010-12-15 24 views
10

Używam skryptu powłoki do komunikowania się z bazą danych MySQL. MySQL obsługuje określając kwerendy jako argument powłoki, tak:Jak zapobiec iniekcji SQL w interfejsie powłoki linii poleceń MySQL?

mysql my_db -B -N -e "select id from Table" 

Jednak jeśli mam parametr, który chciałbym użyć w zapytaniu, w jaki sposób mogę uzyskać ochronę przed atakami wtryskowych?

Naiwny sposobem jest po prostu wkleić wartość zmiennej na żądanie, ale nie jest to bardzo bezpieczny:

mysql my_db -B -N -e "select id from Table where name='$PARAM'" 

Czy są jakieś triki lub udokumentowane interfejsy do wstrzyknięciem bezpieczny kwerend z wiersza polecenia?

+0

Czy aplikacja internetowa przekazuje te "parametry" do skryptu powłoki? Sugerowałbym przeglądanie czyszczenia danych w aplikacji internetowej. – Jakub

Odpowiedz

0

Twoja aplikacja może zostać zaatakowana przez SQL Injection za każdym razem, gdy konstruujesz SQL, łącząc parametry (jak w twoim przykładzie). Istnieje zapis o tym na Wikipedii pod tym linkiem: http://en.wikipedia.org/wiki/SQL_injection

Podejrzewam, że będziesz chciał napisać filtr unixowy do skonstruowania zapytania SQL za pomocą funkcji mysql_real_escape_string wspomnianej w tym artykule.

Rozważ przekazanie SQL jako pierwszego parametru i zmiennej (zmiennych) jako kolejnych parametrów, a następnie zwróć skonstruowany kod SQL. Jeśli nazwa filtru „blobbo” polecenia jak za Twój przykład może wyglądać następująco:

blobbo „select id z tabeli gdzie name =% s” $ PARAM

0

nie tylko w celu ochrony przed SQL injection , ale także przeciwko wstrzykiwaniu skorupy. Możesz napisać zapytanie (po oczyszczeniu dowolnych dynamicznych części) do pliku, a następnie przekierować ten plik do mysql, zamiast mieć nadzieję, że zapytanie nie złamie powłoki. Rozważmy:

PARAM="name'\"; rm -rf/; echo 'pwn3d U" 

staje

mysql my_db -B -N -e "select id from Table where name='name'"; rm -rf/; echo 'pwn3d U' 

lub:

command 1: mysql my_db -B -N -e "select id from Table where name='name'" 
command 2: rm -rf/
command 3: echo 'pwn3d U' 

Zamiast zrobić coś takiego:

cat <<EOT > query.sql 
select .... blah blaah blah .... sanitized query here 
EOT 
mysql my_db -B -N < query.sql 

To uniemożliwiłoby żadnych danych określonych przez użytkownika z pojawiania w obrębie powłoki polecenie to samodzielnie, zapobiegaj co najmniej jednemu poziomowi podatności na wstrzyknięcia. Ale nadal musisz poradzić sobie z problemem SQL injection.

+0

Dziękuję za wspomnienie tego rodzaju problemu. Jednak kod zamieszczony w pytaniu * jest * chroniony przed iniekcją powłoki - jeśli jest wykonywany przez samą powłokę. Tylko wtedy, gdy wywołuję polecenie z innego skryptu (którego nie używam), na przykład: 'system (" mysql -e '$ PARAM' ");' ma tego rodzaju lukę. –

5

Można zakodować kod base64, a następnie dekodować go base64, gdy jest już w MySQL. W MySQL istnieją funkcje UDF do konwertowania danych Base64 na zwykłe dane. Ponadto większość systemów posiada albo kodowanie uuencode, albo polecenie "base64" dla danych kodowania base64.

+0

Świetna odpowiedź, przykład może również pomóc: 'ENKODED = $ (echo 1 $ | base64); echo "SELECT * FROM T WHERE V = FROM_BASE64 (" $ ENKODED ");" | mysql' – brablc

0

Odpowiedź Sargun Dhillon wskazała mi właściwy kierunek. Niestety FROM_BASE64 jest niedostępny przed MySQL 5.6, więc poszedłem z UNHEX.

Poniższy skrypt jest przykładem do sprawdzania szczegółów użytkownika Redmine z powłoki. Nadal nie spałbym dobrze, gdyby niezaufani użytkownicy mieli dostęp do tego skryptu, ale w moim przypadku jest on wystarczająco bezpieczny. (Jest również ograniczony do wartości łańcuchowych i nie powinieneś mieć w zapytaniu znaku zapytania, ale te ograniczenia są ze mną w porządku.)

#!/bin/bash 

MYSQL_OPTS='--defaults-file=/etc/redmine/mysql.cnf' 

mysql_query() { 
    local db=$1 
    local sql=$2 
    shift 2 || return 1 
    declare -a args=("[email protected]") 

    sql=${sql//[%]/%%} 
    sql=${sql//[?]/UNHEX('%s')} 
    for ((i=0; i<${#args[@]}; i++)); do 
    args[$i]=$(echo -n "${args[$i]}" | hexdump -v -e '/1 "%02X"') 
    done 
    sql=$(printf "$sql" "${args[@]}") 
    mysql $MYSQL_OPTS "$db" -e "$sql" || return $? 
} 

for u in "[email protected]"; do 
    mysql_query redmine 'select * from users where login=?\G' "$u" 
done 

W przypadku wykrycia jakiegokolwiek pominięcia SQL lub Shell, które przegapiłem, proszę o komentarz.

Powiązane problemy