[ almisa @ 09.08.2006. 17:26 ] @
Koristim stranu Pretraga.aspx na kojoj se nalaza polja za unos(TextBox, DropDownList isl.) u koja se upisuju kriterijumi (Vrsta, Velicina, Cena od, Cena do, Prodat ili ne ...) za pretragu nekog proizvoda.
Pritiskom da dugme "Prikazi" izvrsava se sledeci kod:

Response.Redirect("RezultatPretrage.aspx?Vrsta=" + strVrsta + "&Velicina=" + strVelicina);

(ima mnogo vise parametara ustvari, ali ovoliko je dovoljno zaobjasnjenje)

Na drugoj strani, RezultatPretrage.aspx nalazi se povezane SqlDataSource1 i GridView1 kontrola, pri cemu SqlDataSource1 ima popunjenje sledece parametre:

Name: Value:

Vrsta Request.QueryString("Vrsta")
Velicina Request.QueryString("Velicina")
.
.
.

Generise se sledeci Select upit:

SELECT [IDProizvoda], [Vrsta], [Velicina] ... FROM [Proizvodi] WHERE (([Vrsta] = @Vrsta) AND ([Velicina] = @Velicina) AND ... ))

Problem je sledeci:
Kada unesem sve parametre pretrage, kojih ime preko 10, sve radi ok,
cim neki od parametara izostavim, tj. ne popunim TextBox sa nekom vrednoscu, rezultat pretrage je uvek prazna GridView1 kontrola.
[ Solution @ 09.08.2006. 18:03 ] @
Pa dobijas praznu tabelu zato sto verovatno u bazi svaki red ima sve popunjene kolone. Ne vidim bas najbolje u cemu je problem jer ti prosto mozes da postavis IF pitanje da li je TextBox prazan i ako jeste da toj promenljivoj koju koristis kao parametar dodelis neku default vrednost.

Pozdrav,
Vladimir
[ Fedya @ 10.08.2006. 08:10 ] @
Mozda je jos lakse da promenis upit u ...WHERE ((@Vrsta = "" OR [Vrsta] = @Vrsta) AND (@Velicina = "" OR [Velicina] = @Velicina) ...
i time ce svaki parametar koji nisi prosledio biti ignorisan.
[ logic_rabbit @ 10.08.2006. 09:14 ] @
Mozda je bolje da dinamicki pravis sql upit kao npr.
if !(Textbox1.text=="")
{
SqlUpit+="AND Vrsta="+@Vrsta
}
Znaci da dinamicki dodajes novi "AND" ako je textbox za unos pun.
[ Fedya @ 10.08.2006. 09:23 ] @
Pa ne znam bas da je to bolje resenje, tako ima mnogo vise koda i mora da doda proveru da li mu tekst pocinje sa AND (tj. da li upit sadrzi WHERE AND pa to treba ispravljati...), mislim da je moje resenje bolje.
[ VerbatimBOT @ 10.08.2006. 09:29 ] @
Citat:
logic_rabbit: Mozda je bolje da dinamicki pravis sql upit kao npr.
if !(Textbox1.text=="")
{
SqlUpit+="AND Vrsta="+@Vrsta
}
Znaci da dinamicki dodajes novi "AND" ako je textbox za unos pun.


Ovo će sigurno raditi.

Citat:
Fedya: Pa ne znam bas da je to bolje resenje, tako ima mnogo vise koda i mora da doda proveru da li mu tekst pocinje sa AND (tj. da li upit sadrzi WHERE AND pa to treba ispravljati...), mislim da je moje resenje bolje.


Pa ovo je jedini način na koji možeš rešiti ovako nešto. Ja sam pokušavao na razne načine, ali tek kad se 100% udubiš u problem shvatiš da je ovo jedino rešenje.

Citat:
Fedya: Mozda je jos lakse da promenis upit u ...WHERE ((@Vrsta = "" OR [Vrsta] = @Vrsta) AND (@Velicina = "" OR [Velicina] = @Velicina) ...
i time ce svaki parametar koji nisi prosledio biti ignorisan.


U ovom slučaju bi izbacio rezultat i tamo gde nisu definisane vrsta i veličina, odnosno gde su prazan string, što nije u redu.
[ Fedya @ 10.08.2006. 09:32 ] @
Citat:
VerbatimBOT: U ovom slučaju bi izbacio rezultat i tamo gde nisu definisane vrsta i veličina što nije u redu.


Nisi dobro pogledao kod koji sam napisao, proveravam da li je parametar = "" a ne vrednost u tabeli. Znaci ako ima parametar uporedi ga sa vrednoscu u tabeli, ako nema ignorisi proveru!
[ Fedya @ 10.08.2006. 09:39 ] @
Sad sam video ovo:

Citat:
VerbatimBOT: Pa ovo je jedini način na koji možeš rešiti ovako nešto. Ja sam pokušavao na razne načine, ali tek kad se 100% udubiš u problem shvatiš da je ovo jedino rešenje.

LOL!

Ti se onda udubi 110%, jel ima jos nekoliko resenja kako mozes ovo reseti (preko dataseta, storovane...) ali je ovo moje najkrace i najlakse (kad ga shvatis)
[ VerbatimBOT @ 10.08.2006. 09:44 ] @
Citat:
Fedya: Nisi dobro pogledao kod koji sam napisao, proveravam da li je parametar = "" a ne vrednost u tabeli. Znaci ako ima parametar uporedi ga sa vrednoscu u tabeli, ako nema ignorisi proveru!
Citat:
Fedya: ...WHERE ((@Vrsta = "" OR [Vrsta] = @Vrsta) AND (@Velicina = "" OR [Velicina] = @Velicina) ...



Teoretski gledano, upit vraća rezultat gde je Vrsta jednaka praznom stringu ili parametru @Vrsta. Isto važi i za ostale parametre.
A drugo, nisam siguran koliko bi to radilo ako mu ne proslediš parametar, jer u tom slučaju parametar dobija vrednost NULL...
Ja ne vidim nikakvu IF proveru ovde...? Niti da si objasnio kako bi to implementirao?
[ VerbatimBOT @ 10.08.2006. 09:47 ] @
Citat:
Fedya: Ti se onda udubi 110%, jel ima jos nekoliko resenja kako mozes ovo reseti (preko dataseta, storovane...) ali je ovo moje najkrace i najlakse (kad ga shvatis) ;)


Ajde ga lepo objasni onda! :)
[ Fedya @ 10.08.2006. 09:56 ] @
Citat:
VerbatimBOT: Teoretski gledano, upit vraća rezultat gde je Vrsta jednaka praznom stringu ili parametru @Vrsta. Isto važi i za ostale parametre.
A drugo, nisam siguran koliko bi to radilo ako mu ne proslediš parametar, jer u tom slučaju parametar dobija vrednost NULL...
Ja ne vidim nikakvu IF proveru ovde...? Niti da si objasnio kako bi to implementirao?


Prakticno gledano, upit vraca samo one vrednosti kada je parametar jednak vrsti ili ignorise parametar ako je on prazan ;)

Da sam napisao WHERE ([Velicina] = "" OR...) onda bi vratio to sto ti kazes, a ovako @VELICINA = "" ce proveriti da li je prosledjen parametar

znaci imas ovako
(@par1 = "" or kolona1 = @par1) AND (@par2 = "" OR kolona2 = @par2)

prosledjujemo
@par1 = "" a za @par2="test')

upit ce izgledati ovako:
("" = "" OR kolona1= @par1) AND ("test" = "" OR kolona2 = "test")

nakon toga:posto je "" == "" a "test" != ""

a posto se prvi uslov u OR-u zadovolji drugi se ne proverava:

(true) AND (false OR kolona2 = "test")

Znaci

where kolona2 = "test" i to je sve (party)

Isto si mogao da poredis sa NULL ali posto ovo covek radi iz aplikacije tamo string ne moze da mu bude null.
[ VerbatimBOT @ 10.08.2006. 10:07 ] @
OK, nisam skapirao sta si hteo da kazes, mislim sad jesam!
VoZdra! :)
[ aleksandarpopov @ 10.08.2006. 10:21 ] @
Pozdrav.
1. Koliko je ovo sporije ( sa ovim poredjenjima) i odnosu na onaj sql da ih nema?
2. Sta bi se desilo kada bih imao ovo (@par1 = "" or kolona1 = @par1) , ali da nisam nigde u kodu definisao parametar @par1 (u nekom if -u utvrdim da nece imati vrednost pa mi ni ne treba, mi pa ga nisam ni pravio) sta se onda desava?

[ Fedya @ 10.08.2006. 10:35 ] @
1. Ne bi trebalo da bude sporije u opste posto upit ne mora da izvrsi nista na bazi, samo sa promenljivama dok ne dobije priblizno isti upit kako i onaj sto bi sklapao pa je efekat isti. Ovako je samo krace i (po meni) preglednije.

2. Ovo sam pisao kada bi se to radilo u aplikaciji, a tamo ne mozes imati NULL za string.
Ako to isto radis na storovanoj (sto je daleko cesce), onda poredis sa NULL, znaci:
(@par1 = NULL or kolona1 = @par1)
[ aleksandarpopov @ 10.08.2006. 11:08 ] @
Znam da ne moze biti null iz aplikacije, ali me zanima sta bi se desilo ako sql sadrzi ime parametra kao ovo
(@par1 = "" or kolona1 = @par1)
a taj parametar u kodu nije definisan a tebi SQL server to ispituje na jednakost sa ""? Verovatno ce baciti gresku..?
[ Fedya @ 10.08.2006. 11:41 ] @
Nisam bas siguran da te razumem. Ako pricamo o primeru gore, SQL serveru nece biti prosledjen parametar sa imenom nego samo njihove vrednosti, tako da ako imas:

SqlCommand cmd = new SqlCommand("SELECT * FROM Nesto WHERE (@param = "" or kolona = @param);
cmd.Parameters.Add("@param", textbox.Text);
cmd.ExecuteNonQuery();

i text ti je prazan, upit koji ce ti generisati SqlCommand i proslediti ga serveru ce izgledati ovako "SELECT * FROM Nesto WHERE ("" = "" or kolona = "")
tako da SQL nece ni bit svestan da si koristio taj parametar.


Ipak, mozda te nisam dobro razumeo...
[ aleksandarpopov @ 10.08.2006. 12:21 ] @
Da preformulisem... stvarno kad sam malo bolje procitao pitanje, nije bas najjasnije...
ako mi je command ovakav
SqlCommand cmd = new SqlCommand("SELECT * FROM Nesto WHERE (@param = "" or kolona = @param);

a ja ne uradim

cmd.Parameters.Add("@param", textbox.Text);

znaci pokusam da izvrsim gornji select bez dodavanja parametara sta se desava?
To sam hteo da pitam, na brzinu, posto nemam trenutno moj komp ovde da probam...
[ Fedya @ 10.08.2006. 12:33 ] @
E, ne moze tako
Dobices gresku, naravno.

Btw, zasto bi radio tako nesto?
[ aleksandarpopov @ 10.08.2006. 13:12 ] @
Nesto sam razmisljao o dinamickom pravljenju parametara, selecta (btw. nisam nikada to radio... :) ), ali kad bolje razmislim glupo je u pravu si... ovako kako sam ja prvo zamislio...
Hvala na odgovorima pozdrav!
[ mmix @ 10.08.2006. 14:17 ] @
Citat:
VerbatimBOT:
Citat:
logic_rabbit: Mozda je bolje da dinamicki pravis sql upit kao npr.
if !(Textbox1.text=="")
{
SqlUpit+="AND Vrsta="+@Vrsta
}
Znaci da dinamicki dodajes novi "AND" ako je textbox za unos pun.


Ovo će sigurno raditi.


Radice, ali uopste nije preporucljivo posto je podlozno SQL injection napadima. Dovoljno je da ukucam '; delete from Proizvodi; u bilo koji text box i da ti obrisem tabelu sa proizvodima. SQLParameters ima mehanizam zastite od ovog napada.


Citat:
Fedya: Ovo sam pisao kada bi se to radilo u aplikaciji, a tamo ne mozes imati NULL za string.
Ako to isto radis na storovanoj (sto je daleko cesce), onda poredis sa NULL, znaci:
(@par1 = NULL or kolona1 = @par1)


Kao prvo, = operator ne radi sa NULLovima, x = NULL uvek vraca false; Ispravni operator je IS, tj
@par1 is NULL

Drugo, ovo je jedini ispravni nacin za resenje ovog problema, stored procedura sa (@par1 is NULL or kolona1 = @par1) AND ... filterom, posto ce resenje sa (="") raditi samo ako su svi paramteri pretrage stringovi. Na aplikaciji je da osigura da se za prazne parametre upuca DBNull.Value u parametar. najjednostavniji nacin u C#-u je preko ?: tj.
Code:

textBox1.Text=="" ? DBNull.Value : <odredisniTip>.Parse(textBox1.Text)


Iako izgleda malo rogobatno ovo resenje je ujedno i najbrze posto ce SQL Query optimizer izbaciti skeniranje indeksa/tabele za one parametre koji su NULL preko boolean optimizacije OR operatora (kao sto je Fedya inicijalno napomenuo). Takodje se NULL moze postaviti kao default vrednost za sve parametre stored procedure, pa onda ne moras cak ni da ih prosledjujes ako su text boxovi prazni.
[ VerbatimBOT @ 10.08.2006. 14:28 ] @
Citat:
Radice, ali uopste nije preporucljivo posto je podlozno SQL injection napadima. Dovoljno je da ukucam '; delete from Proizvodi; u bilo koji text box i da ti obrisem tabelu sa proizvodima. SQLParameters ima mehanizam zastite od ovog napada.

Pa ajde probaj tako nešto i videćeš da ti neće uspeti to što si naveo.
Upravo je to i svrha Prepare() metode za SqlCommand, da ako navedeš u tekst polju neku komandu da je NE IZVRŠI.

Izvršio bi je kada bi je sastavljao u slučaju
Code:

komanda.CommandText = "INSERT INTO TABELA VALUES(' + txtIme.Text + ',' + txtPrezime.Text + ')";


[ Fedya @ 10.08.2006. 14:39 ] @
Citat:
mmix: Kao prvo, = operator ne radi sa NULLovima, x = NULL uvek vraca false; Ispravni operator je IS, tj
@par1 is NULL


Da, slazem se, moja greska, zurio sam ;)

A sto se tice stringova, sve su stringovi posto je na pocetku navedeno da koristi
Request.QueryString("Vrsta")
i to nadovezuje kao parametar SqlCommand objektu, bez upotrebe storovane procedure.
[ mmix @ 10.08.2006. 15:31 ] @
Citat:
VerbatimBOT: Pa ajde probaj tako nešto i videćeš da ti neće uspeti to što si naveo.
Upravo je to i svrha Prepare() metode za SqlCommand, da ako navedeš u tekst polju neku komandu da je NE IZVRŠI.



Code:

        [STAThread]
        static void Main(string[] args)
        {
            string emuliranitextBox = "''; delete from TempTable;";

            string command = "select * from TempTable where ";
            if (emuliranitextBox != "")
                command += "Polje = " + emuliranitextBox;
    
            // krajnji rezultat: select * from TempTable where Polje = ''; delete from TempTable;
            SqlConnection conn = new SqlConnection(connectionstring);
            conn.Open();
            SqlCommand cmd = new SqlCommand(command, conn);

            cmd.Prepare();  // iako nema nikakvog efekta, al ajde
            cmd.ExecuteNonQuery();
            conn.Close();
        }


I voila, TempTable je prazan....

Prepare nema efekta na ovu nasu pricu, on poziva sp_prepexec SQL sistemsku proceduru da "kompajlira" i izvrsi skript i ostavi ga u memoriji SQL servera kako bi pri visestrukom izvrsavanju preko sp_execute sa razlicitim parametrima ustedeo na vremenu. Bez Prepare, SQLCommand objekat koristi sp_executesql da direktno izvrsi skriptu sa parametrima, gde sp_executesql interno svaki put pozove sp_prepexec. Efektivno nista te ne sprecava da iskoristis sp_prepexec da izvrsis SQL injection napad. Zastitni sloj je ovde u samom SqlCommand objektu koji pri parsiranju parametara koje ce proslediti u sp_preexec/sp_executesql zamenjuje ' sa '' Ako nema parametara, nema ni parsiranja istih i SQL injection prolazi neotkriven.


[ VerbatimBOT @ 10.08.2006. 15:54 ] @
Code:
cmd.Prepare();  // iako nema nikakvog efekta, al ajde


Pa naravno da nema kada ja celo vreme pricam o PARAMETRIMA komande!
Dakle: Ako se radi preko parametara, npr:
Code:

komanda.Parameters.Add(new SqlDbParameters("prezime", SqlDbType.VarChar, 25));
komanda.Parameters["prezime"].Value = txtPrezime.Text;
//... neki kod
konekcija.Open();
komanda.Prepare();
komanda.ExecuteNonQuery();
konekcija.Close();


Ako ovde probas da uneses u TextBox
Code:

txtPrezime.Text = "''; delete from TempTable;";

dzaba! Nece izvrsiti ovaj delete upit.
Ja sam samo ovo hteo da napomenem!
[ mmix @ 10.08.2006. 16:45 ] @
Citat:
VerbatimBOT
Pa naravno da nema kada ja celo vreme pricam o PARAMETRIMA komande!
Dakle: Ako se radi preko parametara, npr:

Ajd da ne bude da sam lud , pogledaj svoju originalnu poruku, citirao si poruku od logic_rabbit i rekao da ce to resenje raditi (a njegovo resenje btw ne koristi parametre) na sta sam ja odgovorio da hoce ali je podlozno napadu. Otkud sad pominjes parametre kad ih nema u njegovom resenju (resenje sa paramterima je ponudio Fedya ako se ne varam)...


Citat:
VerbatimBOT: dzaba! Nece izvrsiti ovaj delete upit.
Ja sam samo ovo hteo da napomenem!

SQL Injection napad nece raditi sa parametrima nikad, cak i ako ne pozoves Prepare; sta vise ako text SQL komandu izvrsavas samo jednom nema apsolutno nikakve razlike u funkcionalnosti i performansama izmedju "sa" i "bez" poziva Prepare(). I to je bila moja napomenta, da Prepare() nema nikakve veze sa sprecavanjem SQL injection napada, on jednostavno sluzi za poboljsavanje performansi kada se ista komanda poziva vise puta sa razlicitim parametrima, nista vise. SQL injection sprecava parser parametara u SqlCommand objektu.
[ VerbatimBOT @ 11.08.2006. 08:17 ] @
Hm... neka me neko ispravi ako gresim, ali kako se ovo naziva
Citat:

Mozda je bolje da dinamicki pravis sql upit kao npr.
Code:

if !(Textbox1.text=="")
{
SqlUpit+="AND Vrsta="+@Vrsta
}

Znaci da dinamicki dodajes novi "AND" ako je textbox za unos pun.

ako ne upit sa parametrima?
Kako god, umorio sam se od pisanja... Uostalom, onaj ko je trazio resenje, dobio ga je... tako da je sada svaka rec suvisna.
[ Fedya @ 11.08.2006. 08:23 ] @
if !(Textbox1.text=="")
{
SqlUpit+="AND Vrsta=@Vrsta";
cmd.Parameters.Add("@Vrsta", Textbox1.text);
}

bi bilo sa parametrima ;)
[ VerbatimBOT @ 11.08.2006. 08:44 ] @
Citat:
cmd.Parameters.Add("@Vrsta", Textbox1.text);

Ovo bih podrazumevao. Jer pri kreiranju upita ide
Code:
SqlUpit+="AND Vrsta=@Vrsta";

tako da bi se javila greska (runtime) ukoliko se taj deo koda ne bi naveo.
[ mmix @ 11.08.2006. 13:03 ] @
Citat:
VerbatimBOT: Ovo bih podrazumevao. Jer pri kreiranju upita ide
Code:
SqlUpit+="AND Vrsta=@Vrsta";

tako da bi se javila greska (runtime) ukoliko se taj deo koda ne bi naveo.


Ah sad vidim gd je nastala konfuzija, on je zapravo napisao:

SqlUpit+="AND Vrsta=" + @Vrsta;

sto nije isto. Rezultat ovog koda nije "AND Vrsta = @Vrsta", posto @Vrsta nije string pod navodnicima u gornjem kodu nego varijabla. Tehnicki, ni ja ni ti nismo bili u pravu, posto @Vrsta cak ne moze ni da bude .NET varijabla (pocinje sa @), tako da njegovo resenje uopste ne bi ni radilo jer se ne bi ni iskompajliralo . Toliko o tome...
[ logic_rabbit @ 14.08.2006. 08:32 ] @
Cuo sam nesto o tome sql injection-u ali sad prvi put da to vidim.
Svaka cast na ovako zanimljivoj temi.
Vecina programera ne bi tako kompresivno razmisljala o tome vecina bi posegnula za jednostavnim resenjem koje sam naveo.
[ logic_rabbit @ 14.08.2006. 08:40 ] @
string vrsta;//bez @
vrsta=textbox1.text;
SqlUpit+="AND Vrsta=" + vrsta;
Na to sam mislio,malo je u zurbi pisano.