Har studerat ett exempel ur VISUAL C#.NET Steg för Steg och min fråga är hur man får bättre säker het vid UPDATE så att man inte anger en text vid ett nummeriskt fält i DB kör mot SQL Server. Några förslag : Nu vet jag ju inte hur/om du validerat data't i fälten innan du gör din insert men den kod du visar är definitvt sårbar för sql-injection. Vad är det för Kodgenereringsverktyg du menar? Tricket att få till update i .net handlar om parameteriserade frågor. Testade att göra som du skev men får en massa error vid build Hänger väl inte med i tänket. <b>Vad är det för Kodgenereringsverktyg du menar? </b> om du tittar på din kod och sedan på min så kommer du att uptäcka två saker. " Min poäng här var att man ofta i ren lathet eller glömska skriver dålig kod, men en kodgenerator "tröttnar aldrig" och har inga "bad hair days" :-)" <b>Nja, men Bad hair day kan man ju få om generatorn urgör från felaktigt designad DB eller SP :-) </b>Säkerhet vid UPDATE
private void updateRow(object source, System.Web.UI.WebControls.DataGridCommandEventArgs e)
{
try
{
ErrorMessage.Text = "";
SqlCommand updCommand = new SqlCommand();
updCommand.Connection = sqlConnection1;
updCommand.CommandText = "UPDATE Resultat SET Spelare = '" + ((TextBox)e.Item.Cells[3].Controls[0]).Text
+ "', Omgang = '" + ((TextBox)e.Item.Cells[4].Controls[0]).Text // Int 4
+ "', Resultat = '" + ((TextBox)e.Item.Cells[5].Controls[0]).Text // Float 8
+ "', H_B = '" + ((TextBox)e.Item.Cells[6].Controls[0]).Text // nvchar 255
+ "', Serier = '" + ((TextBox)e.Item.Cells[7].Controls[0]).Text // float 8
+ "', Poang = '" + ((TextBox)e.Item.Cells[8].Controls[0]).Text // float 8
+ "', Lag = '" + ((TextBox)e.Item.Cells[9].Controls[0]).Text // nvchar 255
+ "'" + " WHERE Nr = '" + ((TextBox)e.Item.Cells[2].Controls[0]).Text + "'"; // Nr int 4
updCommand.CommandType = CommandType.Text;
sqlConnection1.Open();
updCommand.ExecuteNonQuery();
sqlDataAdapter1.Fill(dataSet1);
Cache["Resultat"] = dataSet1;
DataGrid1.EditItemIndex = -1;
BindGrid();
sqlConnection1.Close();
}
catch (Exception ex)
{
ErrorMessage.Text = ex.Message;
}
}
Sv: Säkerhet vid UPDATE
* Använd typade datasets. Finns både för och nackdelar med detta, men när det gäller just typkonverteringsproblem så springer typade datasets i cirklar runt otypade dylika.
* Använd kodgenereringsverktyg för de ofta repetitiva datalager-klasserna. Med rätt mallar så generas korrekt kod och du kan även lägga in just funktioner som "IsNumeric" för att verifiera datan för varje fält. Detta är ofta något man inte orkar göra när man kodar själv.
* Sedan så är det ju så att skickar du in icke-numerisk data till en numerisk kolumn så kommer SQL-servern att raisa ett fel och adaptern ett exception. Så en bra felhantering är som vanligt A och O.Sv: Säkerhet vid UPDATE
Tex
(TextBox)e.Item.Cells[6].Controls[0]).Text = "bad input' where 1=1; --"
då blir din sql typ:
UPDATE Resultat SET Spelare = 'Spelare', Resultat = '1.23', H_B = 'bad input' where 1=1; -- etc...
så använd parameteriserad (stavning ?) SQL.
Ta en titt här: http://msdn.microsoft.com/msdnmag/issues/04/09/SQLInjection/default.aspx.Sv:Säkerhet vid UPDATE
Är det med "Web Form generated Code" I VS.NET som du mear?
Men jag tycker den genererar så otroligt dum SELECT Sats för UPDATE som i mitt fall så finns denna:
this.sqlUpdateCommand1.CommandText = @"UPDATE Resultat SET Nr = @Nr, Spelare = @Spelare,
Omgang = @Omgang, Resultat = @Resultat, H_B = @H_B, Serier = @Serier, Poang = @Poang, Lag =
@Lag WHERE (Nr = @Original_Nr) AND (H_B = @Original_H_B OR @Original_H_B IS NULL AND H_B IS
NULL) AND (Lag = @Original_Lag OR @Original_Lag IS NULL AND Lag IS NULL) AND (Omgang =
@Original_Omgang OR @Original_Omgang IS NULL AND Omgang IS NULL) AND (Poang =
@Original_Poang OR @Original_Poang IS NULL AND Poang IS NULL) AND (Resultat = @Original_Resultat
OR @Original_Resultat IS NULL AND Resultat IS NULL) AND (Serier = @Original_Serier OR
@Original_Serier IS NULL AND Serier IS NULL) AND (Spelare = @Original_Spelare OR @Original_Spelare IS
NULL AND Spelare IS NULL); SELECT Nr, Spelare, Omgang, Resultat, H_B, Serier, Poang, Lag FROM
Resultat WHERE (Nr = @Nr)";
this.sqlUpdateCommand1.Connection = this.sqlConnection1;
this.sqlUpdateCommand1.Parameters.Add(new System.Data.SqlClient.SqlParameter("@Nr", System.Data.SqlDbType.Int, 4, "Nr"));
this.sqlUpdateCommand1.Parameters.Add(new System.Data.SqlClient.SqlParameter("@Spelare", System.Data.SqlDbType.Int, 4, "Spelare"));
this.sqlUpdateCommand1.Parameters.Add(new System.Data.SqlClient.SqlParameter("@Omgang", System.Data.SqlDbType.Int, 4, "Omgang"));
this.sqlUpdateCommand1.Parameters.Add(new System.Data.SqlClient.SqlParameter("@Resultat", System.Data.SqlDbType.Float, 8, "Resultat"));
this.sqlUpdateCommand1.Parameters.Add(new System.Data.SqlClient.SqlParameter("@H_B", System.Data.SqlDbType.NVarChar, 255, "H_B"));
this.sqlUpdateCommand1.Parameters.Add(new System.Data.SqlClient.SqlParameter("@Serier", System.Data.SqlDbType.Float, 8, "Serier"));
this.sqlUpdateCommand1.Parameters.Add(new System.Data.SqlClient.SqlParameter("@Poang", System.Data.SqlDbType.Float, 8, "Poang"));
this.sqlUpdateCommand1.Parameters.Add(new System.Data.SqlClient.SqlParameter("@Lag", System.Data.SqlDbType.NVarChar, 255, "Lag"));
this.sqlUpdateCommand1.Parameters.Add(new System.Data.SqlClient.SqlParameter("@Original_Nr", System.Data.SqlDbType.Int, 4, System.Data.ParameterDirection.Input, false, ((System.Byte)(0)), ((System.Byte)(0)), "Nr", System.Data.DataRowVersion.Original, null));
this.sqlUpdateCommand1.Parameters.Add(new System.Data.SqlClient.SqlParameter("@Original_H_B", System.Data.SqlDbType.NVarChar, 255, System.Data.ParameterDirection.Input, false, ((System.Byte)(0)), ((System.Byte)(0)), "H_B", System.Data.DataRowVersion.Original, null));
this.sqlUpdateCommand1.Parameters.Add(new System.Data.SqlClient.SqlParameter("@Original_Lag", System.Data.SqlDbType.NVarChar, 255, System.Data.ParameterDirection.Input, false, ((System.Byte)(0)), ((System.Byte)(0)), "Lag", System.Data.DataRowVersion.Original, null));
this.sqlUpdateCommand1.Parameters.Add(new System.Data.SqlClient.SqlParameter("@Original_Omgang", System.Data.SqlDbType.Int, 4, System.Data.ParameterDirection.Input, false, ((System.Byte)(0)), ((System.Byte)(0)), "Omgang", System.Data.DataRowVersion.Original, null));
this.sqlUpdateCommand1.Parameters.Add(new System.Data.SqlClient.SqlParameter("@Original_Poang", System.Data.SqlDbType.Float, 8, System.Data.ParameterDirection.Input, false, ((System.Byte)(0)), ((System.Byte)(0)), "Poang", System.Data.DataRowVersion.Original, null));
this.sqlUpdateCommand1.Parameters.Add(new System.Data.SqlClient.SqlParameter("@Original_Resultat", System.Data.SqlDbType.Float, 8, System.Data.ParameterDirection.Input, false, ((System.Byte)(0)), ((System.Byte)(0)), "Resultat", System.Data.DataRowVersion.Original, null));
this.sqlUpdateCommand1.Parameters.Add(new System.Data.SqlClient.SqlParameter("@Original_Serier", System.Data.SqlDbType.Float, 8, System.Data.ParameterDirection.Input, false, ((System.Byte)(0)), ((System.Byte)(0)), "Serier", System.Data.DataRowVersion.Original, null));
this.sqlUpdateCommand1.Parameters.Add(new System.Data.SqlClient.SqlParameter("@Original_Spelare", System.Data.SqlDbType.Int, 4, System.Data.ParameterDirection.Input, false, ((System.Byte)(0)), ((System.Byte)(0)), "Spelare", System.Data.DataRowVersion.Original, null));
Så oerhört mycket kod, det måste gå att förkorta dessa parametrar?
Gert
Sv: Säkerhet vid UPDATE
Ex)
SqlCommand cmdPesist = new SqlCommand("UPDATE PRODUCTS SET Name = @Name WHERE Id = @id", cn);
SqlParameter workPrm = new SqlParameter("@Name", SqlDbType.VarChar, 30);
workParam.Value = "New product name";
cmdPersist.Parameters.Add(workParam);
workPrm = new SqlParameter("@Id", SqlDbType.Int);
workParam.Value = 42;
Parameter klassen tar då hand om datatyper, längd, sql injection osv.
Vad gäller den automatgenererade koden som vs skapar, så är den så omfattande för att den bla bygger parametesierade fårgor som skall kunna mappa direkt mot en tabell i ett dataset. Den ser också till att hålla koll på sk optimistic locking, vilket innebär att den undersöker hurvida datat i databasen ändrats sedan du hämtat den. MS genererar kod för hantera den situationen på ett sätt som är ganska vanligt.
Sv:Säkerhet vid UPDATE
Bla.The type or namespace name 'updCommand' could not be found (are you missing a using directive or an assembly reference?) ' på flera rader
och
A local variable named 'workParam' is already defined in this scope ' på flera rader
samt
The name 'Nr' does not exist in the class or namespace 'Lesson.Visaresultat' ' Lär väl betyda att det inte finns någon Label med namnet 'Nr'
Så här ser kocen ut nu:
updCommand.Connection = sqlConnection1;
SqlCommand cmdPersist = new SqlCommand("UPDATE Resultat SET Nr = @Nr, Spelare = @Spelare,
Omgang = @Omgang, Resultat = @Resultat, H_B = @H_B, Serier = @Serier, Poang = @Poang, Lag =
@Lag",sqlConnection1);
SqlParameter workParam = new SqlParameter("@Nr", SqlDbType.Int, 4, "Nr");
workParam.Value = @Nr;
cmdPersist.Parameters.Add(workParam);
SqlParameter workParam = new SqlParameter("@Spelare", SqlDbType.Int, 4, "Spelare");
workParam.Value = @Spelare;
cmdPersist.Parameters.Add(workParam);
SqlParameter workParam = new SqlParameter("@Ombang", SqlDbType.Int, 4, "Omgang");
workParam.Value = @Omgang;
cmdPersist.Parameters.Add(workParam);
SqlParameter workParam = new SqlParameter("@Resultat", SqlDbType.Float, 8, "Resultat");
workParam.Value = @Resultat;
cmdPersist.Parameters.Add(workParam);
SqlParameter workParam = new SqlParameter("@Serier", SqlDbType.Float, 8, "Serier");
workParam.Value = @Serier;
cmdPersist.Parameters.Add(workParam);
SqlParameter workParam = new SqlParameter("@Poang", SqlDbType.Float, 8, "Poang");
workParam.Value = @Poang;
cmdPersist.Parameters.Add(workParam);
SqlParameter workParam = new SqlParameter("@H_B", SqlDbType.NVarChar, 2, "H_B");
workParam.Value = @H_B;
cmdPersist.Parameters.Add(workParam);
SqlParameter workParam = new SqlParameter("@Lag", SqlDbType.NVarChar, 2, "Lag");
workParam.Value = @Lag;
updCommand.Parameters.Add(new SqlParameter("@Nr", SqlDbType.Int, 4, "Nr"));
updCommand.Parameters.Add(new SqlParameter("@Spelare", SqlDbType.Int, 4, "Spelare"));
updCommand.Parameters.Add(new SqlParameter("@Omgang", SqlDbType.Int, 4,"Omgang"));
updCommand.Parameters.Add(new SqlParameter("@Resultat", SqlDbType.Float, 8, "Resultat"));
updCommand.Parameters.Add(new SqlParameter("@H_B", SqlDbType.NVarChar, 2, "H_B"));
updCommand.Parameters.Add(new SqlParameter("@Serier", SqlDbType.Float, 8, "Serier"));
updCommand.Parameters.Add(new SqlParameter("@Poang", SqlDbType.Float, 8, "Poang"));
updCommand.Parameters.Add(new SqlParameter("@Lag", SqlDbType.NVarChar, 2, "Lag"));
sqlConnection1.Open();
updCommand.ExecuteNonQuery();
sqlDataAdapter1.Fill(dataSet1);
Cache["Resultat"] = dataSet1;
DataGrid1.EditItemIndex = -1;
BindGrid();
sqlConnection1.Close();
Sv: Säkerhet vid UPDATE
Inget speciellt verktyg, men CodeSmith www.erikjsmith.com är ett exempel. Dock förutsätter ju detta att du har en mall som genererar korrekt kod. Min poäng här var att man ofta i ren lathet eller glömska skriver dålig kod, men en kodgenerator "tröttnar aldrig" och har inga "bad hair days" :-)Sv:Säkerhet vid UPDATE
1) jag har inget updCommand definerat.
2) jag omdefinerar inte workparam varjegång. Sv:Säkerhet vid UPDATE
Nja, men Bad hair day kan man ju få om generatorn urgör från felaktigt designad DB eller SP :-)
Mvh JohanSv: Säkerhet vid UPDATE
Amen! F ö en av bristerna i CodeSmith, att den utgår från databasdesignen.