Welcome Guest, Not a member yet? Register   Sign In
Security concerns with input in Codeigniter and SOAP webservice
#1

[eluser]nielsiano[/eluser]
We are using a Microsoft Dynamics NAV SOAP webservice to fetch some product information for a webshop, to fetch it we'll send along parameters such as Brand, Type and Modelnumber

These parameters vary alot in characters, the strings could look like these three:

Modelnumbers:
DSM 9510 XA+
3709 / VITALITY
002.228.31 HÖGVÅRDIG


User has to choose Brand, Type and Modelnumber from dynamically generated selects. In jQuery we then grab the values, string replace the characters which are not permitted in Codeigniter URIs, and then urlencode it before sending it along. Like this:

Code:
var model           = $("select#model").val();
model                = model.replace(/\//g, '_');
model                = encodeURIComponent(model);

var url              = fab + '/' + type + '/'  + model + '/'  + produktnummer;
[removed].href = "categories/" + url;

(window location href used..)

Then in the categories controller in Codeigniter we string replace the forbidden chararacters back to the original. Then do rawurldecode($model) on each parameter.

We now have the needed strings to send to the SOAP Webservice in order to get back the correct results. In our Categories controller we would do (simplified):

Code:
public function index($brand, $type, $model, $productnr = NULL)
{
    $model      = str_replace('_', '/', $model);
    $model      = rawurldecode($model);
    $categories = $this->fetch->get_categories($brand, $type, $model, $productnr);
}

In the fetch model we use a NTLMSoapClient to connect to the Dynamics NAV webservice, as explained in this blogpost:

http://blogs.msdn.com/b/freddyk/archive/...m-php.aspx

If we use htmlentities or similar on the strings, the webservice will not return anything. This is however a big concern, since users could just input whatever they wanted in the URI and it would be rawurldecoded and send along. It must be noted that beforementioned Webservice is a Microsoft Dynamics NAV solution, which does some validation and throws Exceptions whenever something fails, although we have no way of knowing how and what is validated.

This is perhaps not the most clever solution, but we can't figure of any other way of doing this. Although it works it, it worries us. So the question is:

Is there a better and more secure way of archieving this, working with these obscure strings?

A little extra information about the shop:

For the webshop, we have extended the Codeigniter cart, and do not process any payments at site, but use a 3rd party payment gateway to handle that. We just store the temporary order with shipping address as serialized() data in db, and after a successful callback from the payment gateway we flag the order as paid, and send orderinfomation to the Dynamics NAV webservice where the "real" order will get processed. The webshop is on HTTPS. Users can have accounts to view their orders, the orders are also fetched from the Webservice, and not from db. We use Ion Auth for authentication in Codeigniter (http://benedmunds.com/ion_auth/)

I will be happy to elaborate anything, if something is unclear. Thank you!
#2

[eluser]TheFuzzy0ne[/eluser]
I haven't done much with SOAP, (err... in the context of Web services!), but here are my thoughts. Please correct me where I'm wrong, or talking out of my Gary Glitter.

I'm not sure what makes you say it's insecure, isn't it a public read-only API? So long as your API responds correctly, doesn't throw any errors, and doesn't give out information it shouldn't to anyone who doesn't have the relevant permissions, I can't see the problem.

Can you not use POST for your AJAX request? That would allow you to circumvent the allowed_uri_chars problem.

If you must use GET, you could add a little logic to ./application/config/config.php to allow all characters in the URI, based on the current URI.

Another idea might be to use IDs instead of words in your URI. Assuming all of this stuff is stashed away in a database somewhere, it should be fairly easy to work with the IDs.
#3

[eluser]nielsiano[/eluser]
First of all, thanks for answering, I've been having trouble to even have anyone look at it. I'm a tad frustrated as to what we should do actually, and worried that our approach is horrible.

Quote:I'm not sure what makes you say it's insecure, isn't it a public read-only API? So long as your API responds correctly, doesn't throw any errors, and doesn't give out information it shouldn't to anyone who doesn't have the relevant permissions, I can't see the problem.

In CI we have a library called Nav. Nav handles all the SOAP requests back and forth. The Webservice needs credentials, a username and password, which we've been giving. We store those credentials in a config on the server away from the public dir. To explain what's going on at our site, I'll probably have to elaborate a bit:

We are doing lots of AJAX requests (Using CSRF tokens) to this webservice on our site, both reading and writing. Reading products, product information, model numbers and prices. Writing orders and userdata.

The company has all their products and users stored in a Microsoft Navision system. In order to communicate with this system, we have to use the SOAP Webservice. We don't have any products, prices or anything stored in the CI db. All we have is a usertable (using ion_auth) and an temporary orders table. We have extended the CI_Cart to meet our needs. Whenever a user clicks 'Go to payment' the contents of their cart (serialized()) and their userid (ion_auth) is added to our temporary order table. The user then pays for their cart through a 3rd party payment gateway, and that gateway does a server to server callback with a checksum, if everything matches up with the order we have in db, we flag the temporary order as paid in db, and send the order through to Navision through the webservice.

Logged in users can then through their profile see their previous orders and address information, which is all fetched from Navision. They can also change their Address information which is then send and updated directly to their user in Navision. All these things happens in this webservice.

Whenever a user performs these 'logged-in' specific tasks we check if the user is in fact logged in, so we can use his userid (ion_auth) to send the orders and data to the correct user in Navision. We do that with:

Code:
if (!$this->ion_auth->logged_in())
{
echo json_encode(false);
}

Furthermore we do serverside validation on input with the form_validation in CI.

However, users that aren't logged in can and should also be able to place orders in that case the userid is tagged as 'weborder' both in Navision and our temporary orders table. They should provide their name, email, address and so forth along with the order, since we don't have anything on them in Navision. That's all non registered users can do, along with fetching product information etc on the site like regular users.

Quote:Can you not use POST for your AJAX request? That would allow you to circumvent the allowed_uri_chars problem.

We are in fact using POST for all AJAX requests that update and create. The only time we are using GET is when we are reloading the view with new items in the cart. What do you mean by circumvent the uri_chars problem? Perhaps I haven't explained myself thoroughly enough.

Quote:If you must use GET, you could add a little logic to ./application/config/config.php to allow all characters in the URI, based on the current URI.
What would that solve specifically? I'm a bit confused.

At the frontpage of our site users have 3 select lists where they need to choose Brand, Type and Model. When they choose a brand, we do a .post AJAX request and send along the Brand, and in the response we the Types for that Brand, which we use to populate the selectlist. After that the user chooses a Type, and the Model selectlist gets populate with models. (On some models there is 4th option, productnr, which populates another selectlist). When all 3 values have been chosen, the user clicks 'Find Products'. When they click, we get the values, stringreplace forward slash with underscore, urlencode them and do this:

Code:
model                = model.replace(/\//g, '_');
brand                = encodeURIComponent(brand);
var url              = brand + '/' + type + '/'  + model + '/'  + productnr;
window location href = "categories/" + url;

EDIT: The reason for the need for GET and URI parameters is also for a index, e.g. all products for a specific model which all links to a
Code:
/products/itemid/name-of-the-product
URI, so that every single product will get indexed by google, else I don't think that would be possible.

We need to query with all sorts of parameters when fetching product information, for example, to get all products that matches multiple parameters we need to send along 'Brand', 'Type', 'Model' which will give us an array of possible products matching those terms. So in order to get that list of products to the user we have to do
Code:
http://site/app/categories/BRAUN/BLENDER/4184 _ MX 2000
(The URI encodings isn't showing here on the forum).
Those URI segments is the parameters we send along to the webservice, in order to get that list.
So in this case, Braun is $brand, blender is $type, 4184.. is $model which gives us a list of perhaps 10 items along with their prices.

I feel like I'm rambling here, am I making any sense? The way we have done it works, but I'm am not at all sure that this is the most optimal and clever of achieving this. How would you go about solving this? Please, if you want me to elaborate on anything, I'll be more than happy to do so.

Thanks in advance, I really appreciate it!
#4

[eluser]nielsiano[/eluser]
Wrong edit. Woops, sorry about that.




Theme © iAndrew 2016 - Forum software by © MyBB