At ang hindi bababa sa tulong ay mula sa function na iyong binuo. PHP: \"Mga Quote\". Pagsusulat ng mysql query, slash, escaping quotes Paghahanap sa code

string ng mga panipi (11)

Sinusubukan kong malaman ang pinakamahusay na paraan upang magsulat ng mga query. Naiintindihan ko rin ang kahalagahan ng pagiging pare-pareho. Sa ngayon ay random na gumagamit ako ng mga solong quote, double quote at backticks nang walang tunay na pag-iisip.

$query = "INSERT INTO table (id, col1, col2) VALUES (NULL, val1, val2)";

Gayundin, sa halimbawa sa itaas, isaalang-alang na ang "talahanayan," "col[n]," at "val[n]" ay maaaring maging mga variable.

Ano ang pamantayan para dito? Anong ginagawa mo?

Mga 20 minuto na akong nagbabasa ng mga sagot sa mga katulad na tanong, ngunit mukhang walang tiyak na sagot sa tanong na ito.

Mga sagot

Ngayon ipagpalagay na gumagamit ka ng direktang post variable sa MySQL query pagkatapos ay gamitin ito tulad nito:

$query = "INSERT INTO `table` (`id`, `name`, `email`) VALUES (" ".$_POST["id"]." ", " ".$_POST["name"]." ", " ".$_POST["email"].." ")";

Ito ang pinakamahusay na kasanayan para sa paggamit ng mga variable ng PHP sa MySQL.

Pangunahin sa Mysql, ang mga uri ng identifier na ito ay ginagamit sa mga query na ` , " , " at ().

    " o " gamitin para magsama ng string bilang value na "01/26/2014 00:00:00" o "01/26/2014 00:00:00" . Ginagamit lang ang identifier na ito para sa "01/26/2014 00:00:00" string function, gaya ng now() o sum ,max .

    ` gamitin para magsama ng table o table table, hal. piliin ang column_name mula sa table_name kung saan id = "2"

    () ay ginagamit lamang upang ilakip lamang ang mga bahagi ng isang query, halimbawa piliin ang column_name mula sa table_name kung saan (id = "2" at kasarian = "lalaki") o name = "rakesh.

Bukod sa lahat ng (mahusay na ipinaliwanag) na mga sagot, walang nabanggit sa ibaba at madalas akong pumupunta sa Q&A na ito.

Sa maikling sabi; Iniisip ng MySQL na gusto mong gawin ang matematika sa iyong sariling table/column at bigyang-kahulugan ang mga gitling gaya ng "email" bilang e mail .

Pagtanggi sa pananagutan. Kaya naisip kong idagdag ito bilang isang "FYI" na sagot para sa mga ganap na bago sa pagtatrabaho sa mga database, at maaaring hindi maintindihan ang mga teknikal na termino na inilarawan na.

(May mga magagandang sagot sa itaas tungkol sa katangian ng SQL ng iyong tanong, ngunit maaaring may kaugnayan din ito kung bago ka sa PHP.)

Maaaring mahalagang tandaan na naiiba ang pagtrato ng PHP sa mga single at double quote...

Ang mga single-quoted string ay "literal" at medyo marami itong WYSIWYG string. Ang mga double-quoted na string ay binibigyang-kahulugan ng PHP para sa posibleng kapalit na variable (ang mga backreference sa PHP ay hindi eksaktong mga string, isinasagawa nila ang command sa shell at ibinabalik ang resulta).

$foo = "bar"; echo "may $foo"; // May $foo echo "may $foo"; // May bar echo `ls -l`; // ... isang listahan ng direktoryo

Kung ang mga talahanayan ng cols at mga halaga ay mga variable, kung gayon mayroong dalawang paraan:

Sa double quotes "" ang kumpletong query ay:

$query = "INSERT IN TO $table_name (id, $col1, $col2) VALUES (NULL, "$val1", "$val2"";

$query = "INSERT INTO ".$table_name." (id, ".$col1.", ".$col2.") VALUES (NULL, "".$val1.", "".$val2."") ) ";

May mga single quotes na "" :

$query = "INSERT INTO ".$table_name." (id, ".$col1.", ".$col2.") VALUES (NULL, ".$val1.", ".$val2.")";

Gumamit ng mga backticks `` kapag ang column/value name ay katulad ng isang MySQL reserved keyword.

Tandaan. Kung tumukoy ka ng pangalan ng column na may pangalan ng talahanayan, gumamit ng mga backtick tulad nito:

`table_name` . `column_name`<- Примечание: исключить. из задних клещей.

Dapat gamitin ang mga backticks para sa mga identifier ng talahanayan at column, ngunit kailangan lang kapag ang identifier ay isang MySQL reserved keyword o kapag ang identifier ay naglalaman ng mga space character o character sa labas ng limitadong set (tingnan sa ibaba). Kadalasang inirerekomenda na iwasan ang paggamit ng mga nakareserbang keyword bilang mga pagkakakilanlan ng hanay o talahanayan kung posible upang maiwasan ang problema sa panipi.

Dapat gamitin ang mga solong quote para sa mga string value, tulad ng sa listahan ng VALUES(). Ang mga dobleng panipi ay sinusuportahan din ng MySQL para sa mga halaga ng string, ngunit ang mga solong panipi ay mas malawak na tinatanggap ng iba pang mga RDBMS, kaya magandang ideya na gumamit ng mga solong panipi sa halip na mga dobleng panipi.

Inaasahan din ng MySQL ang mga literal na halaga ng DATE at DATETIME na iisa-isang sinipi bilang mga string, gaya ng "2001-01-01 00:00:00" . Para sa higit pang impormasyon, tingnan ang dokumentasyon ng literatura ng Petsa at Oras, partikular na mga alternatibo sa paggamit ng gitling - bilang isang separator ng segment sa mga string ng petsa.

Kaya gamit ang iyong halimbawa, ido-double cast ko ang PHP string at gagamit ng mga solong quote para sa mga value na "val1", "val2" . Ang NULL ay isang MySQL keyword at isang non-value at samakatuwid ay hindi ginagamit.

Wala sa mga table o column identifier na ito ang nakalaan na mga salita o gumagamit ng mga character na nangangailangan ng pagsipi, ngunit sinipi ko pa rin ang mga ito nang paurong (higit pa tungkol doon sa ibang pagkakataon...).

Ang mga function na nauugnay sa RDBMS (gaya ng NOW() sa MySQL) ay hindi dapat ma-quote, bagama't ang kanilang mga argumento ay napapailalim sa parehong mga panuntunan o pag-quote ng mga panuntunan na nabanggit na.

Backtick(`) table at column ┬──── ┬──┬───────┐ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ INSERT IN TO `table` (`id`, `col1`, `col2`, `date`, `updated`) VALUES (NULL, "val1", "val2", "2001-01-01", NOW())"; Hindi naka-quote na keyword ─────┴┴┴┘ │ │ │ │ │ │ │││││ Single-quoted (") strings ───‴───‴ ───┴── ┴────┘ │ │ │││││ Single-quoted (") PETSA ────────────——──—── ───┴── Unquoted function ───────────────────────── ──────── ─ ──┴┴┴┴┘

Variable interpolation

Ang pag-quote ng mga pattern para sa mga variable ay hindi nagbabago, bagama't kung balak mong i-interpolate ang mga variable nang direkta sa isang string, dapat itong double quoted sa PHP. Siguraduhin lamang na tama kang makatakas sa mga variable para magamit sa SQL. (Inirerekomenda na gumamit ng API na sumusuporta sa mga inihandang pahayag sa halip bilang isang depensa laban sa SQL injection.)

// Parehong bagay sa ilang variable na kapalit // Dito, ang variable na pangalan ng table na $table ay backtick-quoted, at ang mga variable // sa listahan ng VALUES ay single-quoted $query = "INSERT INTO `$table`(`id`, `col1`, `col2`, `petsa`) VALUES (NULL, "$val1", "$val2", "$date")";

Mga Inihandang Pahayag

Kapag nagtatrabaho sa mga inihandang pahayag, kumonsulta sa dokumentasyon upang matukoy kung dapat isama ang mga tagapuno ng pahayag. Ang pinakasikat na mga API na magagamit sa PHP, PDO at MySQLi ay kinabibilangan hindi awtorisado mga placeholder, tulad ng karamihan sa mga inihandang instruction API sa ibang mga wika:

// Halimbawa ng PDO na may pinangalanang mga parameter, unquoted $query = "INSERT INTO `table` (`id`, `col1`, `col2`, `date`) VALUES (:id, :col1, :col2, :date)" ; // MySQLi halimbawa na may ? mga parameter, unquoted $query = "INSERT INTO `table` (`id`, `col1`, `col2`, `date`) VALUES (?, ?, ?, ?)";

Mga simbolo na nagbabalik ng back reference sa mga identifier:

Halimbawa:

Ang parehong ay maaaring gawin para sa mga pangalan ng talahanayan at mga pangalan ng field. Ito ay lubhang magandang ugali kung itali mo ang iyong database id sa mga back windows.

Tingnan ang sagot na ito para matuto pa tungkol sa mga reverse inferences.

Ngayon tungkol sa Double quotes at Single Quotes (nabanggit na ito ni Michael).

Ngunit para tukuyin ang halaga, kailangan mong gumamit ng single o double quotes. Tingnan natin ang isa pang halimbawa.

INSERT INTO `tablename` (`id, `title`) VALUES (NULL, title1);

Dito ko sinasadyang nakalimutang balutin ang title1 sa mga quotes. Tatanggap na ngayon ng server ang title1 bilang pangalan ng column (i.e. identifier). Kaya, upang ipahiwatig na ito ay isang halaga, kailangan mong gumamit ng doble o solong mga panipi.

INSERT INTO `tablename` (`id, `title`) VALUES (NULL, "title1");

Ngayon, pinagsama sa PHP, dobleng quote at solong quote ay ginagawang mas madali ang pagsulat ng query. Tingnan natin ang binagong bersyon ng query sa iyong tanong.

$query = "INSERT INTO `table` (`id`, `col1`, `col2`) VALUES (NULL, "$val1", "$val2"");

Ngayon, gamit ang mga dobleng panipi sa PHP, gagawin mo ang mga variable na $val1 at $val2 na gamitin ang kanilang mga halaga, kaya lumilikha ng wastong query. gaya ng

$val1 = "aking halaga 1"; $val2 = "aking halaga 2"; $query = "INSERT INTO `table` (`id`, `col1`, `col2`) VALUES (NULL, "$val1", "$val2"");

INSERT INTO `table` (`id`, `col1`, `col2`) VALUES (NULL, "my value 1", "my value 2")

Mayroong maraming mga kapaki-pakinabang na sagot dito, sa pangkalahatan ay nagtatapos sa dalawang puntos.

  1. BACKTICKS (`) ay ginagamit sa paligid ng mga pangalan ng identifier.
  2. SINGLE QUOTES (") ay ginagamit sa paligid ng mga value.

At gaya ng sinabi ni @MichaelBerkowski

Dapat gamitin ang mga backticks para sa mga identifier ng talahanayan at column, ngunit kailangan lang kapag ang identifier ay isang MySQL reserved keyword o kapag ang identifier ay naglalaman ng mga space character o character sa labas ng limitadong set (tingnan sa ibaba). Kadalasang inirerekomenda na iwasan ang paggamit ng mga nakareserbang keyword bilang mga pagkakakilanlan ng hanay o talahanayan kung posible upang maiwasan ang problema sa panipi.

May isang kaso kung saan hindi maaaring maging ang identifier nakalaan na keyword o naglalaman mga character na whitespace o mga character sa labas ng limitadong hanay ngunit tiyak na nangangailangan ng mga backlink sa kanilang paligid.

Ang 123E10 ay isang wastong pangalan ng pagkakakilanlan, ngunit isa ring wastong INTEGER literal.

[nang hindi nagdedetalye kung paano ka makakakuha ng id name na ganyan] Sabihin nating gusto kong gumawa ng pansamantalang talahanayan na tinatawag na 123456e6.

Walang ERROR sa mga backtick.

DB > lumikha ng pansamantalang talahanayan `123456e6` (`id` char (8)); OK ang query, 0 row ang apektado (0.03 sec)

ERROR kung hindi ka gumagamit ng mga callback.

DB > lumikha ng pansamantalang talahanayan 123451e6 (`id` char (8)); ERROR 1064 (42000): Mayroon kang error sa iyong SQL syntax; suriin ang manual na tumutugma sa bersyon ng iyong server ng MariaDB para sa tamang syntax na gagamitin malapit sa "123451e6 (`id` char (8))" sa linya 1

Gayunpaman, ang 123451a6 ay isang magandang pangalan ng ID (walang mga backtick).

DB > lumikha ng pansamantalang talahanayan 123451a6 (`id` char (8)); OK ang query, 0 row ang apektado (0.03 sec)

Ito ay ganap na dahil ang 1234156e6 ay isa ring exponential number.

Dapat gamitin ang mga solong quote para sa mga string value, tulad ng sa listahan ng VALUES().

Ang mga backticks ay karaniwang ginagamit upang magpahiwatig ng isang identifier at maaari ding maging ligtas dahil sa paminsan-minsang paggamit ng mga nakalaan na keyword.

Kapag pinagsama sa PHP at MySQL, ang mga dobleng quote at solong quote ay lubos na nagpapasimple sa oras ng pagsulat ng query.

Mayroong dalawang uri ng mga quote sa MySQL:

  1. " upang isama ang mga literal na string
  2. ` upang isama ang mga identifier tulad ng mga pangalan ng talahanayan at column

At pagkatapos ay mayroong "ito ay isang espesyal na kaso. Ito ay maaaring gamitin para sa isa ng mga target sa itaas sa isang pagkakataon depende sa sql_mode ng server :

  1. Default Maaaring gamitin ang "character" para mag-nest ng mga literal na string "
  2. Sa ANSI_QUOTES mode " ang simbolo ay maaaring gamitin upang isama ang mga identifier, ANSI_QUOTES

Ang sumusunod na query ay magbubunga ng iba't ibang resulta (o mga error) depende sa SQL mode:

PUMILI ng "column" MULA sa talahanayan KUNG SAAN foo = "bar"

ANSI_QUOTES hindi pinagana

Pipiliin ng query ang literal na string na "column" kung saan ang column foo ay katumbas ng string na "bar"

Pinagana ang ANSI_QUOTES

Pipili ang query ng column na column kung saan ang column foo ay katumbas ng column

Kailan gagamitin

  • Iminumungkahi kong iwasan mo ang paggamit ng " upang ang iyong code ay hindi nakadepende sa mga SQL mode
  • Palaging isama ang mga identifier dahil ito ay magandang kasanayan (medyo ilang katanungan sa SO talakayin ito)

May malinaw na pagkakaiba sa pagitan ng paggamit ng " " at " " .

Kapag ang " " ay ginamit sa kabuuan, walang "pagbabagong-anyo o pagsasalin". Ito ay naka-print na tulad ng dati.

Gamit ang " ", anuman ang nakapaligid dito ay "isinasalin o binago" sa halaga nito.

Ang ibig kong sabihin sa pagsasalin/pagbabalik-loob ay ito: ang anumang nilalaman sa loob ng mga solong panipi ay hindi "isasalin" sa kanilang mga halaga. Matatanggap sila dahil nasa loob sila ng mga quotes. Halimbawa: a=23 , pagkatapos ay bubuo ng $a ang echo "$a" sa karaniwang output. Habang ang echo "$a" ay gagawa ng 23 sa karaniwang output.

(PHP 4 >= 4.3.0, PHP 5)

mysql_real_escape_string — Tinatakasan ang mga espesyal na character sa isang string para gamitin sa isang SQL statement

Paglalarawan

mysql_real_escape_string (string $unescaped_string [, mapagkukunan $link_identifier = NULL]): string

Tinatakasan ang mga espesyal na character sa unescaped_string , isinasaalang-alang ang kasalukuyang set ng character ng koneksyon upang ligtas itong ilagay sa isang mysql_query(). Kung ang binary data ay ilalagay, ang function na ito ay dapat gamitin.

mysql_real_escape_string() tinatawag ang function ng library ng MySQL na mysql_real_escape_string, na naglalagay ng mga backslashes sa mga sumusunod na character: \x00, \n, \r, \ , " , " at \x1a.

Ang function na ito ay dapat palaging (na may ilang mga pagbubukod) upang gawing ligtas ang data bago magpadala ng query sa MySQL.

Pag-iingat

Seguridad: ang default na set ng character

Ang set ng character ay dapat itakda alinman sa antas ng server, o sa function ng API mysql_set_charset() para maapektuhan mysql_real_escape_string() . Tingnan ang seksyon ng mga konsepto sa set ng character para sa higit pang impormasyon.

Mga Parameter

unescaped_string

Ang string na dapat takasan.

Link_identifier

Ang koneksyon sa MySQL. Kung hindi tinukoy ang link identifier, ang huling link na binuksan ni mysql_connect() ay ipinapalagay. Kung walang mahanap na link, susubukan nitong lumikha ng isa na parang mysql_connect() ay tinawag na walang argumento. Kung walang nakitang koneksyon o itinatag, an E_WARNING nabuo ang error sa antas.

Ibalik ang mga Halaga

Ibinabalik ang nakatakas na string, o MALI sa pagkakamali.

Mga Error/Exceptions

Ang pagsasagawa ng function na ito nang walang koneksyon sa MySQL ay maglalabas din E_WARNING antas ng mga error sa PHP. Isagawa lamang ang function na ito na may valid na koneksyon sa MySQL.

Mga halimbawa

Halimbawa #1 Simple mysql_real_escape_string() halimbawa

//Kumonekta
$link = mysql_connect("mysql_host" , "mysql_user" , "mysql_password")
O mamatay(mysql_error());

//Tanong
$query = sprintf ( "PUMILI * MULA SA mga user WHERE user="%s" AT password="%s"",
mysql_real_escape_string($user),
mysql_real_escape_string($password));
?>

Halimbawa #2 mysql_real_escape_string() nangangailangan ng halimbawa ng koneksyon

Ipinapakita ng halimbawang ito kung ano ang mangyayari kung walang koneksyon sa MySQL kapag tinatawagan ang function na ito.

Ang halimbawa sa itaas ay maglalabas ng katulad ng:

Babala: mysql_real_escape_string(): Walang ganoong file o direktoryo sa /this/test/script.php sa linya 5 Babala: mysql_real_escape_string(): Hindi maitatag ang link sa server sa /this/test/script.php sa linya 5 bool(false) string(41) "PUMILI * MULA sa mga aktor WHERE last_name = """

Halimbawa #3 Isang halimbawa ng SQL Injection Attack

// Hindi namin sinuri ang $_POST["password"], maaaring kahit anong gusto ng user! Halimbawa:
$_POST [ "username" ] = "aidan" ;
$_POST [ "password" ] = "" O ""="" ;

// Query database upang suriin kung mayroong anumang tumutugmang mga gumagamit
$query = ($_POST [ "username" ]) " AT password=" ( $_POST [ "password" ]) "" ;
mysql_query($query);

// Nangangahulugan ito na ang query na ipinadala sa MySQL ay:
echo $query ;
?>

Ang query na ipinadala sa MySQL:

Ito ay magpapahintulot sa sinuman na mag-log in nang walang wastong password.

Mga Tala

Ang isang koneksyon sa MySQL ay kinakailangan bago gamitin mysql_real_escape_string() kung hindi man ay isang error ng antas E_WARNING ay nabuo, at MALI ay ibinalik. Kung hindi tinukoy ang link_identifier, gagamitin ang huling koneksyon sa MySQL.

Tandaan: mysql_real_escape_string() hindi nakatakas % at _ . Ito ay mga wildcard sa MySQL kung isasama sa GAYA NG, BIGYAN, o Bawiin.

8 taon na ang nakaraan

Isang maliit na function na ginagaya ang orihinal na mysql_real_escape_string ngunit hindi nangangailangan ng aktibong koneksyon sa mysql. Maaaring ipatupad bilang isang static na function sa isang klase ng database. Sana makatulong ito sa isang tao.

function mysql_escape_mimic ($inp) (
if(is_array($inp))
return array_map (__METHOD__ , $inp );

If(!empty($inp ) && is_string ($inp )) (
return str_replace (array("\\" , "\0" , "\n" , "\r" , """ , """ , "\x1a" ), array("\\\\" , "\ \0" , "\\n" , "\\r" , "\\"" , "\\"" , "\\Z" ), $inp );
}

Ibalik ang $inp ;
}
?>

13 taon na ang nakalipas

Tandaan na ang mysql_real_escape_string ay hindi naglalagay ng mga backslashes sa \x00, \n, \r, at \x1a gaya ng nabanggit sa dokumentasyon, ngunit talagang pinapalitan ang character ng isang MySQL na katanggap-tanggap na representasyon para sa mga query (hal. \n ay pinalitan ng "\ n" litteral). (\, ", at " ay nakatakas bilang dokumentado) Hindi nito binabago kung paano mo dapat gamitin ang function na ito, ngunit sa tingin ko magandang malaman ito.

6 na taon na ang nakaraan

Walang talakayan tungkol sa pagtakas ay kumpleto nang hindi sinasabi sa lahat na hindi ka dapat gumamit ng panlabas na input upang bumuo ng na-interpret na code. Napupunta ito para sa mga pahayag ng SQL, o anumang bagay na tatawagin mo sa anumang uri ng function na "eval".

Kaya, sa halip na gamitin ang napakasira na function na ito, gumamit na lang ng mga pahayag na inihandang parametric.

Sa totoo lang, ang paggamit ng data na ibinigay ng user upang bumuo ng mga SQL statement ay dapat ituring na propesyonal na kapabayaan at dapat kang panagutin ng iyong tagapag-empleyo o kliyente para sa hindi paggamit ng mga pahayag na inihandang parametric.

Anong ibig sabihin niyan?

Nangangahulugan ito sa halip na bumuo ng isang SQL statement tulad nito:

"INSERT IN TO X (A) VALUES(".$_POST["a"].)"

Dapat mong gamitin ang mysqli's prepare() function () upang magsagawa ng isang pahayag na ganito ang hitsura:

"INSERT IN TO X (A) VALUES(?)"

NB: Hindi ito nangangahulugan na hindi ka dapat kailanman bumuo ng mga dynamic na SQL statement. Ang ibig sabihin nito ay hindi ka dapat gumamit ng data na ibinigay ng user upang bumuo ng mga statement na iyon. Ang anumang data na ibinigay ng user ay dapat ipasa bilang mga parameter sa statement pagkatapos nito pinaghandaan.

Kaya, halimbawa, kung bubuo ka ng isang maliit na balangkas at nais mong gumawa ng isang insert sa isang talahanayan batay sa kahilingang URI, ito ay sa iyong pinakamahusay na interes na huwag kunin ang halaga ng $_SERVER["REQUEST_URI"] (o anumang bahagi nito) at direktang pagsamahin iyon sa iyong query. Sa halip, dapat mong i-parse ang bahagi ng $_SERVER["REQUEST_URI"] na halaga na gusto mo, at imapa iyon sa pamamagitan ng ilang uri ng function o associative array sa isang hindi user ibinigay na halaga. Kung walang halaga ang pagmamapa, alam mong may mali sa ibinigay na data ng user.

Ang hindi pagsunod dito ay naging sanhi ng maraming problema sa SQL-injection sa balangkas ng Ruby On Rails, kahit na gumagamit ito ng mga pahayag na inihandang parametric. Ito ay kung paano na-hack ang GitHub sa isang punto. Kaya, walang wika ang immune sa problemang ito. Iyon ang dahilan kung bakit ito ay isang pangkalahatang pinakamahusay na kasanayan at hindi isang bagay na partikular sa PHP at kung bakit dapat mong TALAGANG gamitin ito.

Gayundin, dapat ka pa ring gumawa ng ilang uri ng pagpapatunay ng data na ibinigay ng mga user, kahit na gumagamit ng mga pahayag na inihandang parametric. Ito ay dahil ang data na ibinigay ng user ay kadalasang magiging bahagi ng ilang nabuong HTML, at gusto mong tiyakin na ang data na ibinigay ng user ay hindi magdudulot ng mga problema sa seguridad sa browser.

9 taon na ang nakalipas

Mayroong isang kawili-wiling quirk sa halimbawa #2 tungkol sa SQL injection: AT mas inuuna ang OR, kaya ang na-inject na query ay talagang gumagana bilang WHERE (user="aidan" AND password="") O ""="", kaya sa halip ng pagbabalik ng isang database record na naaayon sa isang arbitrary username (sa kasong ito ay "aidan"), talagang ibabalik nito ang LAHAT ng mga record ng database. Sa walang partikular na pagkakasunud-sunod. Kaya't ang isang attacker ay maaaring makapag-log in bilang anumang account, ngunit hindi kinakailangan sa anumang kontrol sa kung aling account ito.

Siyempre, maaaring baguhin ng isang potensyal na pag-atake ang kanilang mga parameter upang i-target ang mga partikular na user ng interes:

//Hal. mga halaga ng umaatake
$_POST [ "username" ] = "" ;
$_POST["password"] = "" O user = "administrator" AT "" = "";

// Maling nabuong query
$query = "PUMILI * MULA sa mga user WHERE user="$_POST [ username ] " AT password=" $_POST [ password ] "" ;

echo $query ;

// Ang query na ipinadala sa MySQL ay mababasa:
// SELECT * FROM users WHERE user="" AND password="" OR user="administrator" AT ""="";
// na magpapahintulot sa sinuman na magkaroon ng access sa account na pinangalanang "administrator"

?>

1 taon na ang nakalipas

@feedr
Inilarawan ko ang kanyang tala bilang sumusunod:
$string = "asda\0sd\x1aas\\\\\\\\dasd\"asdasd\na\"\"sdasdad";
$array1 = array("\\\\\\\", "\0", "\n", "\r", """, """, "\x1a");
$array2 = array("\\\\\\\\\\\\\\\\\\", "\\\0", "\\\n", "\\\r", "\\\ " ", "\\\"", "\\\Z");
echo($string);
echo(PHP_EOL);
para sa($i=0; $i kung ($i==0)
$p = "/(?iba pa
$p = "/(?echo($i);
echo($p);
echo($array2[$i]);
$string = preg_replace($p, $array2[$i], $string);
echo("\t");
echo($string);
echo(PHP_EOL);
}
echo(PHP_EOL);
echo($string);

2 mga taon na nakalipas

Upang Sipiin si Sam sa Numb Safari

[ "Walang talakayan tungkol sa pagtakas ay kumpleto nang hindi sinasabi sa lahat na hindi ka dapat gumamit ng panlabas na input upang makabuo ng interpreted code. Ito ay para sa mga SQL statement, o anumang bagay na tatawagin mo sa anumang uri ng "eval" na function.

Kaya, sa halip na gamitin ang napakasira na function na ito, gumamit na lang ng mga pahayag na inihandang parametric.

Sa totoo lang, ang paggamit ng data na ibinigay ng user upang bumuo ng mga SQL statement ay dapat ituring na propesyonal na kapabayaan at dapat kang panagutin ng iyong tagapag-empleyo o kliyente para sa hindi paggamit ng mga pahayag na inihandang parametric." ]

tama si Sam.........

Gayunpaman, sa palagay ko ay hindi makatwirang ihinto ang lahat ng paglilinis at ipasa lamang ang gawain sa mga inihandang pahayag ng parametric.

Ang isang partikular na developer na nagtatrabaho sa isang partikular na sitwasyon ay palaging makakaalam ng higit pa tungkol sa wastong input (partikular sa kontekstong iyon).

Kung hihilingin mo sa isang user na ipasa ang isang halaga na naibigay mo na sa kanila at alam mo na ang lahat ng naturang mga halaga ay nagsisimula sa AB****** at ang string ay dapat na may haba na 7 o 11 ngunit hindi kailanman sa anumang iba pang haba kung gayon mayroon kang ang batayan ng isang mahusay na pre-sanitiser - maaaring magpahiwatig ng legacy na data ang iba't ibang pinapayagang haba ng isang string.

Hindi ko kailanman gugustuhin na basta na lang ipasa ang basura na maaaring ipinasa ng isang malisyosong user sa pamamagitan ng isang form sa mga inihandang pahayag ng parametric, gusto kong palaging gawin muna ang sarili kong mga pagsusuri sa katinuan at sa ilang mga kaso ay maaaring magkamali ang mga ito sa panig ng pag-iingat at piliin lamang na ganap na i-abort ang Database op.

Sa ganoong paraan ang aking DB ay hindi barado sa mga hindi ligtas na pahayag na ginawang ligtas - hindi lang ito barado na mas mabuti.

Seguridad sa mga layer - sanitization at validation ay dapat pa ring isaalang-alang sa bawat sitwasyon BAGO gumamit ng mga inihandang pahayag.

Bilang karagdagan sa abot ng aking nabasa sa opisyal na doc
==============================================

"Pagtakas at SQL injection

Ang mga nakatali na variable ay ipinapadala sa server nang hiwalay sa query at sa gayon ay hindi makagambala dito. Ginagamit ng server ang mga halagang ito nang direkta sa punto ng pagpapatupad, pagkatapos ma-parse ang template ng pahayag. Ang mga nakatali na parameter ay hindi kailangang i-escape dahil hindi sila direktang pinapalitan sa string ng query"

Iyon ay nagmumungkahi sa akin na ang panganib ay maiiwasan sa mga panloob sa pamamagitan ng alternatibong paghawak hindi sa pamamagitan ng pagpapawalang-bisa.

Nangangahulugan ito na ang isang malaking proyekto na may hindi kumpletong conversion sa mga inihandang pahayag, legacy code sa iba't ibang bahagi ng isang organisasyon o mga server na nakikipag-usap sa isa't isa ay maaaring magpasa ng masamang balita mula sa isang immune na lokasyon o sitwasyon sa isang hindi immune.

Hangga't ang sanitization ay mahusay na isinasagawa nang hindi nagkakaroon ng karagdagang mga panganib, personal kong mananatili sa ilang mga layer ng sanitization at pagkatapos ay tatawagan ang mga inihandang pahayag.


Una, kaunti tungkol sa kung bakit kailangan ang mga slash na ito sa pangkalahatan.
Kung papalitan namin ang anumang data sa isang query, pagkatapos ay upang makilala ang data na ito mula sa mga SQL command, dapat silang ilagay sa mga panipi.
Halimbawa, kung nagsusulat ka
SELECT * FROM table WHERE name = Bill
pagkatapos ay magpapasya ang database na ang Bill ay ang pangalan ng isa pang field, hindi ito mahahanap, at magtapon ng error. Samakatuwid, ang pinalit na data (sa kasong ito, ang pangalang Bill) ay dapat na nakapaloob sa mga quote - pagkatapos ay isasaalang-alang ito ng database na isang string, ang halaga nito ay dapat italaga sa field ng pangalan:
SELECT * FROM table WHERE name = "Bill"
Gayunpaman, maaari ring lumitaw ang mga quote sa mismong data. Hal,
SELECT * FROM table WHERE name = "D"Artagnan"
Dito ang database ay magpapasya na ang "D" ay data, at ang Artagnan ay isang utos na hindi nito alam, at magtapon din ng isang error. Samakatuwid, kinakailangang subaybayan ang lahat ng data upang maipaliwanag sa database na ang mga panipi (at ilang iba pang mga espesyal na character) na matatagpuan sa mga ito ay tumutukoy sa data.
Bilang resulta, makakatanggap kami ng tamang kahilingan na hindi magdudulot ng mga error:
SELECT * FROM table WHERE name = "D\"Artagnan"

Kaya, nalaman namin na kapag pinapalitan ang string ng data sa isang query, dalawang panuntunan ang dapat sundin:
- lahat ng ipinasok na string data ay dapat na nakapaloob sa mga quote (single o double, ngunit ang mga single ay mas maginhawa at mas madalas na ginagamit).
- ang mga espesyal na character ay dapat na makatakas sa mga slash.

Dapat itong espesyal na tandaan: ang mga idinagdag na slash ay HINDI pumupunta sa database. Ang mga ito ay kailangan lamang sa kahilingan. Kapag tumama sa base, ang mga slash ay itinatapon. Alinsunod dito, ang isang karaniwang pagkakamali ay ang paggamit ng mga stripslashes kapag kumukuha ng data mula sa database.

Nalalapat ang lahat ng nasa itaas sa string data at mga petsa. Ang mga numero ay maaaring ipasok nang walang trailing o nakapalibot sa kanila ng mga panipi. Kung gagawin mo ito pagkatapos KINAKAILANGAN! pilitin ang data sa nais na uri bago ito ipasok sa query, halimbawa:
$id = intval ($id);
Gayunpaman, para sa pagiging simple (at pagiging maaasahan), maaari kang magtrabaho sa mga numero tulad ng sa mga string (dahil ang mysql ay nagko-convert pa rin sa mga ito sa nais na uri). Alinsunod dito, susubaybayan namin ang anumang data na ipinasok sa kahilingan at ilakip ito sa mga panipi.

Gayundin, may isa pang panuntunan - opsyonal, ngunit dapat itong sundin upang maiwasan ang mga error:
Ang mga pangalan ng mga patlang at mga talahanayan ay dapat na nakapaloob sa likod ng mga solong panipi - "`" (ang susi na may simbolong ito ay matatagpuan sa isang karaniwang keyboard sa kaliwa ng "1" na key). Pagkatapos ng lahat, ang pangalan ng field ay maaaring magkasabay sa mysql mga keyword, ngunit kung gagamit tayo ng back quote, mauunawaan ng MySQL na tama ang lahat:
PUMILI * MULA SA `table` WHERE `date` = "2006-04-04"
Dapat mong makilala ang pagitan ng mga panipi na ito at huwag malito ang isa sa isa. Dapat mo ring tandaan na ang mga backtick ay hindi natatakasan ng mga slash.

Kaya, natutunan namin kung paano wastong palitan ang data sa isang kahilingan.
PERO! Ang pagbuo ng dynamic na query ay hindi limitado sa pagpapalit ng data. Kadalasan kailangan nating palitan ang mga SQL command at field name sa isang query. At narito tayo lumipat sa paksa ng seguridad:

Ang SQL Injection ay isang paraan ng pag-atake ng hacker kapag ang data na inilipat sa isang script ay binago sa paraang ang query na nabuo sa script na ito ay nagsimulang magsagawa ng isang bagay na ganap na naiiba mula sa kung ano ang nilayon nito.
Ang mga patakaran para sa pagprotekta laban sa mga naturang pag-atake ay maaaring nahahati sa dalawang punto:
1. Paggawa gamit ang data.
2. Paggawa gamit ang mga kontrol sa query.

Tinalakay namin ang unang punto nang detalyado sa itaas. Masasabing hindi ito, sa katunayan, isang depensa. Ang pagsunod sa mga panuntunan para sa pagdaragdag ng data sa isang query ay idinidikta, una sa lahat, ng mga kinakailangan ng SQL SYNTAX. At bilang side effect, mayroon din kaming proteksyon laban sa pag-hack.

Ang pangalawang punto ay mas mahirap, dahil walang iisang unibersal na panuntunan tulad ng para sa data - hindi mapoprotektahan ng mga backtick ang pangalan ng field mula sa pagbabago ng isang hacker. Hindi posibleng gumamit ng mga quote para protektahan ang mga pangalan ng talahanayan, SQL statement, LIMIT command parameter, at iba pang statement.
Samakatuwid, ang pangunahing panuntunan kapag pinapalitan ang mga elemento ng kontrol sa isang query ay:
Kung kailangan mong dynamic na magpasok ng mga SQL statement o mga pangalan ng mga field, database, table sa isang query, sa anumang pagkakataon ay hindi mo dapat direktang ipasok ang mga ito sa query.
Ang lahat ng mga opsyon para sa mga naturang karagdagan ay dapat na nakasulat sa ADVANCE sa iyong script at piliin batay sa kung ano ang ipinasok ng user.
Halimbawa, kung kailangan mong magpasa ng pangalan ng field sa order ng operator, sa anumang pagkakataon ay hindi mo ito dapat palitan nang direkta. Kailangan muna nating suriin ito. Halimbawa, gumawa ng hanay ng mga wastong halaga, at palitan ito sa kahilingan lamang kung ang naipasa na parameter ay nasa array na ito:
$orders =array("pangalan" , "presyo" , "qty" );
$key = array_search($_GET["sort"], $orders));
$orderby = $orders [ $key ];
$query = "PUMILI * MULA SA `table` ORDER NI$orderby " ;

Hinahanap namin ang hanay ng mga paunang inilarawan na opsyon para sa salitang ipinasok ng user, at kung makita namin ito, pipiliin namin ang kaukulang elemento ng array. Kung walang nakitang tugma, pipiliin ang unang elemento ng array.
Kaya, ang ipinalit sa kahilingan ay hindi kung ano ang ipinasok ng gumagamit, ngunit kung ano ang nakasulat sa aming script.
Ang parehong ay dapat gawin sa lahat ng iba pang mga kaso.
Halimbawa, kung ang sugnay na WHERE ay dynamic na nabuo:
kung (!empty($_GET [ "presyo" ])) $where .= "price="" . mysql_real_escape_string ($_GET [ "presyo" ]). """ ;
$query = "PUMILI * MULA SA `table` SAAN $where " ;

Mahirap para sa akin na isipin ang isang kaso kung saan maaaring maipasok ang isang pangalan ng talahanayan sa isang query nang pabago-bago, ngunit kung mangyari ito, kailangan ding ipasok ang pangalan mula lamang sa isang set na paunang natukoy sa script.
Ang mga parameter ng LIMIT operator ay dapat na pilitin sa isang uri ng integer gamit ang mga pagpapatakbo ng arithmetic o ang intval() function.
Huwag isipin na nauubos ng mga halimbawang nakalista dito ang lahat ng opsyon para sa pagbuo ng dynamic na query. Kailangan mo lamang na maunawaan ang prinsipyo at ilapat ito sa lahat ng ganoong kaso.

Dahil sa likas na katangian ng aking trabaho, kailangan kong magsagawa ng mga pag-audit sa seguridad ng source code ng mga web application.
Maraming web application at maraming code...

Hindi lihim na ang mga kahinaan ng SQL injection ay ang pinakakaraniwan sa lahat ng mga kahinaan sa web application sa panig ng server. May mga platform at framework kung saan halos hindi kasama ang mga ganitong bagay, halimbawa ORM at iba pa. Ngunit patuloy na sinasabi sa amin ng mga istatistika ang tungkol sa ganap na pamamayani ng mga web application na may simpleng pinagsama-samang mga query sa SQL sa Internet. Bilang karagdagan, may mga kaso kung saan ang ORM ay pangkalahatang naaangkop Hindi ito, halimbawa, kapag hindi lamang ang mga parameter ng mga expression, kundi pati na rin ang lohika ng query mismo sa antas ng operator ay dapat nakadepende sa data ng user.

Kaya, magsimula tayo.

Walang kwentang karakter na tumatakas
Natagpuan sa 83% ng mga web application ng PHP na mahina sa mga SQL injection
Gamit ang escape function para sa mga character tulad ng
mysql_escape_string
mysql_real_escape_string
magdagdag ng mga pilikmata
walang panipi. Kadalasan ito ay nagpapakita mismo sa mga numeric na parameter (lahat ng uri ng *_id).
Halimbawa
$sql = "PUMILI NG user MULA sa listahan ng mga user WHERE userid=".mysql_real_escape_string($_GET["uid"]);

Lumilitaw na ito ay ligtas na code, ngunit sa ibabaw lamang. Ang pinakakaraniwang pattern ng SQL injection sa PHP sa aking pagsasanay ay pumasok dito. Upang atakehin ang kahinaang ito, kailangan lang ng isang umaatake na iwasan ang paggamit ng " " \x00 \r \n \x1a character sa attack vector.
Halimbawa:
/index.php?uid=-777 UNION SELECT password MULA sa userlist

Maghanap sa code
Kumplikado ng semantika ng wika. Para sa isang simpleng paghahanap maaari mong gamitin ang egrep:
egrep -Rin "(piliin | i-update | ipasok | tanggalin | palitan).*(mula sa | itakda | sa).*(mysql_escape_string|mysql_real_escape_string|addslashes)" . | grep -v "[\""]["\"]"

Ang lohika ng expression ng paghahanap ay ang mga sumusunod: hanapin ang lahat ng mga linya kung saan walang pagkakasunud-sunod ng mga quote character ("", "", "", "") sa kaliwa ng mga function ng pag-filter. Ang pamamaraan, siyempre, ay malayo sa 100%, ngunit imposibleng mangailangan ng isang regular na expression upang maisagawa ang semantic analysis.
Upang gawing mas madali ang pagpapakita ng impormasyon, maaari mong i-highlight ang function sa kulay sa console:
egrep -Rin "(piliin | i-update | ipasok | tanggalin | palitan).*(mula sa | itakda | sa).*(mysql_escape_string|mysql_real_escape_string|addslashes)" . | grep -v "[\""]["\"]" | egrep --color "(mysql_escape_string|mysql_real_escape_string|addslashes)"

Para maprotektahan laban sa wildcard na kahinaan na ito, pinakamahusay na gumamit ng uri ng casting.
Palagi itong gumagana nang mas mabilis at mas maaasahan kaysa sa lahat ng uri ng pag-filter at screening.
Para sa halimbawa sa itaas, ang patch ay maaaring ganito:
$sql = "PUMILI NG user MULA sa listahan ng mga user WHERE userid=".intval($_GET["uid"]);

Dito nagtatapos ang maikling sanaysay. Hinihimok ko ang lahat ng mga web developer na subukang suriin ang kanilang mga mapagkukunan para sa mga naturang disenyo. Mas mabuti pa, palawakin ang ibinigay na script sa paghahanap para sa mga tao.

So basically I dug deep into the areas of MySQL and PHP... specifically the security measures I should take when dealing with the database and form inputs. Sa ngayon ay natagpuan ko ang mga sumusunod na lubos na inirerekomenda:

  1. Mga Inihandang Pahayag
  2. Gamit ang _real_escape_string()
  3. HINDI gumagamit ng mga magic quotes dahil nililito nito ang mga database at nagtatapos sa pagbibigay sa iyo ng mga bagay tulad ng "Hindi mo ito tinawag...".

Ang lahat ng ito ay mahusay at binabantayan ko ito. Gayunpaman, iniisip ko kung dapat kong takasan ang mga character tulad ng dollar sign [$], percent sign [%], at marahil iba pa. Maaari bang bigyang-kahulugan ng query ang dollar sign bilang variable ng PHP? Paano naman ang LIKE syntax na narinig ko na gumagamit ng % na simbolo o kahit isang wildcard? Ang mga inihandang pahayag ay dapat teknikal na pangalagaan ang lahat ng ito, ngunit gusto ko lang na maging ligtas at tiyaking nasasakupan ko nang maayos ang lahat. Sa mga kaso kung saan nakalimutan kong gumamit ng mga inihandang pahayag o pinabayaan lamang ang mga ito, umaasa ako na ang pangalawang linya ng depensang ito ay makapagsasabi sa akin na maaari kong alisin ang pagkahilo.

Narito ang kasalukuyang ginagamit ko para sa pagtakas:

Function escape($koneksyon, $data)( $new_data = trim($data); $new_data = i_real_escape_string($koneksyon, $new_data); $new_data = addcslashes($new_data, "%_$"); $new_data = htmlspecialchars ($new_data, ENT_NOQUOTES); ibalik ang $new_data; )

So tama ba ito? May ginagawa ba akong napakalaking mali? Pakitandaan na kapag ibinabalik ang data ng database ay kailangan kong tanggalin ang mga backslashes bago ang $,% at _ na mga character.

May ginagawa ba akong napakalaking mali?

Una tungkol sa iyong pananaliksik.

Inihanda na mga pahayag - ang nag-iisa kahanga-hangang bagay na iyong natagpuan.

Bagaman ang paggamit ng mysqli_real_escape_string (ipagpalagay na gumagamit ka ng mga inihandang pahayag) ay magiging walang silbi at nakakapinsala(paglikha ng resulta na ikaw mismo ang nagsabi: "Tumawag ka ay hindi...").

At ang Magic Quotes ay matagal nang tinanggal mula sa wika - kaya wala talagang halaga.

Kaya kahit na ang karamihan sa iyong mga unang lugar ay malinaw na mali.

Ngayon sa iyong tanong.

Maaari bang bigyang-kahulugan ng query ang dollar sign bilang variable ng PHP?

Paano naman ang LIKE syntax na narinig ko na gumagamit ng % na simbolo o kahit isang wildcard?

Oo, tama ang narinig mo. Ang eksaktong layunin ng operator ng LIKE ay magsagawa ng paghahanap ng pattern. Ang pag-disable sa mga character na ito sa LIKE ay hindi magkakaroon ng kaunting kahulugan.

Sa bawat oras na gagamitin mo ang operator ng LIKE, dapat kang magpasya kung aling karakter ang gagamitin at alin ang hindi papayagan. Hindi ka maaaring gumamit ng isang beses na solusyon. Hindi banggitin na sa lahat ng iba pang mga pakikipag-ugnayan sa mysql ang % sign ay walang espesyal na kahulugan.

Ang mga inihandang pahayag ay dapat teknikal na pangalagaan ang lahat ng ito

Ang mga inihandang pahayag ay walang kinalaman sa $ o % na mga palatandaan. Ang mga inihandang pahayag ay tumutukoy sa SQL injection, ngunit walang karakter ang maaaring magdulot nito (hindi mo matatawag ang "injection" bilang isang operator na TULAD na ginamit nang maayos, hindi ba?).

Sa wakas, sa pinakamasamang bahagi.

Kung sakaling makalimutan mong gumamit ng mga inihandang pahayag o basta basta na lamang pinabayaan na sundin ang mga ito,

walang magliligtas sa iyo.

At ang hindi bababa sa tulong ay mula sa function na iyong binuo.

Ibuod.

  1. Alisin ang tampok na ito.
  2. Gamitin mga tagapuno * upang kumatawan sa bawat indibidwal na variable sa query.
  3. Itakas ang % at _ na mga character sa input lamang kung gagamitin ang mga ito sa operator ng LIKE at hindi mo nais na bigyang-kahulugan ang mga ito.
  4. Gumamit ng htmlspecialchars() para sa output, hindi mysql input.

*basahin ang mga inihandang pahayag kung ang terminong ito ay hindi pamilyar sa iyo.

Hindi mo kailangang iwasan ang dollar sign. Hindi partikular na tinitingnan ng MySQL ang karakter na ito, at kinikilala lamang ito ng PHP sa source code, hindi sa mga halaga ng string (maliban kung tatawagin mo ang eval sa string, ngunit iyon ay isang buong iba pang mga uod ng bulate).

Kakailanganin mo lamang na i-escape ang % at _ kung gumagamit ka ng input ng user bilang LIKE argument at hindi mo gustong gumamit ang user ng mga wildcard. Maaaring mangyari ito kung pinoproseso mo ang isang form sa paghahanap. Hindi mo kailangang gamitin ito kapag nag-iimbak sa isang database.

Hindi mo kailangang gumamit ng htmlspecialchars kapag ina-access ang database. Dapat lang itong gamitin kapag nagpapakita ng data sa user sa isang HTML page upang maiwasan ang XSS injection.

Depende sa kung anong data at para saan ito ginagamit.

Kung nalaman mong masyadong malaki at kumplikado ang default na out-of-the-box na mga pahayag ng PHP, iminumungkahi kong tingnan mo ang ilan sa mga klase na available sa github para mabigyan ka ng ideya ng mga pinasimpleng query.

Isang halimbawa ng paglalagay ng mga query sa klase na ito

$data = Array ("login" => "admin", "active" => true, "firstName" => "John", "lastName" => "Doe", "password" => $db->func( "SHA1(?)",Array ("secretpassword+salt")), // password = SHA1("secretpassword+salt") "createdAt" => $db->now(), // createdAt = NOW() " mag-e-expire" => $db->now("+1Y") // mag-e-expire = NOW() + interval 1 year // Mga sinusuportahang interval [s]econd, [m]inute, [h]hour, [d]day, [M]buwan, [Y]tainga); $id = $db->insert("mga gumagamit", $data); if ($id) echo "nalikha ang user. Id=" . $id; else echo "nabigo ang pagpasok: " . $db->getLastError();