Page 1 of 2

Numbers

Posted: Tue May 09, 2006 12:00 pm
by s.dot
If I expect a number to be 34 for example, and I do the following check:

Code: Select all

if(!is_numeric($_POST['number'])){
    die('Invalid ID.');
}
OR

Code: Select all

if(!in_array($_POST['num'],array(1,34,57))){
    die('Invalid ID.');
}
Does that still need to be escaped or cleaned with mysql_real_escape_string(), stripslashes(), strip_tags(), htmlentities() or the likes? Or is it guaranteed to be a number?

I'm curious because I've seen some people use hex representation of ascii text to get around some blocks on other web sites.

Posted: Tue May 09, 2006 12:15 pm
by angus
A number can only have 1 decimal point and numbers (obviously), thats what I believe is_numeric is looking for. SO I wouldn't have thought so.

Posted: Tue May 09, 2006 12:42 pm
by RobertGonzalez
Why not run an is_numeric test on the value 1,000.00 and see what is returned. I know that a decimal point is allowed in is_numeric, but I am not sure if commas are.

Another thing you can do is type cast the value to an integer or use int_val to return the numeric (integer) value of the posted data.

Posted: Tue May 09, 2006 3:58 pm
by Oren
angus wrote:A number can only have 1 decimal point and numbers (obviously), thats what I believe is_numeric is looking for. SO I wouldn't have thought so.
That's not true, have a read at http://us2.php.net/manual/en/function.is-numeric.php

scottayy: It may help if you tell us exactly what this number can be (e.g can it be 034? can it be 34.00?).

Posted: Tue May 09, 2006 5:25 pm
by $phpNut
I stand corrected :lol:

Forgot about signs and standard form ... and I did A Level Math aswell 8O reasuring :D

Posted: Wed May 10, 2006 12:41 am
by s.dot
It will be an integer, usually an auto incremented id from a database

so could be in the range from 1 to X, but won't have 0s in front or contain decimal points.

Posted: Wed May 10, 2006 2:43 am
by Benjamin
Use

Code: Select all

ctype_digit
You may want to check string length as well. That should be secure.

Posted: Wed May 10, 2006 3:24 am
by Maugrim_The_Reaper
Simplest method is to cast the variable - to integer or float depending on the number (float is needed for very large numbers or you lose data). ctype_digit() will only accept numerals - not decimal points or hex. is_numeric() accepts numerals, decimal point and hex (hence those bypasses mentioned earlier) but never ever accepts the comma separator even if you switch the locale (annoying in many ways).
Does that still need to be escaped or cleaned with mysql_real_escape_string(), stripslashes(), strip_tags(), htmlentities() or the likes? Or is it guaranteed to be a number?
If input filtering is separated into a separate layer from escaping, then it often makes sense to add the extra measures even though they appear to be wasted effort. The idea is called Defense in Depth and attempts to ensure an application is not reliant on just one protective measure (which could conceivably fail for any number of reasons - the common one being developer error) and has a backup or three...

Posted: Wed May 10, 2006 7:27 am
by matthijs
If I may ask: there's one thing I don't understand about casting. It's often recommended as a method to validate numeric data. From PHP architects guide to php security: "A cast forces PHP to convert the parameter from a string to a numeric value, ensuring that the input is a valid number".
Example:

Code: Select all

$_GET['product_id'] = (int) $_GET['product_id'];
But the thing is, if someone or something is inputting a non-valid value, input you don't want, isn't it better - at least in some situations - to throw an error or exception when wrong input is entered?

As I see it, the first layer of input filtering/validation should check all input and if any wrong input is entered, an error, warning, message or whatever must be returned. Then the second layer is or could be something like casting to make sure the processing logic only works with the right input. It's just that casting (again, in some situations I can think of) is like: "ok, the data is bad but I'll accept it anyway and clean it up for you".

Posted: Wed May 10, 2006 8:48 am
by Maugrim_The_Reaper
Keep in mind filtering and validation are themselves two discrete ideas. They often overlap or are integrated into the same step), but are not always one and the same. Take the example of using casting to "validate" numeric data. Casting by itself cannot validate a numeric value in the context of your application - it only ensures a value is filtered and ensures it is a numeral - assuming you take filtering to be a narrow upfront check. Actual validation would involve additional tests specific to your app.

As an example, I could be sending an item id to a shopping app. Casting the $_POST value to Integer does not validate the value - it filters out obviously invalid data. I still need to check the item id corresponds to a valid item. In other contexts there may be MIN/MAX contraints, a non-ranged series of valid values, etc.

Posted: Wed May 10, 2006 9:00 am
by matthijs
Some good points.

But, to take your example of the shopping cart: say I have 10 items which you can buy. They have product_id 1, product_id 2,3, ..10. Now my shopping cart recieves the following:
shop.php?buyitem=3.24523

Now, casting this will convert this to buyitem=3. But the original value was not valid. So I am now processing something which I probably should not, because the 3.245 means someone is trying to mess with my script (for example).

So wouldn't you agree that in this case casting is not the first step to take? Instead, when recieving such a value I should send the user to a page with a friendly error message.

Posted: Wed May 10, 2006 10:02 am
by RobertGonzalez
A general rule that I follow (excuse me while I butt in here) is to use query string vars in limited scope. I also have a tendency to know exactly what is coming through them (ie, database id's, etc), so I know what to look for. If the passed var doesn't match the type or format I expect, I error the script and send a message to the user. This is just me, more than anything, because I hate when apps don't work the way they are supposed even when someone screws around with it.

As for type casting, it is a secondary cautionary measure, at least for me, and I use it only if I need to, after validating the passed data against what I expect it to be.

/excuses himself on the way out

OK, you all can carry on.

Posted: Wed May 10, 2006 10:20 am
by Maugrim_The_Reaper
In this case ctype_digit() will detect the decimal allowing you to pass an error/redirect - it's the best way of ensuring whole number values are being passed - not simply a value to be cast as integer... As you say, this is a specific example - and its one where the context demands something outside simple casting. Actually in this case, casting would "fix" the user input which in general is not recommended if it can lead to a mistake in setting up a shopping cart for a user. Fixing input can become a bad practice to get into to - let the user make the corrections, its their request! :)

I think the moral of the thread should be that filtering/validating should be very specific, precise and appropriate for its context in an application. Anything else is inviting potential trouble...

To Everah, I take the lazy approach of escaping everything entering the database. My open source projects all use the variable binding structure provided by ADOdb and ADOdb Lite which quote and escape all values without mucking around with mysql_real_escape_string() every second line...;) Lazy, but highly effective...

Posted: Wed May 10, 2006 10:20 am
by Oren
scottayy wrote:It will be an integer, usually an auto incremented id from a database

so could be in the range from 1 to X, but won't have 0s in front or contain decimal points.
I agree with Everah:
Everah wrote:As for type casting, it is a secondary cautionary measure, at least for me, and I use it only if I need to, after validating the passed data against what I expect it to be.
But since GET data is always a string, I don't see another option other than type casting if you want to keep things simple (= not using regex).

Posted: Wed May 10, 2006 10:33 am
by RobertGonzalez
Maugrim_The_Reaper wrote:To Everah, I take the lazy approach of escaping everything entering the database.
Lazy, secure, good programming... That's just semantics. I am with you. Nothing gets close to my database without some sort of washing. Especially when it comes to things coming from the querystring. But like I said, I have minimized my reliance on querystring data being passed to my apps. Almost everything is passed through post, and even then, I validate and revalidate the crap out of it.
Oren wrote:But since GET data is always a string...
Even integer values? I wasn't aware of this. I do know that asking if a querystring numeric value is numeric (is_numeric) returns true when the value is numeric. But I never looked at querystring data being a string always. Interesting.