Zapytania SQL - kwestia bezpieczeństwa

0

Witam,
Mam troszkę pytań i proszę o udzielenie odpowiedzi, jeżeli ktoś ma chwilę i może pomóc :)
Będą mi bardzo potrzebne, ponieważ chciałbym zrobić w miarę 'bezpieczną' strone pod względem ataków na nią.
Przeglądałem wiele artykułów i są bardzo zróżnicowane odpowiedzi,dlatego proszę o wyrozumiałość.

Przykład 1.

if (isset($_POST['username'])) 
{
    $username = $_POST['username'];
    $query=$db->prepare('SELECT * FROM users where userName = :username');
    $query->bindValue(':username', $username);
    $query->execute();
    $result = $query -> fetchAll(PDO::FETCH_COLUMN);
    $query->closeCoursor();    

    foreach($result as $info) 
    {
        echo 'Nick username  : '.htmlspecialchars($info['name']) . '</br>';
        echo 'ID usera : '.htmlspecialchars($info['id']) . '<hr>';
    }
}

Pytania.

  1. Czy jak jest jakaś reguła żeby stosować przy robieniu zapytania po nawiasie pojedynczego apostrofa (') , podwójnego(") , czy też tzw. ciapka (`) ?
  • przedstawiłem apostrof pojedynczy w przykładzie
  1. Jeśli binduje dane i używam PDO to przed "SQL_Injection" powinienem być bezpieczny?
  2. Czy trzeba dawać apostrofy w zapytaniu jezeli w tym warunku WHERE columna ktora chce filtrowac jest stringem?
    Chodzi mi o to :
$query=$db->prepare('SELECT * FROM users where userName = ":username" ');

A dla inta wtedy nic nie dawać apostrofów?
Czy nie ma to reguły i wystarczy dać w ten sposób :

$query=$db->prepare('SELECT * FROM users where userName = :username ');

// bez apostrofów :username

  1. Czy bindować trzeba wszystkie dane jakie są zarówno wprowadzane do bazy, usuwane, wybierane, czy tez usuwane? (INSER,DELETE,SELECT,DELETE) ?
  2. Czy za każdym razem muszę zamykac kursor?
  3. Czy muszę używać za kazdym razem htmlspecialchars przed wyswietlanym tekstem z bazy, w celu unikniecia ataku XSS?

Ew. inne wskazówki mile widziane
pozdrawiam i proszę o odpowiedzi.

1

' -> to jest apostrof
" -> to jest cudzysłów
` -> to jest backtick i nie kojarzę polskiej nazwy

Apostrofami otaczasz wartości/stringi. Nie cudzysłowiem. W MySQL bodajże tak można, ale chyba tylko w MySQL. Nawet nie wiem, bo standardem jest apostrof.
Backtickami otaczasz nazwy tabel/kolumn.

  1. Tak

  2. Jeżeli używasz binda to nie wpisuj żadnych apostrofów itd. <ins>Pamiętaj tylko o wskazaniu typu zmiennej w bindValue</ins>. W czystym SQL (czasem nie ma potrzeby bawić się z bindem, bo szybciej napisać na sztywno jakąś wartość, oczywiście NIE zmienną (tu zawsze bind)) intów/flatów itd nie otaczaj apostrofami, bo choć powinno to działać, to w skrajnych, pojedynczych, przypadkach może nie zadziałać: https://4programmers.net/Forum/1177344 - tu upewnij się, że nie wstawiasz nulla, bo zapytanie SELECT * FROM tabela WHERE id = (zamiast nulla pusty string) się wywali - najlepiej castuj na oczekiwany typ, np: $sql = 'SELECT [..] WHERE id = '.((int) $id).' AND [...]'; a stringi/daty/itd w apostrofy (oczywiście ręcznie escape'owane).

Oczywiście najbezpieczniej będzie zawsze używać binda, gorzej<ins>trudniej</ins> wtedy o przypadkowe pominięcie jakiegoś szczegółu (np. castowanie przy nullach).

  1. Tak

  2. Jeżeli kod puszcza Cię bez tego to nie. Niektóre drivery PDO (zakładam, że jest to stałe, tj. jeżeli u Ciebie działa z MySQL to gdzieś indziej z MySQL będzie tak samo, ale dopiero np. z bazami FireBird będzie się wywalać --- choć pewności nie mam, PHP to chyba najbardziej zależny od środowiska język :/) wymagają tego, niektóre nie.

  3. Tak

Polecam zainteresować się systemem szablonów, które zajmują się takimi rzeczami automatycznie, nie wymagają też plucia na przemian echo, albo zamykania i otwierania tagów PHP. Filozofia szablonów jest troszkę inna jak u Ciebie w poście, bo w szablonach nie wyświetlasz co chwila danych, tylko najpierw zbierasz do zmiennych wszystko, co chcesz wyświetlić, a potem na jeden raz to wyświetlasz. TWIG jest bardzo dobrym systemem szablonów.

0

__

' -> to jest apostrof
" -> to jest cudzysłów
` -> to jest backtick i nie kojarzę polskiej nazwy

Apostrofami otaczasz wartości/stringi. Nie cudzysłowiem. W MySQL bodajże tak można, ale chyba tylko w MySQL. Nawet nie wiem, bo standardem jest apostrof.
Backtickami otaczasz nazwy tabel/kolumn.

Napisałeś , czym otaczać wartości/stringi + nazwy tabel/kolumn, a co odnośnie samego zapytania? Chodzi mi o to co jest np przed SELECT zaraz po nawiasie.
W moim przykładzie wcześniejszym użyłem apostrofu. Nie ma różnicy czy dam tam apostrof czy cudzysłów?

//////////////////* AKTUALIZACJIA*////////////////
I jeszcze jedno pytanie nasuwa mi sie na myśl.
Jeżeli mam do wybrania z bazy pewien ID , gdzie przy jego filtracji znam jego wartość i chcę ją ustawić na sztywno to też muszę używac

bindValue
czy mogę wtedy wklepać ją bezposrednio do zapytania? Przykład poniżej.

$query=$db->prepare('SELECT * FROM `users` WHERE id = ((int)1) ');

czy muszę zrobić to w następujący sposób...

$query=$db->prepare('SELECT * FROM `users` WHERE id = :id ');
$query->bindValue(':id' , 1);

?_

1

Jeżeli chodzi o tworzenie stringów w PHP to jak Ci wygodniej. Teoretycznie ' są uważane za szybsze, bo nie parsują zmiennych:

$zmienna = 'test';
echo "To jest zmienna: $zmienna".PHP_EOL;
echo 'To jest zmienna: $zmienna";

//Wyświetli:
//To jest zmienna: test
//To jest zmienna: $zmienna

W praktyce jednak różnice są zacieralne, czasami z korzyścią dla podwójnego cudzysłowy.

Najprościej jest podążać za wybranym przez siebie standardem kodowania: http://www.php-fig.org/psr/ - czasami pracodawca nawet taki na Ciebie narzuca. Nie wiem w sumie czy PSR gdzieś mówi o tym w ogóle niestety - nie stosuję się do oficjalnych standardów :(

Niemniej widziałem wskazania, żeby używać podwójnych, bo unikasz escapeowania aposrtofu, który regularnie występuje w języku angielskim:

echo "It's simple!";
echo 'It\'s bad and messy!';
1

Tak jak zauważyłeś, coś na ten temat wspomniałem ;)

dzek69 napisał(a):

W czystym SQL (czasem nie ma potrzeby bawić się z bindem, bo szybciej napisać na sztywno jakąś wartość, oczywiście NIE zmienną (tu zawsze bind)) intów/flatów itd nie otaczaj apostrofami, bo choć powinno to działać, to w skrajnych, pojedynczych, przypadkach może nie zadziałać: https://4programmers.net/Forum/1177344 - tu upewnij się, że nie wstawiasz nulla, bo zapytanie SELECT * FROM tabela WHERE id = (zamiast nulla pusty string) się wywali - najlepiej castuj na oczekiwany typ, np: $sql = 'SELECT [..] WHERE id = '.((int) $id).' AND [...]'; a stringi/daty/itd w apostrofy (oczywiście ręcznie escape'owane).

Twój przykład nie zadziała:

$query=$db->prepare('SELECT * FROM `users` WHERE id = ((int)1) '); // - to zostanie zinterpretowane tak jak jest i się wykrzaczy.

$query=$db->prepare('SELECT * FROM `users` WHERE id = 1'); // tak wystarczy - to wartość na sztywno

// Mój przykład (tu z kolorowaniem) odnosił się do wstawiania zmiennej typu nie-string w zapytanie
$sql = 'SELECT [..] WHERE id = '.((int) $id).' AND [...]';

// Czyli w Twoim przypadku:
$id = 1;
$query=$db->prepare('SELECT * FROM `users` WHERE id = '.((int) $id);

Niemniej ostatecznie:

dzek69 napisał(a):

Oczywiście najbezpieczniej będzie zawsze używać binda, gorzej<ins>trudniej</ins> wtedy o przypadkowe pominięcie jakiegoś szczegółu (np. castowanie przy nullach).

1 użytkowników online, w tym zalogowanych: 0, gości: 1