Forum Moderators: coopster

Message Too Old, No Replies

Form Validation

Is this needed?

         

spyder_tek

9:11 am on Feb 4, 2006 (gmt 0)

10+ Year Member



In terms of security...

Do checkbox values need to be validated?

For example, if my script processes:

<input type="checkbox" name="checkbox1" value="checkbox1">
<input type="checkbox" name="checkbox2" value="checkbox2">

Would a user be able to change the "name=checkbox1" or "value=checkbox1" to insert malicious data?

Also, if a textarea box within the same form is only used to display echoed data from the script, does this need to be validated as well?

Thanks.

simon2263

10:40 am on Feb 4, 2006 (gmt 0)

10+ Year Member



A malicious user could well write their own form to send data to your script, while you might not need to do validation on the page (using Javascript), it's a good idea to check the values received by the script. I can't off-hand think of a reason to change the field NAMES, though - maybe this isn't such a threat.

If the content of the textarea box is used by the receiving box then it ought also to be checked.

Question:
--------
In Perl, there is a "taint" flag that warns you when you use data from forms unchecked - does PHP have a similar facility anyone?

Gero_Master

12:08 pm on Feb 4, 2006 (gmt 0)

10+ Year Member



One possibility to check if the form is sent from the page you wante is to check the referrer

First, do a test, send the form and make your validation page display the $_SERVER['HTTP_REFERRER'] value. This value must not be sent with the form.

Now, it should say your webpages url. Enable to form validation a IF sentence like

if($_SERVER['HTTP_REFERRER'] == "the value it showed on test") { check form } else { echo "Nice try malicious user"; }

spyder_tek

8:58 pm on Feb 4, 2006 (gmt 0)

10+ Year Member



simon2263...

Well, the textarea box isn't used by the script (there's no reference to the textarea within the script). It's only used to hold echoed data from the script.

Gero_Master...

That's a good idea...

Although, some browsers allow people to modify the HTTP referer info, right?

Thanks.

skinter

11:08 pm on Feb 5, 2006 (gmt 0)

10+ Year Member



Some browsers also don't send the referrer. So if your page uses that, those people won't be able to use it.

I have loads of people in my logs using IE but don't send a referrer, so lots of people might be unable to execute the script.

Like you were saying, though, some browsers allow you to edit the referrer. I have a few fx plugins that would let me spoof the referrer, so don't make the referrer the main point for your site's security.

JollyK

11:48 pm on Feb 5, 2006 (gmt 0)

10+ Year Member



The quick answer is, yes, check your input for every field always. Anyone can view the source of your page (no matter how you try to hide it) and then write a script to send whatever data they want. Any type of form field, whether text, textarea, checkbox, radio button, anything, can be faked.

Not only do some browsers not send the REFERER tag or let you edit it, but just in general, faking HTTP_REFERER is easy to do. (That's why so many people's FormMail scripts get hijacked to send spam -- because they depend on the REFERER field being honest.)

Really, sending any kind of fake data is easy to do, and you can almost depend on someone eventually trying to do so. I hate to say it, but honestly, I think it's better to just check the incoming data from the beginning and send an error if it's not an appropriate value.

JK

willybfriendly

11:55 pm on Feb 5, 2006 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



With checkboxes and radio buttons I always cover every possible valid submission in the script, either with a switch statement or an if statement.

ALL input should be validated before it is processed. A checkbox would be a great place to launch an injection attack.

WBF

spyder_tek

5:54 am on Feb 6, 2006 (gmt 0)

10+ Year Member



Ok, so definitely validate all input.

I've heard some people mention that you should also verify all output as well? Is this necessary if I've already validated all input?

I also take it that I shouldn't use HTTP_REFERRER, right?

In that case, how do I prevent people/bots from remotely executing/using my scripts?

Would using CAPTCHA image verification prevent this?

Is there another way to prevent this without using image verification?

Thank you for all of your help.

JollyK

3:45 pm on Feb 6, 2006 (gmt 0)

10+ Year Member



I also take it that I shouldn't use HTTP_REFERRER, right?

Right. HTTP_REFERER is useless, pretty much, and you might as well ignore it. At this point, it would probably hurt more ordinary non-malicious people than it would malicious hackers/crackers.

In that case, how do I prevent people/bots from remotely executing/using my scripts?

Answer 1: You don't.

Answer 2: I don't know as it's a good idea to worry about that, since it sort of takes you down a path of thinking that if you can prevent people from remotely using your scripts that you don't have to validate input. It just leads to complacency!

Would using CAPTCHA image verification prevent this?

~sigh~ You could do that, yes, and it probably would prevent it, BUT! Again, you cannot depend on people not being able to execute your script outside of your form. The CAPTCHA you use today may be cracked for happy bot use tomorrow. And honestly, if you validate all input, then who cares if people run your scripts outside your form? They still won't be able to do anything they couldn't do from your form, right?

Is there another way to prevent this without using image verification?

Don't put them online? :-)

Sorry, I couldn't resist. Maybe someone else has an idea: I just think that's an awful lot of work that would be better placed in battening down the hatches in the script ...

Just my opinion, though!

JK

spyder_tek

2:31 am on Feb 7, 2006 (gmt 0)

10+ Year Member



JollyK...

Thanks, I agree. I'm going to focus more on the internal integrity of my scripts, such as input validation/filtering.

So far I've created a simple function for "validating" input:

function clean($value1){
$value1 = strip_tags($value1);
$value1 = htmlentities($value1);
$value1 = escapeshellarg($value1);
$value1 = escapeshellcmd($value1);
return $value1;
}

Would the above be enough to guard against most attacks?

All feedback is appreciated!

Thanks.

JollyK

3:43 am on Feb 7, 2006 (gmt 0)

10+ Year Member



It sort of depends on what you're going to do with the values. Are you going to use them in an email header? Stick them into a Mysql database? Base authentication on them? Run system commands?

I try to do two things:

1. Based on what I'm going to do with a particular variable/value, I decide what characters/entities/etc are "ok" and which are not. I then either strip out all characters not on the "ok" list and use it, or present an error to the user like, "Sorry, email addresses may not contain spaces. Please try again."

2. I'll make a list of all possible name/value pairs that can come from my form. Then, go through the $_['POST'] data (I think that's how you call it in php -- might be $_SERVER['POST']) and if there is something in the POST (or GET) data that is not in my list, present an error, like "Sorry, Email_Address_2 is not valid data. Please use the form at [blahblah_whatever...]

I'm not sure how things like "escapeshellarg()" and "escapeshellcmd()" will stack with each other also: will you end up double-escaping things? I guess I would caution you to be very certain that you know exactly what value is going to be returned from each of those stripping functions, though. Try sending data such as newlines and backslashes and double backslashes and %00 and various other escaped entities in a GET url and see what happens and whether it's escaping things as you think it should.

Picking a set of characters that are safe, and only allowing them may be better. That's just my preference, though, and is certainly NOT the only way to do it. I'm just a random message board poster: what do I know? :-)

Oh ... did I mention that Javascript validation is not sufficient? It's client-side, so it's easily bypassed even if you make the page inaccessible to non-Javascript browsers. The thing to remember is that whatever your form posts to, I can post to with my own script and make it look like it came from your form, and I don't have to pay attention to Javascript. (I'm sure you already know that, but I do run into a LOT of people who feel that Javascript makes their form posts safe.)

JK

[Ack: edit to say, you don't want to strip TOO much either depending on what you're doing with the data. I have scripts where you can enter HTML. I wouldn't want to strip all HTML entities -- I just strip "<script>" tags. So, there are times when you may want to leave some things in there, but just be careful about how you use them, if that makes sense.]

willybfriendly

4:28 am on Feb 7, 2006 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



Would the above be enough to guard against most attacks?

Ideally you should have an idea what data will be in each field. Confirm that it is the type of data you expect.

Numeric fields should only contain numbers (like a US postal code, or credit card number). Radio buttons should only be one of a short list of possible values. States/Countries can be compared to an array of values, and they can be taken from a drop down list on your form.

Text fields can be checked for length and escaped with mysql_real_escape().

The idea is to confirm that the data is some semblance of what is expected before proceeding, and then escaping for an additional layer of protection.

$data = ""
$valid = array("a", "b", "c");
if(in_array($_POST[data], $valid))
$data=$_POST[data];
else $errmsg = "That is not a valid value for (field name)";

With the above, it the possible values are from a checkbox, radio button or drop down list, and the $_POST[data] doesn't match, well, that tells you something, doesn't it?

WBF

spyder_tek

6:57 am on Feb 7, 2006 (gmt 0)

10+ Year Member



Thank you for your help. So far I've learned a lot from this thread.

JollyK...

Well, the script that I have doesn't do too much.

Basically when a checkbox is selected it tells the script to echo back some text to a textrea box. So, if checkbox1 is selected it echoes back text1, if checkbox2 if selected it echoes back text2, etc.

So it's a fairly basic script. I'm just concerned that someone could save the form to their computer and change:

<input type="checkbox" name="checkbox1" value="checkbox1">

to maybe:

<input type="text" name="malicious_data" value="malicious_data">

It doesn't interact with Mysql, nor does it post anything publicly, so do I still have to worry about XSS, SQL injection, or any other system call attacks?

willybfriendly...

So, that would check to see if the values from my form fields match the values in the array?

So, it would stop someone from changing checkbox1 to something else?

Thanks.

willybfriendly

12:02 am on Feb 8, 2006 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



So, it would stop someone from changing checkbox1 to something else?

They could change it to whatever they wanted.

The change would not get by the error checking.

The idea is that where possible you have screened the submitted value against a list of valid values. Many, perhaps most, data fields can be compared against a known list of values.

State
Country
Gender
Age
Postal Code
Price
Marital Status
etc.

Others can be regex'd for validity, such as an email address's format

If we screen these through these filters, bad data will never make it to a sensitive part of the script.

$data will continue to equal ""

It is $data that is manipulated in the script. $_POST[data] never gets beyond the filters you build, until you assign its value to $data.

Clear as mud?

WBF

willybfriendly

10:04 pm on Feb 11, 2006 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



A couple of sticky exchanges suggest that what I had written about screening input against known good values was not particularly clear, so I offer this as an example.

Remember $_SERVER[PHP_SELF] is itself insecure, so this should only be used as an example.

WBF

<?
//initialize variable(s)
$state = "";
//initialize array(s)
$stabbrev = array("AL", "AK", "AZ", "AR" ,"CA", "CO", "CT", "DE", "FL"=>"Florida", "GA", "HI", "ID", "IL", "IN", "IA", "KS", "KY", "LA", "ME", "MD", "MA", "MI", "MN", "MS", "MO", "MT", "NE", "NV", "NH", "NJ", "NM", "NY", "NC", "ND", "OH"=>"Ohio", "OK", "OR", "PA", "RI", "SC", "SD", "TN", "TX", "UT", "VT", "VA", "WA", "WV", "WI", "WY");

//exact match on processing instruction
if($_POST[ds]==="process")
$ds = $_POST[ds];
else
$ds="";
//if it is good, proceed...
if($ds == "process")
{
if(in_array($_POST[state],$stabbrev))
{
$state=$_POST[state];
$msg = "The State Abreviation is $state";
}
else
$msg = "The State information is INVALID!";

die($msg);
}
?>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">

<html>
<head>
<title>Untitled</title>
</head>
<body>
<form action="<? $_SERVER[PHP_SELF]?>" method="post">
<input type="hidden" name="ds" value="process">
<select name="state" >
<OPTION VALUE="">--Select State--</OPTION>
<OPTION VALUE="AL">Alabama</OPTION>
<OPTION VALUE="AK">Alaska</OPTION>
<OPTION VALUE="AZ">Arizona</OPTION>
<OPTION VALUE="AR">Arkansas</OPTION>
<OPTION VALUE="CA">California</OPTION>
<OPTION VALUE="CO">Colorado</OPTION>
<OPTION VALUE="CT">Connecticut</OPTION>
<OPTION VALUE="DE">Delaware</OPTION>
<OPTION VALUE="FL">Florida</OPTION>
<OPTION VALUE="GA">Georgia</OPTION>
<OPTION VALUE="HI">Hawaii</OPTION>
<OPTION VALUE="ID">Idaho</OPTION>
<OPTION VALUE="IL">Illinois</OPTION>
<OPTION VALUE="IN">Indiana</OPTION>
<OPTION VALUE="IA">Iowa</OPTION>
<OPTION VALUE="KS">Kansas</OPTION>
<OPTION VALUE="KY">Kentucky</OPTION>
<OPTION VALUE="LA">Louisiana</OPTION>
<OPTION VALUE="ME">Maine</OPTION>
<OPTION VALUE="MD">Maryland</OPTION>
<OPTION VALUE="MA">Massachusetts</OPTION>
<OPTION VALUE="MI">Michigan</OPTION>
<OPTION VALUE="MN">Minnesota</OPTION>
<OPTION VALUE="MS">Mississippi</OPTION>
<OPTION VALUE="MO">Missouri</OPTION>
<OPTION VALUE="MT">Montana</OPTION>
<OPTION VALUE="NE">Nebraska</OPTION>
<OPTION VALUE="NV">Nevada</OPTION>
<OPTION VALUE="NH">New Hampshire</OPTION>
<OPTION VALUE="NJ">New Jersey</OPTION>
<OPTION VALUE="NM">New Mexico</OPTION>
<OPTION VALUE="NY">New York</OPTION>
<OPTION VALUE="NC">North Carolina</OPTION>
<OPTION VALUE="ND">North Dakota</OPTION>
<OPTION VALUE="OH">Ohio</OPTION>
<OPTION VALUE="OK">Oklahoma</OPTION>
<OPTION VALUE="OR">Oregon</OPTION>
<OPTION VALUE="PA">Pennsylvania</OPTION>
<OPTION VALUE="PR">Puerto Rico</OPTION>
<OPTION VALUE="RI">Rhode Island</OPTION>
<OPTION VALUE="SC">South Carolina</OPTION>
<OPTION VALUE="SD">South Dakota</OPTION>
<OPTION VALUE="TN">Tennessee</OPTION>
<OPTION VALUE="TX">Texas</OPTION>
<OPTION VALUE="UT">Utah</OPTION>
<OPTION VALUE="VT">Vermont</OPTION>
<OPTION VALUE="VA">Virginia</OPTION>
<OPTION VALUE="WA">Washington</OPTION>
<OPTION VALUE="WV">West Virginia</OPTION>
<OPTION VALUE="WI">Wisconsin</OPTION>
<OPTION VALUE="WY">Wyoming</OPTION>
</select>
<button type="submit">Submit</button>
</form></body>
</html>

spyder_tek

2:43 am on Feb 12, 2006 (gmt 0)

10+ Year Member



Thanks, willybfriendly. :)