Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Professional ASP.NET Security - Jeff Ferguson

.pdf
Скачиваний:
28
Добавлен:
24.05.2014
Размер:
13.26 Mб
Скачать

Treating the Client with Caution

<input type="text" id="txtFirstname" MaxLength="40" runat="server" />

The above steps will not prevent the hacker from saving the content of the file into a local HTML file and removing the MaxLength restrictors and reporting the data back to the server. Therefore, it is very import to validate the length at the server side. This can be done by using the Length property of the String object:

String strCustID = txtCustlD.Text().Length(20);

The next step in preventing SQL injection attacks is to remove the single quote from users' input by adding one more single quote next to it, or replacing the single quote with a space. This will prevent this kind of attack.

'Replace the Single Quote with one more single quote

Dim Strlnput as String = txtCustlD.Text().Replace("'", ••'•)

Dim StrSQL as String = "SELECT CustomerlD, CompanyName, ContactName, " & "ContactTitle FROM Customers WHERE CustomerlD = '" & Strlnput &

'Replace the Single Quote with a space

Dim Strlnput as String = txtCustlD.Text().Replace("'", " ")

Dim StrSQL as String = "SELECT CustomerlD, CompanyName, ContactName, " & "ContactTitle FROM Customers WHERE CustomerlD = '" & Strlnput &

If the user input is going to be an integer value, then use validation controls to make sure the user can only enter an integer value in this field. If your SQL query uses a LIKE operator, then look for the % symbol on the user's input, since it can increase the possibility of vulnerability issues.

Another way to tackle SQL injection attacks is by using the parameter collection of the ADO.NET Command object. For example, let's consider the previous SQL injection example, where we build the query dynamically using the string concatenation method. We can fix the single quote manipulation by using the ADO.NET Command object. Here is an example:

String StrSQL

=

"SELECT

CustomerlD,

CompanyName, ContactName, ContactTitle

FROM

 

 

 

 

Customers WHERE

CustomerlD

= SCustID

";

SqlConnection

dbConn = new

 

SqlConnectionf"server=Sruthi;uid=SecureAppUser;pwd=!23Chille32~@@@!;database=North

wind;");

//Open the connection dbConn.Open();

//Create a SQL Command object

SqlCommand sqlCmd = new SqlCommandfStrSQL, dbConn);

sqlCmd.CommandText = StrSQL; sqlCmd.CommandType = CommandType.Text;

sqlCmd.Parameters.Add(new SqlParameter("@CustID", SqlDbType.NChar, 5)); sqlCmd.Parameters[0].Value = txtCustlD.Text;

//Create a datareader, connection object

DataGrd.DataSource = sqlCmd.ExecuteReader(CoiranandBehavior.CloseConnection); DataGrd.DataBind();

The only difference between the previous example and this one is the way we build the dynamic SQL. We use the @Parameter name in the dynamic SQL instead of concatenating the strings, then we pass the values using the SqlCommand object Parameters collection. This method is a safer way to build a dynamic SQL connection since:

Q We do not play with the string concatenation special characters.

Q The data type of the parameter is specified, and if the user has passed an invalid value to the current data type, the query will fail.

Q We've specified the length of the parameter right after the type. This prevents any large amount of data being sent to the database server.

The following screenshot shows how this method of dynamic SQL generation behaves for the user input

ALFKI ' or 1 = 1 --.

SQL Injection

ALFKI

Alfreds Futterkiste Maria Anders Sales Representative

ADO supported the question mark (?) as the parameter substitution and SQL Server .NETData provider doesn 't support it. Instead we have to use the parameter name, as shown above.

When we're passing the input value using the parameter collection, the data will be sent to the database as unstructured data. So there is no side effect of invalid use of the value.

The next major SQL Injection attack, using the extended stored procedure, can be avoided by connecting to the database with an unprivileged account that has just enough privileges to get the job done.

Hidden Form Fields

Web developers use hidden form fields extensively to store data in the browser in a convenient way. Even ASP.NET server control view state information is stored in a hidden variable called _VIEWSTATE. The problem with using hidden fields is that anyone can view the data stored in them by viewing the source of the HTML page. No special tools are necessary. I've seen developers store the session information, shopping cart information, and so on, in hidden fields. Even some high profile online stores use this technique - it's very widely used.

54

Treating the Client with Caution

If the user has even a little knowledge of HTML, they can save the HTML page locally, can change values in the page, and resubmit the page back to the server. For example, suppose that you have a couple of form fields and a few hidden fields that you maintain to track user information. Let's assume that the form fields are all well defined, including the Maxlength property, and that we have put in place some JavaScript validation of user input.

<input

id="Firstname"

type="text" runat="server" maxlength=40

/> <input

id="Lastname"

type="text"

runat="server"

maxlength=40

/> <input

id="Address"

type="text"

runat="server"

maxlength=40

/>

 

<input

id="ID"

type="hidden"

runat="server" value="4343dsdfsd@2323" />

The user could simply save the HTML file into the local hard drive, strip out all the JavaScript code and the entire well-defined HTML code, and load it into the browser. In this situation, the content is loaded in a browser without any validation code: the user can now send whatever they want, since there is now no control in the page. This can also be automated using tools such as Achilles.

So, how do we address this issue? Well, the following guidelines provide a good start:

Q Always check whether the user has a valid session using the ASP.NET Session object.

G Do not store any sensitive information in the hidden form fields. If you can't avoid this, then -when storing the data in the hidden field - store the session key and time stamp in an encrypted form. This will be helpful in validating that the information is coming from the browser.

Q Be prepared to handle the situation when the data in the hidden field is removed. Q Check the length and data type of the parameters on the client side.

Q Redo this validation on the server side. One of the advantages of using ASP.NET Validation controls is that, regardless of the client-side validation, the data will be validated on the server side.

Cookies

Cookies are small pieces of information that are sent as a part of an HTTP header during the HTTP Request and HTTP Response operations. Web developers also use cookies store data on the client. The data stored in the cookie could include such things as session key, browser behaviors, shopping cart information, and so on. The data stored in the cookies is also as vulnerable as the other forms of client-side data that we have been looking at, such as URL parameters, or hidden form field variables. Cookies can be set to be either persistent or non-persistent. In either case, this data stored in the cookie can be manipulated, regardless of its type. For example, a tool such as Winhex (http://www.winhex.com/) could be used to modify a cookie, or you could use client-side JavaScript code.

For example, suppose that your site uses two cookies to maintain user information. The first cookie is the Auth cookie, which maintains the access rights of the user, and the second cookie stores the shopping card information, including Product IDs, prices, and so on. Here is what the cookie data looks like when alert (document. cookie) ; is used.

Microsoft Internet Explorer

xj

 

Auth=Catdog5te=True&Prod5ite-TrueaiAdminS(te=False;

Cart=Pfke-20%2E99%2C3S%2E50%2C19%2£00%2C7%Z£20&Prods=1909%2C2123%2C343l%2C'»411;

ASPSESSIONlDGGQ<MWQQ=a<JPNGFBHHICBNGf*WPMCGLDE

OK

J

As you can see, the Auth cookie maintains the user rights, and the Cart cookie maintains the shopping cart information. The hacker could read this cookie information and change it in the following way:

Auth=CatalogSite=True&ProdSite=True&:AdminSite=True;

Now the hacker has given themself permission to get into the Admin site. If your site just relies on cookie information to authorize the user into the site, then the hacker can very easily get into the Admin site and do all kinds of stuff. In the same way, they can change the information stored in the shopping cart cookie, and might possibly manipulate the price of an item.

Q The best way to avoid this is to not to store any sensitive information in cookies.

Q As an alternative, store encrypted values in the cookies with strong encryption. Also be prepared handle the situation when the cookie information is altered or removed.

Q In ASP.NET, the best way to store sensitive information in a cookie is to use the Forms authentication API to create an encrypted authentication ticket cookie that contains the information. The other way of addressing the problem is using SSL. If you can't avoid storing sensitive information in cookies then use SSL. This is the best way to protect cookies from the prying eyes. But even then, SSL will only secure the session between the server and the client. Even though you're using SSL, the data stored in the cookie can be read or exploited using a Cross-Site Script attack.

Http Referrer

Many developers will base some security decisions on the HTTP_REFERER server variable. For example, an application will check if the referred page is within the same domain, or from a certain page, and will implement security based on this. Let's consider the following example, in which we check the HTTP_REFERER server variable in the Page_Load event. Based on the value of the server variable, we grant access to the browser and display a message in a label.

void Page_Load(Object Src,EventArgs E)

String sSearchStr=""

 

 

NameValueCollection

colQstr

=

Request.ServerVariables;

String!]

qStrAry =

colQstr.AllKeys;

for

(int

i =

0;

i<=

qStrAry.GetUpperBound(O); i++)

if

(qStrAryli]

==

"HTTP_REFERER")

 

String!]

qStrAryVal

=

colQstr.GetValues(i);

 

for

(int

j

= 0;

j<=qStrAryVal.GetUpperBound(0); j++)

56

Treating the Client with Caution

sSearchStr= qStrAryVal[j]; break;

//Compare the HTTP_REFERER server variable

if (sSearchStr == "http://localhost/ch!2/HttpRefferer.html")

{

//Assume that the page is secure and all them to view the private data IblResult.Text = "Access to the private data is granted!";

}

else

{

//Assume that the page is secure and all them to view the private data IblResult.Text = "Access denied!";

As long as the referring page is that specified in our code, access will be granted:

I 5 Http Referrer Variable - Microsoft Internet Explorer

 

 

-JOJ2SJ

FJte £dfi:

Sew Fgvorftes lools

Help I *>Back » •* - <Q ^

 

^}

m

'.^Search

^Favorites 'UfMetla

^J ] [3^*-

 

 

 

 

 

 

 

ji&

^^Hfthttp;//localhost/chl2/HTTP_REFERER_CS.aspx

 

 

 

|

 

 

 

 

 

 

Http Referrer Variable

 

 

 

Access to the private data is granted!

 

 

J

j^jOone

-

|

 

j— j— -jgp]^^^*"

 

 

 

 

j&

The HTTP_REFERER server variable can also be manipulated by a hacker. For example, the WebRequest class in the System.Net namespace enables us to make HTTP requests from any .NET code, such as for screen scraping techniques. When using the WebRequest class, we can utilize the Headers property to change the HTTP Header information. Fortunately, the Headers property prevents changing some parts of the header information including the HTTP_REFERER server variable. But this is not always the case. Many programming environments enable us to change the HTTP header information. There are also many tools available to simulate the HTTP header information. It's wise to conclude that we shouldn't trust the HTTP_REFERER server variable to make security decisions.

Note that, the HTTP_REFERER server variable will be dropped when we're switching from HTTPS to HTTP.

URL

Many developers use URL query strings to pass values from one page to another. The query strings may also be used to maintain state across pages, or - in a Web Farm environment - across servers. Since the query string parameters are text based, and they're very visible in the browser window, the query string values can be tampered with very easily. This is called URL Tampering.

URL Tampering

URL tampering is one of the simplest and commonest ways a web application can be attacked. If your ASP.NET application uses the HTTP GET method rather than HTTP POST, it is far more vulnerable to attack. Let's consider the following scenario. Suppose we had an application that provides a search facility, and that we allow the users to search for customers using their names:

Ana Trujillo Emparedados y helados Ana Trirjillo

nabela Domingues Sales Representatlv

As you can see, we have a textbox to search the customer names, and two radio buttons to specify the search type. Also notice that the Starts With radio button is selected by default. If you look closer at the address bar, you'll see that the application is using the HTTP GET method to post information to the server, and we can see all the information it is transmitting to the server, including the view state information for all the controls and other HTML control information. Users may easily modify and repost the information. If we use HTTP GET and have enabled view state on our page, it will be sent within the URL. If we use POST, it will not.

For example, let's remove "&Search=RdoAnyWhere" from the URL, and reload the page.

TRADH

jTradifao Hipermercados

[Anabela Domingues

Sales

entatw

58

Treating the Client with Caution

This is the complete URL:

http: //localhost/chl2/Input_CS.Aspx? _ VIEWSTATE=dDwyMDg2NzE5NjcyO3Q8O2w8aTwyPj S%2B O2w8dDw7bDxpPDExPjs%2BO2w8dDxAMDw7Ozs7Ozs7Ozs7Pjs7Pjs%2BPjs%2BPjtsPFJkblNOYXJOcztS ZG9BbnlXaGVyZTtSZG9BbnlXaGVyZTs%2BPrftFuUPpRv5X%2FSjXI7ylBbMcitd&txtSearch=Ana&Sea rch=RdoStarts&btnCust=Get+Customer+Info

Notice that the default value selection for the search options has disappeared in the reposted form. In the same way, the user can modify the view state information posted in the URL, and this will break the application. If your application is passing some sensitive information in the URL, then it can again be misused.

For example, let's say that the xyz.com site passes the customer ID as part of the URL to maintain state information, in the following way:

http://localhost/chl2/URL,Tampering_CS.Aspx?CustID=ALFKI

The Page_Load event will take this parameter and build the query.

String sCustID = ReadQueryString("CustID");

String StrSQL = "SELECT CustomerlD, CompanyWame, ContactName, ContactTitle FROM Customers WHERE CustomerlD = '" + sCustID + "'";

When a hacker sees this information, they can modify any of these parameters, including the customer ID, submit it back to the server, and gain access to private information about different users.

3'

Fife

F: i

 

Help

«

4^ Back *

•* - >|J J3 4f

'35ean:h

-^ Address |^} http://!ocalhost/chl2/URLTampenng_VB.

URL Tampering

CustomerlD CornpanyName ContactNameContactTitle

ALFKI

SQL Statement: SELECT CustomerlD, CompanyName, ContactName, ContactTitle FROM Customer; WHERE CustomerlD = 'ALFKI'

Address |^) http;j/localhost/chl2/URLTarrpef>n_VB.Aspx?Cusl:lD-ANATR

URL Tampering

ANATR

 

ContactNa

AnaTrujillo Emparedados .,

 

 

Ana Trujillo

Owner

helados

 

SQL Statement: SELECT CustomerlD, CompanyName, ContactName, ContactTitle FROM Customers

WHERE CustomerlD - 'ANATR'

g? Local intranet

In this case, the server will process inconsistent information. Even though you might use Stored Procedures or parameterized queries, this type of attack can't be prevented, since the information sent from the browser is valid. The easiest way to avoid this kind of URL tampering attack is to not include sensitive information in the URL. You should keep all the sensitive information on the server, or send it in an encrypted format and verify the returned result on the server.

If you want to simulate the POST method, we can use MSXML parsers, XMLHTTP object's POST method from the server side or from client-side JavaScript. Here is a JavaScript example.

var XMLApp = new ActiveXObject("MSXML2.XMLHTTP"); XMLApp.Open "Post","URL with data", false; XMLApp.Send "Posting some data";

We can also use the WebRequest class in the System.Net namespace to do the same.

Content Sucking

Content sucking is a type of attack that is, again, caused by URL tampering vulnerability. These attacks are based on easily guessable URL values. For example, suppose you have a table called Employees, and the employee ID is generated using sequential value generation features, such as Identity columns in MS SQL Server, or Sequences in Oracle. If you are passing the Employee ID in the URL to fetch the employee information, the value can be easily changed, and different employee records may be viewed.

60

Treating tne unem wnn

Ad&ess [|£)"http i //localhost/ch 12/CantentSucking_CS. Aspx?EmpID= 1

Content Sucking

 

 

ErnployeelDlFlrstName LastNan

 

 

 

 

 

 

 

 

 

 

[Nancy

 

Davolio

 

[Sales Representative|(206)

 

 

 

 

 

 

 

 

 

555-98571

 

 

 

 

 

 

SQL Statement' S

 

 

 

 

 

 

 

 

 

 

 

EmploveelD = 1

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

3ft Internet Explorer

 

 

 

 

 

 

 

Fie

Edit

View Favorites Toote

Help v-'Bad*

-

**

' $ J^ ^$

 

 

 

^Search

^j Favorites

^Media

,_^ ^' _f

~^

_^j

?f Address to

 

 

 

http;//localhosychl2;Cor*entSuckJng_C5.Aspx?EmpID-2

 

 

 

 

 

 

 

Content Sucking

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

"Ernpioy'el

First'1 Jams

LastNarn

Title

 

 

 

HomePhone

 

 

 

 

2

Andrew

FuHer

 

Vice President,

 

206) 1^~

 

 

 

 

SQL St*t«mant; £

Employ««ID - 2

This is because the parameter value is very easily guessable. If the information you are showing is sensitive, then this could be a problem. Moreover, this is not just about sensitive information, rather about preventing people from sucking the entire database out. This is not just a problem that affects internet applications: this kind of attack can happen in an intranet scenario. This will allow one employee to see other employee's information. The best way to address this problem is to encrypt the content of the URL, and pass it back and forth. Another way of addressing this issue is by making the URL value not guessable. For example, we could make the field in the database a character field, and could use another means of generate the employee ID.

URL Variations

Since anyone can tamper with the URL parameters, it is wise to encode the URL so that it'll be very hard for anyone to predict the value. For example, if we are passing three values in the query string in the following way:

URLVariations_CS. aspx?CustID=ALFKIScSave=True&PageID=2

we can build a simple encoding method that reads the values from the URL, builds an encoded string, and passes back the encoded URL string. Let's see an example of this. First of all we're going to build two methods to encode and decode the data. The Encode and Decode algorithm is going to be very simple. We're going to get the ASCII value of the current character and we're going to add 5 to it and transform the new value back to an ASCII character. The Decode method does the opposite.

public String encode(String strData)

int i, iStringChar;

61

StringBuilder sbUrl = new StringBuilder(); char ch;

ford = 0; i< strData.Length ; i + + ) {

iStringChar = Asc(strData.Substring(i, 1)) + 5; ch = Chr(iStringChar);

sbUrl.Append(ch); } return sbUrl.ToString() ;

The encode method takes a string as an input and parses each character in the string. Then it finds the ASCII value of the character representation and adds 5 to the current value. It then finds the character value for the new value and adds it to the StringBuilder object.

public String decode(String strData) { int i, iStringChar;

StringBuilder sbUrl = new StringBuilder(); char ch;

ford = 0; i< strData.Length ; i++) {

iStringChar = Asc(strData.Substring(i, 1)) - 5; ch = Chr(iStringChar);

sbUrl.Append(ch); } return sbUrl.ToString();

The decode function does exactly the opposite. Since C# doesn't support the common VB6/VB.NET functions such as Asc and Chr, I've built a custom equivalent in C#.

private int Asc (String S) {

return (int) Encoding. ASCII .GetBytes (S) [0] ; }

private Char Chr (int i) {

return Convert .ToChar (i) ;

If you want to use the UTF or UNICODE character set, then you can use the

Encoding. UTF7 .GetBytes, Encoding. UTF8 .GetBytes, or

Encoding. Unicode. GetBytes methods.

Using this method, all the query string information will encoded into a single element, and all the encoded information will be passed in one single query string. Here's an example of this:

62

Соседние файлы в предмете Программирование