views:

355

answers:

6

I am trying to read get parameters in such a way that will not open up potential security issues.

What I was thinking was matching the request parameter explicitly to what I expect and then setting a default for anything that doesn't match.

For example:

if ($_REQUEST['media'] == "video")
    $sort = "video";
elseif ($_REQUEST['media'] == "audio")
    $sort = "audio";
else
    $sort = "both";

Is this enough or are further steps necessary?

+1  A: 

I would add one more condition:

 $sort = "both";
 if (array_key_exists('media', $_REQUEST))
 {
  if ($_REQUEST['media'] == "video")
   $sort = "video";
  elseif ($_REQUEST['media'] == "audio")
   $sort = "audio";
 }

And yes, the $_REQUEST superglobal is the recommended way to read the request.

Byron Whitlock
or `isset($_REQUEST['media'])` instead of `array_key_exists` Also - why not just default $sort to "both" to start with?
gnarf
Good idea, changed!
Byron Whitlock
This is the most readable way, so it is probably the method I will use.
Jeff Davis
(But using $_GET instead of $_REQUEST)
Jeff Davis
+4  A: 

What you mention is safe, but is overly verbose. Using an PHP's array operations would let PHP handle the dirty work for you:

$sort_valid = array('video', 'audio', 'both');
$sort = 'both'
if (isset($_REQUEST['media']) && in_array($_REQUEST['media'], $sort_valid)) {
    $sort = $_REQUEST['media'];
}

If this sort of superglobal parsing is common throughout your code, you could abstract this into a function that handles it for you (as many large PHP projects do).


As Gavin noted, it's also a good idea to use the specific superglobal that you're interested in (i.e. $_GET, $_POST, or $_COOKIE) if at all possible. It might not seem important now, but some ugly bugs can manefest from naming conflicts will occur between the three superglobals (e.g. sort in $_COOKIE may refer to the default sorting of search results, but sort in $_GET refers to ascending or descending order).

Mike Koval
Throws a E_NOTICE if there wasn't a $_REQUEST['media'] set. Should still test isset($_REQUEST['media']).
gnarf
OK. Thanks for answering the question, as well as the explanation about why one should use $_GET instead of request.
Jeff Davis
Very good point Gnarf - I hadn't considered that. Edited the original post to be correct.
Mike Koval
+4  A: 

It's probably also worth noting (if you're that concerned about security) that it is fairly bad practice to not know where your data is coming from. You should probably either use $_GET, $_POST or $_SESSION depending on the method of delivery.

Gavin Gilmour
Good catch. I figured somebody would notice that, but I wasn't sure if it mattered.
Jeff Davis
+1  A: 

Simplest way would be:

$sort='both';
$sort_valid = array('video', 'audio');
if(isset($_REQUEST['media']) && in_array($_REQUEST['media'], $sort_valid)) $sort=$_REQUEST['media'];
Thinker
A: 
$valid = array("media" => array("both", "media", "video"), ... );
$default = array("media" => "both", ...);

...

// 1. drop invalid keys
$filtered_on_keys = array_key_intersect($_REQUEST, $valid);

// 2. drop invalid values
$filtered_on_values = array();

foreach($filtered_on_keys as $key => $value) {
  if (array_search($value, $_REQUEST($key) !== FALSE) {
    $filtered_on_values[$key] = $value;
  }
}

// 3. add missing defaults
$result = array_merge($defaults, $filtered_on_values);
Zed
+1  A: 
OctaneFX