Archive

Archive for the ‘Security’ Category

Question of the Day: How do you stop a user from querystring, form post, or web service method parameter injection attacks?

How vulnerable the web is today. There are so many simple ways someone can come along and spoof a query to a server to obtain information that does not belong to them. How much more vulnerable are the web developers who must bear the burden of supporting a web solution and lock down all of those vulnerabilities. If he doesn’t, he could get fired.

A very large percentage of the Internet’s World Wide Web consists of e-commerce catalogs, shopping carts, and order forms. If a web site is well implemented to support its users, it will also expose a "customer service" feature that might show a list of orders in the user’s history. Navigating to one of these orders might allow the user to track the order’s shipment or look up the content of an order. Alternatively, the user could go directly to the order by passing in an order number or ID and getting back the details of the order.

For a querystring aproach, the URL navigating directly to the order might look something like this:

http://www.mysite.com/OrderInfo.aspx?orderid=[orderID]

An HTTP form post will look completely different but will function in the same way. The Order ID will be passed in the body of an HTTP Request rather than in the actual URL.

An attacker can come along and replace the value for the order ID with a value that the user should not have access to. This can be critically dangerous if the order information that is returned consists of credit card information or other transaction data that could result in theft of services either from the web host or from the other users who are associated with the orders that are accessed.

A web service method parameter injection attack is when someone hijacks a SOAP service, such as an .asmx file, and when executing a method they pass method arguments consisting of data other than what was originally intended. For example,

POST /shopping/CustomerService.asmx HTTP/1.1 
Host: services.mysite.com
Content-Type: application/soap+xml; charset=utf-8
<?xml version="1.0" encoding="utf-8"?>
<soap12:Envelope xmlns:xsi=http://www.w3.org/2001/XMLSchema-instance
xmlns:xsd=http://www.w3.org/2001/XMLSchema
xmlns:soap12="http://www.w3.org/2003/05/soap-envelope">
<soap12:Body>
<GetOrderInfo xmlns="http://tempuri.org/">
<A>[orderID]</A>

</GetOrderInfo>
</soap12:Body>
</soap12:Envelope>

This scenario is, for all practical purposes, an identical scenario as the standard form post, you are only changing the request and response formatting of the data to be computer-readable rather than human-readable. You are still using HTTP, you are still posting the request in the body of the request, and you are still passing in variables as with a form.

In all three of these scenarios (querystrings, form posts, and web service methods), parameters are passed into an HTTP-based bucket that processes the requested data and spits the results out in some form in an HTTP response. The fundamentals are, for the most part, identical between the three, so we will focus on these common elements since the non-matching elements do not really reflect upon user security.

So the big question is, how do you lock down this web site or web solution so that a user can only see his own order and not someone else’s order, in this scenario? There is more than one action to take. Some actions have dependencies on others. But no individual action should stand alone.

Action #1: Authenticate The User’s Identity

The first and most obvious action is to be sure not to pass out data to anyone other than an authenticated user who has access to the type of data being requested in the first place. You might be surprised how often web interfaces will fail to authenticate the user and let any anonymous stranger have access to order information from a URL just like the one above.

In ASP.NET, when a user accesses a web page that takes a parameter such as a querystring value of "orderid=[orderid]" the first thing that should happen in the code-behind is the context of the session should be associated with a credentialed user. If the current user is an anonymous user, the web page should immediately redirect to a login page. (Ideally, this login page should return the user to the same place after logging in, rather than go to the home page.) If the current user is an authenticated user, other actions should be handled.

When dealing with XML web services, you can still retain a user context. You can, for example, pass in user authentication credientials as parameter information. But since you’re working with HTTP, you can still use HTTP basic and digest authentication methods. You can also use token-based authentication, digital certificates, and many other authentication methods.

Action #2: Authenticate The User’s Humanity

A lot of attacks are automated. Consider the example of harvesting credit card numbers by passing in random or consecutive order IDs into the web interface, one after another. Even if there was a one-hour delay between successful queries, the attacker could cause hundreds of thousdands of dollars worth of theft in a matter of a few days.

Unless you’re working with web services (i.e. SOAP) which is never accessed by humans directly, you may want to force the user to pass a test of some sort that ensures that the user is indeed human and not an automation "bot" that is scouring the web page programmatically. An example of this is using an image validation technique where text or drawings are displayed to the user and the user must type into a textbox exactly what is being displayed. These images should be sufficiently distorted so that modern OCR (optical character recognition) software cannot programmatically determine what is being displayed. You might also try retaining a large collection of drawings and requiring the user to describe the drawing. For example, the drawing of a house could require "house", or the drawing of a tree should require "tree".

Action #3: Audit The User’s Actions

Auditing is such a severely overlooked security measure. Sure, it won’t stop an attacker dead in his tracks at the moment he is initiating an attack with you. But it can stop an attacker from attacking you in general in the future by helping you detect the attack and monitor the attacker’s actions.

Auditing here does not mean getting evaluated by the IRS. It simply means that for every action that a user performs on a web site, a small record of information is logged into the database regarding

  • who the user was,
  • where the user was (IP address),
  • what the user was doing at what URL,
  • at what date/time, and
  • with what general result (success / fail),
  • etc.

Much of these logs are already captured by Windows Internet Information Services. However, those logs are not queryable. Retaining redundant log data in SQL server will allow you to utilize them to perform SQL lookups in real-time in your web application to impose security rules on the basis of user’s history, both recent and distant.

And you actually can use audit logs to stop attackers on the spot on the basis of irregular activity. For example, these should raise red flags:

  • Someone at the same IP address keeps logging in as someone else, many times (hundreds) in a very short time span (one hour).
  • A user is repeatedly (more than ten times) getting security-related errors from your web interfaces
  • A user is accessing many different orders at once,
  • etc.

This isn’t as effective in XML web services (i.e SOAP) because those web interfaces are often there to make obtaining collections of data easier in the first place. On the other hand, you can still establish hard and fast business rules that can still raise red flags when a SOAP consumer performs actions that are irregular.

Action #4: Associate The User With The Data

This is the most important action to take in any database-driven web solution where security is important. If you fail to implement any of these actions, at least implement this action.

A sensitive chunk of data (i.e. a record in the database) should always be associated with the user in some way. If the user represents an account, as with an e-commerce shopping cart type of web site, then the database records in question (the orders) should include the user ID as an element of its record. The only way that the order should be accessible to the user is if the user is the user associated with the order. This is implemented in SQL using an inner join:

SELECT * FROM ORDERS INNER JOIN USERS ON ORDERS.USERID = USERS.USERID
WHERE ORDERS.ORDERID = '[order ID]' AND ORDERS.USERID = '[current user ID]'

We perform a join to the Users table here because the user ID on the order record may have become invalid for whatever reason by not having an associated record in the USERS table. The WHERE clause could be extended such that USERS.STATUS = ‘Active’ or something similar, to be sure that the user is still an active account.

Take advantage of multi-tier programming!

For practical purposes, this should not be implemented on the user interface code-behind or even in the SOAP code-behind. This is a practical example where a middle layer class library should expose the interface to order information such as with an Order class with a static method,

public static Order GetOrder(string orderID, User queryingUser) {
    // ...
}

Whenever a data query is made to obtain an order record, this middle layer should be called upon to access the data. The interface on this middle layer should require not only the order ID but also, who wants to know? This way, rather than adding the demonstrated SQL join directly within every page code-behind or web service code-behind where data is retrieved, your page and web service code-behind implementations instead query this middle tier to request business objects, where such security validation is already implemented.

Eliminating redundancy by taking the layered approach affects not only the efficiency of your programming efforts but also security. Security holes are always the result of someone either not caring, not knowing potential flaws, or not remembering the agreed-upon security standards. By continuously having to manually add SQL joins for security in every user interface binding, you’re setting yourself up for a mess. What if the security standards change? You have to go back and iterate through all of your web pages to clean that up. What if you made a typo or forgot a security condition in your WHERE clause? Will someone have to be robbed before you ever find out? Forcing all data to go through a common layer where the security logic is implemented as few times as possible will ensure that you only worry about it on a universal basis rather than on a page basis.

I have also seen this type of security implemented directly on the data tier rather than the business layer, in a database form of an ACL (Access Control List). All tables in the database had a security ID column, and all users and teams of users were issued a security ID. Whenever a query was made to the database for any reason or for any data, a JOIN was implemented on the custom OLE-DB provider that enforced record-level security on the basis of this ID. If the user did not match the security ID of the record, and none of the teams that the user was on matched the security ID of the record, then the user simply could not see the record. It was as though the record did not exist.

Unfortunately, short of a the data access layer security described above, tying a record directly to a user is not always possible, which is why there are also other actions to take.

Action #5: Spoonfeed Your Querystrings

You can also try "spoonfeeding" your querystrings. If a user logs in and accesses a "customer service" section of the web site, the URLs that are available to the user that enable access to the order details can be:

  • dynamically generated with a query identifier,
  • timestamped with a timeout, and
  • stored in the session, and dropped when the session times out

Let’s say a user accesses a customer services section of a web page where order history can be found. Each URL exposed to the user is not only generated in the form of a hyperlink, but it is also added to the Session object in an array of spoonfed URLs. When the user clicks on a hyperlink, the Session is scanned for the URL being requested before the requested page is processed, to be sure that the URL was issued to the user in the first place. If the user changes the querystring in any way, there is a mismatch, and the query fails. Likewise, if the timestamp on the querystring has expired, the query will fail.

Although this approach helps, there are of course caveats. The first caveat is that this isn’t a client attributable query. You may as well store all of the parameters of the query on the server, because if the client is going to present legitimate custom parameters in the query then it isn’t a server-spoonfed query, is it? The second caveat is that this is only a solution for querystrings. Applying this technique to form posts and XML web service requests, which tend to be large, is not very practical. The body of the request would have to be spoonfed and/or completely predicted with the prediction hosted on the server, at which point there is no reason to support the post in the first place when a querystring to acquire the same data will suffice.

This is not to say that you cannot add custom parameters to a spoonfed query. It only means that those custom parameters cannot be secured without taking other actions.

Action #6: Serve Only Hashbrowns (Hash Your Queries)

As an extension of Action #5 (Spoonfeed Your Data), you can also tamper-proof your spoonfed queries by hashing the queries. By passing the querystring through an MD5 encryption routine before reformatting it for URI compliance and then passing it on to the user, you eliminate the ability of the user to just go in and change values around in the query. This is an encoded string, and changing characters around will result in a corrupted string.

Although this solution is foolproof, the problem with this approach is that the queries would have to be generated on the server. If the queries are generated on the client, the algorithm or a public key would have to be known on the client side, which eliminates the utility of hashing. The only security advantage of client-hashed communications with a server in any client-server implementation is keeping transitive listeners (i.e. proxy servers, snooping routers, or wireless data decrypters) from hijacking and decrypting your queries. And how often does that really happen?

As we discussed in Action #5, the reason why hashed queries being limited to server generation is a problem is because, frankly, there are few times when server-issued query is useful. It is useful in our case because a user will typically only have a handful of orders, so capturing their predefined queries is a reasonably accomplishable task. But consider the users who have 5,000 orders in their history, on a B2B fulfillment company web site. Hashing and spoonfeeding 5,000 distinct queries would not only involve a slow and heavy load on the server, it would also significantly limit the user interface options for finding an appropriate order. Suppose the user wanted to find all orders that included at least one gallon of milk. Suppose the user performed twenty different searches before agreeing on the best search criteria. If all orders are accessible only by pre-defined, dynamically generated, encrypted URLs, this would not be possible for someone with a large order history.

This is why the other actions are so important. By forcing the user to log in and restricting the data to what the user has access to, for example, you eliminate the bulk of the security concerns on a web solution.

Action #7: Follow Microsoft Best Practices

Microsoft covered additional tips at a more technical level for ASP.NET in an article located here:

How To: Protect From Injection Attacks in ASP.NET

The article adds these steps:

Step 1. Use ASP.NET Request Validation
Step 2. Constrain Input
Step 3. Encode Unsafe Output
Step 4. Use Command Parameters for SQL Queries
Step 5. Verify that ASP.NET Errors Are Not Returned to the Client

Conclusion

We evaluated multiple techniques that can be used to keep attackers from hijacking web interfaces that expose sensitive data on the basis of the parameters being passed in with a querystring, form post, or web service method, the most common dynamic interfaces for querying for data on the World Wide Web. Web Services security also goes much deeper than we delved here, instituting such tactics as binary serialization, WSE, and pre-salted deep encryption. But hopefully the fundamental bases have been covered in this perusal of proactive actions to enforce security on the Web.

Advertisements
Categories: Security

Question of the Day: What is a salt?

A salt is used in cryptography to make decryption less efficient for attackers by adding another hashing layer on top of an encryption algorithm. When a passphrase is used to encrypt data, a salt can be additional data that gets concatonated to the passphrase or key. This means that the attacker’s dictionary now needs to contain many more entries, one for each possible salt value for each probable passphrase.

Salts are implemented as random bits. They are used as a second argument along with the passphrase in a function that is used to derive a decryption key.

For practical purposes, you can use salts as a second passphrase equivalent across services, such as for example when interfacing with a third party web service that intends to be synchronized. By agreeing upon a common salt or salt algorithm, such as making it time-based, you can support handshaking while retaining an extent of cryptographic security.

For more information, the following Googled links are just a tiny few of the resources that describe salt in the context of cryptography and some of them provide a good introduction to cryptographic principles:

Categories: Security