Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống
1
/ 50 trang
THÔNG TIN TÀI LIỆU
Thông tin cơ bản
Định dạng
Số trang
50
Dung lượng
0,98 MB
Nội dung
The text entered into the text box has added an extra test to the
WHERE
clause, and this test will
be
true
for every row in the table; therefore, all the rows are returned. If, for example, you were
collecting a username and password from a visitor and creating a SQL statement this way, you
could find that your system is open to attack from this type of value entered by a user. For
example, you might construct the SQL statement for such a process by using code like this:
sSQL = “SELECT UserID FROM Users WHERE UserID = ‘“ & txtUser.Text
& “‘ AND Password = ‘“ & txtPassword.Text & “‘“
In theory, this will return a row only when the user ID and password match the entries in the
database. However, by using the technique just demonstrated, a visitor could contrive to have
the following SQL statement executed:
SELECT UserID FROM Users WHERE UserID = ‘johndoe’
AND Password = ‘secret’ or ‘1’ = ‘1’
This would return a non-empty rowset, and if you only check whether there are any rows
returned, you might find that your security has been breached.
However, if you enter the same text into the second text box in the sample page and click the
second Go button to execute the SQL string with the value as a parameter, you’ll see that no
rows are returned (see Figure 10.4).
10
Relational Data-Handling Techniques
388
FIGURE 10.4 The result of entering a mali-
cious string for the parameter
to a SQL statement.
To understand why no rows are returned in this example, you can open the Profiler utility (by
selecting Start, Microsoft SQL Server, Profiler) and trace the actions taken in the database. In this
case, this is the instruction that SQL Server executes:
exec sp_executesql N’SELECT CustomerID, CompanyName, City, Country
FROM Customers WHERE CustomerID LIKE @CustomerID’,
N’@CustomerID nvarchar(4000)’, @CustomerID = N’’’ or ‘’1’’=’’1’
In other words, SQL Server is passing the SQL statement and the parameter separately to the
system stored procedure named
sp_executesql
, and it is specifying that the parameter is a
14 0672326744 CH10 5/4/04 12:23 PM Page 388
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
389
Using Parameters with SQL Statements and Stored Procedures
character string (
nvarchar
). This string does
not match the value in the
CustomerID
column
of any row, so no rows are returned.
It Gets Even Worse…
The problem with the literal construction of
the SQL statement described in the preceding
section actually leaves you open to risks that
are even more serious than you might think.
For example, if you enter the following text
into the first text box and execute it, you’ll
see that the SQL statement shown in Figure
10.5 is used:
‘; update customers set city=’here!’ where customerID like ‘BOLID
In fact, this is a batch statement that contains two separate SQL statements. The first one fails to
find any rows that match the empty string in the
WHERE
clause, but then the second one is
executed, and it updates the table.
How to Use SQL Profiler
To use SQL Profiler, open it from the Start
menu or the Tools menu in Enterprise
Manager and select File, New Trace to
connect to your database. In the Trace
Properties dialog that appears, select the
Events tab and make sure that the complete
set of actions for the Stored Procedure entry
in the list of available TSQL event classes
(displayed in the right-hand list) is selected.
Then click Run, and you’ll see the statements
that are being executed appear in the main
Profiler window.
FIGURE 10.5 A malicious value that
updates the source table in
the database.
If you now change the value in the first text box and display the rows for customers whose IDs
start with
BO
, you’ll see that the first one has been updated (see Figure 10.6). However, if you try
this with the second text box, you’ll find that—as before—the process has no effect on the origi-
nal data. The value that is entered and passed to SQL Server as a parameter simply fails to match
any existing rows in the table, and nothing is changed or returned.
One consolation is that the attack could be worse. For example, your malicious visitor could
have entered this instead:
‘; drop database Northwind
This deletes the database altogether. (The double hyphen at the end is a rem or comment marker
that forces SQL Server to ignore the final apostrophe that gets added to the statement batch.)
So if you construct SQL statements dynamically in your code and there’s any risk at all that the
values you use might contain something other than you expect, you should always use parame-
ters to build the SQL statement. In fact, it’s not a bad idea to do it every time!
14 0672326744 CH10 5/4/04 12:23 PM Page 389
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
The Code for Adding Parameters
The code used in the sample page shown in Figures 10.1 through 10.6 contains two routines—
one for each of the two Go buttons in the page. The first one builds the SQL statement in literal
fashion, using the following:
Dim sSQL As String = “SELECT CustomerID, CompanyName, City, “ _
& “Country FROM Customers “ _
& “WHERE CustomerID LIKE ‘“ & sParam & “‘“
In this case,
sParam
is the value extracted from the first text box on the page. This SQL statement
is then executed and the result is assigned to the
DataSource
property of the
DataGrid
control on
the page in the usual way.
The second routine, which runs when the second Go button is clicked, works a little differently
from the first. Listing 10.1 shows the complete routine. After collecting the value from the
second text box, the routine declares the SQL statement. However, this time, the
WHERE
clause
contains a parameter named
@CustomerID
:
“WHERE CustomerID LIKE @CustomerID”
LISTING 10.1 A Routine to Execute a SQL Statement with a Parameter
Sub UseParamValue(sender As Object, e As EventArgs)
‘ get input value from TextBox
Dim sParam As String = txtParam.Text
‘ declare SQL statement containing parameter
Dim sSQL As String = “SELECT CustomerID, CompanyName, City, “ _
& “Country FROM Customers “ _
& “WHERE CustomerID LIKE @CustomerID”
‘ get connection string, create connection and command
Dim sConnect As String = _
ConfigurationSettings.AppSettings(“NorthwindSqlClientConnectString”)
10
Relational Data-Handling Techniques
390
FIGURE 10.6 The result of executing the
batch command shown in
Figure 10.5.
14 0672326744 CH10 5/4/04 12:23 PM Page 390
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
391
Using Parameters with SQL Statements and Stored Procedures
Dim oCon As New SqlConnection(sConnect)
Dim oCmd As New SqlCommand(sSQL, oCon)
Try
‘ specify query type, add parameter and open connection
oCmd.Parameters.Add(“@CustomerID”, sParam)
oCmd.CommandType = CommandType.Text
oCon.Open()
‘ execute query and assign result to DataGrid
dgr1.DataSource = oCmd.ExecuteReader()
dgr1.DataBind()
‘close connection afterwards
oCon.Close()
‘ display SQL statement in page and show hint
lblResult.Text = “Executed: “ & sSQL
lblHint.Visible = True
Catch oErr As Exception
‘ be sure to close connection if error occurs
‘ can call Close more than once if required - no exception
‘ is generated if Connection is already closed
oCon.Close()
lblResult.Text = “<font color=’red’><b>ERROR: </b>” _
& oErr.Message & “</font>”
End Try
End Sub
Next, you create the
Connection
instance and
Command
instance as usual. Before executing the SQL
statement, however, you have to add a parameter to the
Command
instance to match the parame-
ter declared within the SQL statement. The sample code uses the simplest override of the
Add
method for the
Parameters
collection of the
Command
instance and specifies the name and value of
the parameter. The data type of the variable is automatically used to set the data type of the
parameter—in this case, a
String
data type, which means that the parameter will be treated as
being of type
nvarchar
(
System.Data.SqlDbType.NVarChar
) when SQL Server processes it.
LISTING 10.1 Continued
14 0672326744 CH10 5/4/04 12:23 PM Page 391
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
Notice also that you still have to use the value
Text
for the
CommandType
property of the
Command
instance because this is still a SQL statement
and not a stored procedure. (
Text
is the default,
so you could, in fact, omit it altogether.)
Ordering of Stored Procedures
and Query Parameters
A parameter-related issue can cause problems
if you are not aware of it. It concerns the way
that the different .NET Framework data
providers handle parameters when you specify
them by name. The sample page shown in
Figure 10.7 helps illustrate this issue.
10
Relational Data-Handling Techniques
392
Parameter Name Prefixes in SQL Server
In databases other than SQL Server or Sybase
databases, you use just a question mark (
?)
as the parameter placeholder. If there is more
than one parameter, you use multiple ques-
tion mark placeholders and you must add the
parameters to the
Parameters collection of
the
Command instance in the same order that
the placeholders appear in the SQL state-
ment. The names of the parameters are
ignored in this case. You can use this same
syntax with SQL Server and Sybase as well,
although the named parameter technique is
usually more readable and less error prone.
FIGURE 10.7
The ordering of stored proce-
dure parameters that are
specified by name.
The sample page uses two stored procedures—one in SQL Server and one in an Access
database—and executes them by using the various data providers that are part of the .NET
Framework. The SQL Server stored procedure is as follows:
CREATE PROCEDURE ParamOrderProc
@Param1 varchar (10) = ‘Default1’,
@Default varchar (10) = ‘Default2’,
@Param2 varchar (10) = ‘Default3’,
@Param3 varchar (10) = ‘Default4’
AS
SELECT @Param1 + ‘, ‘ + @Default + ‘, ‘ + @Param2 + ‘, ‘ + @Param3
14 0672326744 CH10 5/4/04 12:23 PM Page 392
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
393
Using Parameters with SQL Statements and Stored Procedures
This SQL Server stored procedure simply
collects the values of the four parameters you
provide when the stored procedure is
executed, and it returns a character string
that concatenates their values together.
However, the point here is that they are all
optional parameters, which means that not
all of them must be specified when you
execute the stored procedure. If the code that
executes the procedure does not provide a
value for one of the parameters, the default
value specified within the stored procedure is
used instead.
Unfortunately, however, Access doesn’t
support optional parameters, so the Access
query used in the sample page has only three
parameters and no default values:
PARAMETERS Param1 Text(10), Param2 Text(10), Param3 Text(10);
SELECT [Param1] + ‘, ‘ + [Param2] + ‘, ‘ + [Param3] AS Expr1;
The strange effects shown in Figure 10.7 come about because when you call the stored proce-
dure, you add the parameters in a different order from which they are defined in the stored
procedures:
oCmd.Parameters.Add(“@Param1”, “Value1”)
oCmd.Parameters.Add(“@Param3”, “Value3”)
oCmd.Parameters.Add(“@Param2”, “Value2”)
The result shown in Figure 10.7 proves that with the exception of the
SqlClient
classes, the
names you provide for parameters have no effect. They are ignored, and the parameters are
passed to the stored procedure by position and not by name. You get back the three values in
the same order as you specified them, even though the parameters’ names don’t match.
However, with the
SqlClient
classes, the result is different. With these classes, parameters are
passed by name, so you get back the values in an order that matches the order within the
Parameters
collection. The order in which you add them to the
Parameters
collection doesn’t
matter; each one will match up with the corresponding named parameter in the stored
procedure.
Using Default Values in a Stored Procedure
The previous example uses a stored procedure containing optional parameters. When you declare
a parameter in a stored procedure in SQL Server and most other enterprise-level database
systems, you can provide a default value for the parameter. In fact, it is required because this is
how the database knows that it is an optional parameter. Without a default value, you’ll get an
error if you call the procedure without providing a value for that parameter.
Installing the Stored Procedure for
This Example
A SQL script named ParamOrderProc.sql is
provided in the
databases subfolder of the
samples you can download for this book (see
www.daveandal.net/books/6744/). You can
use this script to create the stored procedure
for the example. For SQL Server, you open
Query Analyzer from the SQL Server section of
your Start menu, select the Northwind data-
base, and then open the script file and execute
it. You must have owner or administrator
permission to create the stored procedure.
14 0672326744 CH10 5/4/04 12:23 PM Page 393
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
By taking advantage of sensible defaults for your parameters, you can simplify the data access
code you have to write in your ASP.NET pages and data access components. Listing 10.2 shows
the stored procedure used in the sample page for this section of the chapter. It is designed to
update rows in the
Orders
table of the Northwind sample database, and you can see that it takes
12 parameters.
LISTING 10.2 A Stored Procedure That Provides Sensible Default Values
CREATE PROCEDURE ParamDefaultProc
@OrderID int, @CustomerID nchar(5),
@OrderDate datetime = NULL, @RequiredDate datetime = NULL,
@ShippedDate datetime = NULL, @ShipVia int = 1,
@Freight money = 25, @ShipName nvarchar(40) = NULL,
@ShipAddress nvarchar(60) = NULL, @ShipCity nvarchar(15) = NULL,
@ShipPostalCode nvarchar(10) = NULL, @ShipCountry nvarchar(15) = NULL
AS
IF @OrderDate IS NULL
BEGIN
SET @OrderDate = GETDATE()
END
IF @RequiredDate IS NULL
BEGIN
RAISERROR(‘Procedure ParamDefaultProc: you must
provide a value for the RequiredDate’,
1, 1) WITH LOG
RETURN
END
IF @ShipName IS NULL
BEGIN
SELECT @ShipName = CompanyName, @ShipAddress = Address,
@ShipCity = City, @ShipPostalCode = PostalCode,
@ShipCountry = Country
FROM Customers
WHERE CustomerID = @CustomerID
END
10
Relational Data-Handling Techniques
394
Using Optional Parameters in a Stored Procedure
Optional parameters will only work really successfully when you use the SqlClient data provider
because none of the other data providers (as discussed earlier in this chapter) pass parameters by
name. To use other data providers, which pass parameters by position, you would have to make sure
that the optional parameters are located at the end of the list and provide values for all the parame-
ters up to the ones that you want to use the default values.
BEST PRACTICE
14 0672326744 CH10 5/4/04 12:23 PM Page 394
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
395
Using Parameters with SQL Statements and Stored Procedures
UPDATE Orders SET
OrderDate = @OrderDate, RequiredDate = @RequiredDate,
ShippedDate = @ShippedDate, ShipVia = @ShipVia,
Freight = @Freight, ShipName = @ShipName,
ShipAddress = @ShipAddress, ShipCity = @ShipCity,
ShipPostalCode = @ShipPostalCode, ShipCountry = @ShipCountry
WHERE
OrderID = @OrderID
The first 2 parameters, the order ID and the customer ID, are required. They are used to select
the correct rows in the
Orders
and
Customers
tables within the stored procedure. However, the
remaining 10 parameters are all optional. Notice that a couple of them are set to sensible default
values (the freight cost and shipper ID), but the remainder are set to
NULL
by default.
Inside the stored procedure, the code can figure out what to do if the user doesn’t provide
values for some of the parameters. For example, if the order date is not specified, the obvious
value to use is the current date, which is provided by the
GETDATE
function in SQL Server. All you
have to do is test for the parameter being
NULL
(
IF @OrderDate IS NULL
).
Writing to the Event Log from SQL Server
If the user doesn’t provide a value for the
RequiredDate
parameter when he or she executes the
stored procedure, you want to prevent the update and flag this as an invalid operation. You can
do this by calling the
RAISERROR
method in SQL Server and providing the error message that will
be returned to the user. By adding the
WITH LOG
suffix, you force SQL Server to write a message to
its own error log file and into the Application section of Windows Event Log as well.
The values used for the
RAISERROR
method are the message to write to the error and event logs,
the severity level (which should be between 0 and 18 for non-system-critical messages), and an
arbitrary state value that must be between 1 and 127. It’s also possible to use the
RAISERROR
method to raise system-defined messages or custom messages stored in the SQL Server
sysmessages
table. SQL Server’s Books Online contains more details.
After executing the
RAISERROR
method, the sample page’s code simply returns from the stored
procedure without updating the database row.
Providing a Default Shipping Address
The sample database contains details of the existing customers in the
Customers
table, so it
would seem sensible that when a new order is added, the customer’s address details are used by
default. In this case, you’re updating order rows rather than adding them, but the code still
demonstrates a technique you could use when inserting rows.
If the user does not provide a value for the
@ShipName
parameter (the name of the order recipi-
ent), the stored procedure collects the values for all the address columns from the
Customer
table,
using the
CustomerID
value provided in the mandatory second parameter to the stored proce-
dure.
LISTING 10.2 Continued
14 0672326744 CH10 5/4/04 12:23 PM Page 395
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
Then, finally, the stored procedure executes a SQL statement with a combination of the values
that were specified for the parameters, specified as defaults, or calculated within the stored
procedure code.
The sample page shown in Figure 10.8 uses this stored procedure. It contains a series of controls
where you can enter the values for the parameters and specify whether they are to be set. If a
check box is not set, that parameter will not be added to the
Parameters
collection of the
Command
instance, so the default parameter value will be used within the stored procedure.
10
Relational Data-Handling Techniques
396
FIGURE 10.8
The sample page that uses the stored
procedure with optional parameters.
The right-hand column of the page shows the
values currently in the row in the database
(for columns that can be edited). When you
first load the page, this column is empty.
You’ll see that it is populated after you execute
the stored procedure, so you can tell what
effects your settings have had on the row.
The Code for the Stored Procedure Default
Values Sample Page
The code used for the sample page contains
an event handler routine named
ExecuteSproc
that runs when the Execute button is clicked. Listing 10.3 shows the relevant sections of this
code. After you create the
Connection
and
Command
instances and specify that you’re working with
a stored procedure, you add the two mandatory parameters (the values for which are specified
in page-level variables).
The Sample Page Sets Some of the Values
to Sensible Defaults
By default, the sample page sets the check
box for the
RequiredDate parameter and fills
in some suggested values for this and the
other parameters. Even though
RequiredDate
is an optional parameter, a value must be
provided to prevent an error from being
reported within the procedure. You can click
the Show button on the page to view the
stored procedure code.
14 0672326744 CH10 5/4/04 12:23 PM Page 396
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
397
Using Parameters with SQL Statements and Stored Procedures
Then you test each check box to see if it’s set. If it is set, you add a parameter to the
Command
instance with the value collected from the appropriate text box or drop-down list. After you’ve
added all the parameters, you execute the stored procedure and then check whether any rows
were updated. If no rows were updated, you display an error message in the page.
LISTING 10.3 The ExecuteSproc Routine That Executes the Stored Procedure
Sub ExecuteSproc(sender As Object, args As EventArgs)
‘ get connection string, create connection and command
Dim sConnect As String = ConfigurationSettings.AppSettings( _
“NorthwindSqlClientConnectString”)
Dim oCon As New SqlConnection(sConnect)
Dim oCmd As New SqlCommand(“ParamDefaultProc”, oCon)
Dim iRows As Integer
Try
‘ specify query type, add parameters and execute query
oCmd.Parameters.Add(“@OrderID”, iOrderID)
oCmd.CommandType = CommandType.StoredProcedure
oCmd.Parameters.Add(“@CustomerID”, sCustomerID)
If chkOrderDate.Checked Then
oCmd.Parameters.Add(“@OrderDate”, _
DateTime.Parse(txtOrderDate.Text))
End If
If chkRequiredDate.Checked Then
oCmd.Parameters.Add(“@RequiredDate”, _
DateTime.Parse(txtRequiredDate.Text))
End If
If chkShippedDate.Checked Then
oCmd.Parameters.Add(“@ShippedDate”, _
DateTime.Parse(txtShippedDate.Text))
End If
If chkShipVia.Checked Then
oCmd.Parameters.Add(“@ShipVia”, _
Integer.Parse(lstShipVia.SelectedValue))
End If
If chkFreight.Checked Then
oCmd.Parameters.Add(“@Freight”, _
Decimal.Parse(txtFreight.Text))
End If
If chkShipName.Checked Then
oCmd.Parameters.Add(“@ShipName”, txtShipName.Text)
End If
If chkShipAddress.Checked Then
14 0672326744 CH10 5/4/04 12:23 PM Page 397
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
[...]... select Start, Programs, Administrative Tools, Microsoft NET Framework 1.1 Configuration and open the Assembly Cache section by clicking the link in the left pane of the window All the installed assemblies are listed in the right pane (see Figure 10.16) Writing Provider-Independent Data Access Code FIGURE 10.16 Using the NET Framework 1.1 Configuration utility The Page_Load event handler simply calls... DataList controls) We include this example after seeing a question on the ASP.NET groups as to whether it is possible to handle the changed events for controls located within the output of a DataGrid control and do anything useful with them When you use a DataGrid control or DataList control for inline editing of the data rows in ASP.NET, as demonstrated in Chapter 4, the usual technique for updating... the Provider-Independent Data Access Example ‘ assembly details for System.Data in version 1.1 Dim sFQName As String = “System.Data, Version=1.0.5000.0, “ _ & “Culture=neutral, PublicKeyToken=b77a5c561934e089” Sub Page_Load() ‘ display data using SqlClient classes first time If Not Page.IsPostback... the full metadata for each column, such as primary keys, default values, and constraints n When you intend to perform a subsequent update to the source data n When you are using sorting or paging in an ASP.NET DataGrid control For other tasks, especially simple server-side data binding, the subsequently lower processing and memory overhead of the DataReader class can substantially improve performance... then call its Unwrap method This instantiates the class and returns a reference to the resulting object instance To use these methods, you have to import the System.Runtime.Remoting namespace into your ASP.NET page, along with any namespaces for other classes that you use through static binding However, you don’t have to import the namespaces for the classes that you instantiate dynamically through the... in each row as a selector that the browser will not recognize (and therefore will ignore) But because it is part of the style attribute of the HTML element, it is also part of the Style property of the ASP.NET control that implements the element You can set and read this value in your server-side code and have it persisted in the page, and it will be available following a postback An Alternative Approach . Param1 Text (10 ), Param2 Text (10 ), Param3 Text (10 );
SELECT [Param1] + ‘, ‘ + [Param2] + ‘, ‘ + [Param3] AS Expr1;
The strange effects shown in Figure 10 .7.
nvarchar
(
System.Data.SqlDbType.NVarChar
) when SQL Server processes it.
LISTING 10 .1 Continued
14 0672326744 CH10 5/4/04 12 :23 PM Page 3 91
Please purchase PDF Split-Merge on www.verypdf.com