I'm a new in the world of coding,
I built a large web site with several textboxes, so now i figure out that I've been using a dangerous method of inserting data in the SQL server by some thing like this:
execSQL("insert into Dossier(ID_Dossier,Nom_Giac) values(" & id_dossier.text & "," Nom_gaic.text & "')")
Public Function execSQL(ByVal req As String, Optional ByVal type As String = "r")
cmd = New SqlCommand
cmd.CommandText = req
cmd.Connection = con
openCon()
If type = "r" Then
Return cmd.ExecuteReader(CommandBehavior.CloseConnection)
Else
Return cmd.ExecuteNonQuery
End If
closeCon()
End Function
I just want to know if there is any quick way to solve this problem in my entire web site.
I applaud the fact that you want to remove any possibilities of SQL injection from your site.
That said, there's no quick, magical "find-and-replace-my-vulnerable-code" function; you need to go into your system and update any calls like that with parameterized queries.
Parameterized queries are required to prevent SQL injection. Here's an example, taken from this question: How do I create a parameterized SQL query? Why Should I?
Public Function GetBarFooByBaz(ByVal Baz As String) As String
Dim sql As String = "SELECT foo FROM bar WHERE baz= #Baz"
Using cn As New SqlConnection("Your connection string here"), _
cmd As New SqlCommand(sql, cn)
cmd.Parameters.Add("#Baz", SqlDbTypes.VarChar, 50).Value = Baz
Return cmd.ExecuteScalar().ToString()
End Using
End Function
Using LINQ to SQL can help prevent SQL Injection attacks by parameterizing for you:
LINQ to SQL passes all data to the database via SQL parameters. So, although the SQL query is composed dynamically, the values are substitued server side through parameters safeguarding against the most common cause of SQL injection attacks.
Read more about it here.
Related
I have the following code:
Dim da As SqlDataAdapter
Dim rst As DataRow = MyrstEdit("SELECT * FROM tblHotels WHERE ID = 19",, da).Rows(0)
rst("HotelName") = "My Cool"
rst("FirstName") = "Albert"
rst("City") = "Edmonton"
da.Update(rst.Table)
So, the above is nice and short. And it works rather nice.
And of course this being asp.net, then centralizing things like connection code (that I don't have to create over and over) is a also rather nice. And why bother with a connection during coding, so above reduces coding workload.
How then can I ensure the connection object is disposed and closed correctly?
From reading, since I do not open the conneciton, then
The Fill() does open, then close.
And I have to assume that the da.Update() ALSO must then by logic open, then close the conneciton.
However, I still should clean up the connection object after above is done.
Question:
Is disposing of the sql data adaptor object sufficient here to also dispose the connection object that the data adaptor is using?
eg:
da.Dispose()
The MyRstEdit routine is this:
Public Function MyrstEdit(strSQL As String,
Optional strCon As String = "",
Optional ByRef oReader As SqlDataAdapter = Nothing) As DataTable
' can pass custom connection string - if not passed, then default
If strCon = "" Then
strCon = GetConstr() ' global func to get application con string
End If
Dim mycon As New SqlConnection(strCon)
oReader = New SqlDataAdapter(strSQL, mycon)
Dim rstData As New DataTable
Dim cmdBuilder = New SqlCommandBuilder(oReader)
Try
oReader.Fill(rstData)
oReader.AcceptChangesDuringUpdate = True
Catch
End Try
Return rstData
End Function
So, the return sqlDataAdaptor object must be holding the connection, since the scope in above routine is limited.
So do I have to dispose the connection object?
Can I do this with the sqlAdaptor?
I can't dispose/close the connection object in above sub, since my da.Update() in the calling code still needs that connection until I do the update.
How then can I ensure the connection object is disposed and closed correctly?
Don't worry about it; it's not your job. DataAdapter makes it, DataAdapter will clean it up
However, I still should clean up the connection object after above is done
No, for the aforementioned reason
Is disposing of the sql data adaptor object sufficient here to also dispose the connection object that the data adaptor is using?
Yes, unless you have good reason to believe that Microsoft's code has a critical flaw and their classes will benefit from your code micromanaging the resources they create..
You can also read the reference source if you want to know what they do internally
The MyRstEdit routine is this:
It's hard to understand why it exists in that form; you'd be better off just passing a datatable around and creating dataadapters as and when you need them. MyRstEdit isn't well named; it doesn't seem to edit anything, it always overwrites the passed in adapter with stuff that a any passed in adapter might already know (the connstr and sql) and then doesn't really do anything that couldn't just be put to
Using da As New SqlDataAdapter("SELECT * FROM tblHotels WHERE ID = 19", GetConStr())
Dim dt as New DataTable
da.Fill(dt)
Dim rst = dt(0)
rst("HotelName") = "My Cool"
rst("FirstName") = "Albert"
rst("City") = "Edmonton"
New SqlCommandBuilder(da)
da.Update(rst.Table)
End Using
About the most useful thing it does is apply a command builder, but that's only a single line and only needed for an update..
Perhaps you could create an extension method that applies to a DataAdapter, that gets the first row, so you could say:
Using da As SqlDataAdapter("SELECT * FROM tblHotels WHERE ID = 19", GetConStr())
Dim rst = da.FirstRow()
rst("HotelName") = "My Cool"
rst("FirstName") = "Albert"
rst("City") = "Edmonton"
New SqlCommandBuilder(da)
da.Update(rst.Table)
End Using
But it isn't saving much over "just using it how MS intended", and there is still that block of "data columns accessed by string and hence intellisense can't help" in the middle.
If you're looking to find ways of making your SqlDataAdapter life easier it might be an opportunity to skip it and have a look at Dapper instead; a set of extension methods on a SqlConnection that map classes to and from:
Using c as New SqlConnection(GetConStr())
Dim h = Await c.SingleAsync(Of Hotel)("SELECT * FROM tblHotels WHERE ID = #id", New With { .ID = 19 } )
h.HotelName = "My Cool"
h.FirstName = "Albert"
h.City = "Edmonton"
Await c.ExecuteAsync("UPDATE tblHotels SET HotelName = #HotelName, FirstName = #FirstName, City = #City WHERE ID = #ID", h)
End Using
You still have to write the queries, but it's a one time op, or you could look at something like Dapper Contrib.. The main use here is that instead of being some DataRow object you access by "string column names" you have a first class VB.NET object - Hotel, with named typed proeprties, and dapper can create them from SQL queries and put their values directly into SQL parameters (another thing that is absent from your existing code)
I have trouble converting this to stored procedure
//The string included in the sql statement:
string employer = Session["Employer"].ToString();
then the sql statement
update tblWorkData set EmployerName='"+txtemployername.text+"' where EmployerName='"+Employer+"' //the string above
This works fine in asp.net
But when I turn it into stored procedure,
create proc updateWork
#EmployerName nvarchar(max)
as
begin
update tblWorkData set EmployerName=#EmployerName where EmployerName=#EmployerName
end
Now when I execute the sp on asp.net,
string update = "updateWork '"+employer+"','"+txtemployername.text+"'";
I got an error saying "too many arguements". What should I do?
Your stored procedure only takes one argument and you're calling it with two. To fix this you need to alter the procedure to take two arguments like this:
create proc updateWork
#EmployerName nvarchar(max),
#Employer nvarchar(max)
as
begin
update tblWorkData set EmployerName=#EmployerName where EmployerName=#Employer
end
I changed the whereclause as I guess you meant it to be. As it was before it didn't actually do anything at all.
On a side note you might want to look into how to properly call procedures and how to add parameters in a way that isn't vulnerable to SQL injection.
You have to connect to the database in order to execute sql statements:
string employer = Session["Employer"].ToString();
// assume connectionString is a valid connection string
using (SqlConnection connection = new SqlConnection(connectionString))
{
connection.Open();
SqlCommand command = connection.CreateCommand();
command.CommandText = "updatework";
command.CommandType = CommandType.StoredProcedure;
command.Parameters.AddWithValue("#EmployerName", employer);
command.ExecuteNonQuery();
}
In my ASP.NET(3.5) project, I am using inbuilt TableAdapters/Dataset for all Data Access. Does it provide the same security as SQLDataSource does from SQL injection? I am using parameters as follows.
Dim myDAL As New ABCTableAdapters.XYZTableAdapter
Label1.Text = myDAL.getDatafromDB(myParameter)
Update 1:
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
Dim myParameter As String = getSafeURL(Request.QueryString("MS_Code")) 'getsafeurl encodes querystring using HttpUtility.UrlEncode
Dim myDAL As New ABCTableAdapters.XYZTableAdapter
Label1.Text = myDAL.getDatafromDB(myParameter)
End Sub
getDatafromDB corresponds to following query present in app_code/DAL.xsd
SELECT something FROM sometable where fieldname = #parameter
Update 2:
If I 'View Code' of XSD I am able to see following
<SelectCommand>
<DbCommand CommandType="Text" ModifiedByUser="true">
<CommandText>SELECT pageContent FROM [content] where name = #name</CommandText>
<Parameters>
<Parameter AllowDbNull="true" AutogeneratedName="name" ColumnName="name" DataSourceName="iseac.dbo.[content]" DataTypeServer="nchar(100)" DbType="String" Direction="Input" ParameterName="#name" Precision="0" ProviderType="NChar" Scale="0" Size="100" SourceColumn="name" SourceColumnNullMapping="false" SourceVersion="Current" />
</Parameters>
</DbCommand>
</SelectCommand>
It depends.
You could get SQL injection if you badly use tableAdapters.
The main thing is to use SqlParameters for all data that is gathered from users.
Can you show some of your data access code ?
Look up here How To: Protect From SQL Injection in ASP.NET
using System.Data;
using System.Data.SqlClient;
using (SqlConnection connection = new SqlConnection(connectionString))
{
DataSet userDataset = new DataSet();
SqlDataAdapter myDataAdapter = new SqlDataAdapter(
"SELECT au_lname, au_fname FROM Authors WHERE au_id = #au_id",
connection);
myCommand.SelectCommand.Parameters.Add("#au_id", SqlDbType.VarChar, 11);
myCommand.SelectCommand.Parameters["#au_id"].Value = SSN.Text;
myDataAdapter.Fill(userDataset);
}
The important part here is that user entered data (what comes in from web request) is passed to DB inside database parameters like #au_id. In that case you are protected from SQL injection.
BAD WAY would be this (DON'T USE THIS):
myCommandText = string.Format(
"SELECT au_lname, au_fname
FROM Authors WHERE au_id = {0}", SSN.Text)
This way user can manipulate what is send to DB and if your connection to DB has enough privileges it can drop tables or database. Or it can silently modify your data and that is even worse.
So, always use database parameters.
Additionally if you do you gain in performance, because DB will cache execution plan and if you later execute same SQL with only different values for parameters, DB already have execution plan and it doesn't need to parse sql again.
I'm using SQL Server 2005 with classic ASP and on a form repost (I post back to the same page), I replace each text field as follows:
course = trim(replace(request("course"),"'","''"))\
The problem with this is if I have to repost the form multiple times in case of validation errors, the tick marks I replace multiply.
Is there another way to safely vet the string fields without doing this kind of replace?
you better use a parametrized query:
dim cmd : set cmd = server.createObject("ADODB.Command")
dim param
dim sql : sql = "INSERT INTO table(course) VALUES (?)"
cmd.ActiveConnection = yourDBconnection
cmd.CommandType = adCmdText
set param = cmd.CreateParameter("course", adVarChar, , 20, request("course"))
cmd.Parameters.Append param
cmd.CommandText = sql
cmd.Execute
so you are completely safe with sql injection
Only replace the ' for use in the sql string. (which you should better do with parameterized queries..)
The easiest way would be to only do the SQL escaping when you're actually inserting into the database:
course = trim(request("course"))
Make a SafeSQL function:
function SafeSQL(TempStr)
SafeSQL = Replace(TempStr,"'","''")
end function
Then, when you're inserting:
"INSERT INTO table(course) VALUES ('" & SafeSQL(course) & "')"
Disclaimer: I only have a working knowledge of ASP, I don't really know the best practices.
you can do this
course = trim(replace(request("course"),"'","&apos ;"))
Please help me to prevent my data from SQL injection.
I have replaced ' with '' (single quote with 2 quote) while doing any operation on sql server.
Please tell me what all i need to do , to prevent my application from SQL injection. my application is in asp.net 2.0
i will use parameterized queries but what about my old projects.. i mean what about where i have written a string query and sending it to sql server as a commandtext.
Please tell me can any one insert sql injection even i have replaced ' with ''?
The best you can do is to use parameterized queries, if the language/framework supports it.
EDIT: asp.net can handle it. Use SqlCommand
An example from here -
private static void UpdateDemographics(Int32 customerID,
string demoXml, string connectionString)
{
// Update the demographics for a store, which is stored
// in an xml column.
string commandText = "UPDATE Sales.Store SET Demographics = #demographics "
+ "WHERE CustomerID = #ID;";
using (SqlConnection connection = new SqlConnection(connectionString))
{
SqlCommand command = new SqlCommand(commandText, connection);
command.Parameters.Add("#ID", SqlDbType.Int);
command.Parameters["#ID"].Value = customerID;
// Use AddWithValue to assign Demographics.
// SQL Server will implicitly convert strings into XML.
command.Parameters.AddWithValue("#demographics", demoXml);
try
{
connection.Open();
Int32 rowsAffected = command.ExecuteNonQuery();
Console.WriteLine("RowsAffected: {0}", rowsAffected);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
}
Instead of cleaning up the SQL manually, you should be using a library to access SQL.
Do not build up query string manually and if you need to pass parameters through, use parameterized queries and stored procedures.
See this example in VB.NET.
I'm not certain, but I don't think there's any quick easy way to protect your old projects from SQL injection attacks.
I think your best bet would probably be to actually modify the data access code in your old projects to use parameterised queries.
Or, you could do as Oded suggests and re-write your old projects using a library.