Is it secure to use "require" with GET/POST data? - php

Is it secure to use the following code:
require($_SERVER['DOCUMENT_ROOT'] . "/pages/" . $_GET['page'] . ".php")

No, it is not secure. Why?
Because sequence of two dots /../ means one directory back and the attacker could potentially include anything on your system, even above $_SERVER['DOCUMENT_ROOT']. (In an unfortunate configuration that means secret/sensitive OS config files.)
You have to IF or SWITCH for the allowed values to prevent malicious input. Example:
switch($_GET['page']) {
case 'welcome': $page='welcome';
case 'shop': $page='shop';
default: $page='index';
}
require($_SERVER['DOCUMENT_ROOT'] . "/pages/" . $page . ".php")
Also check out in_array() for a little easier filtration.

StackOverflow has a useful Q&A for how to sanitize user input with PHP. It's a few years old, but the principles haven't changed at all.
The quick answer is: if you can avoid the problem in the first place, you're better off.
Show us how you're trying to use this, and we may be able to offer suggestions for improvement.

It's not secure. You can use array with allowed values.
For example
$allowed_pages = array('index', 'test', 'my_page')
if (!in_array($_GET['page'], $allowed_pages)){
echo 'good bye';
die();
} else {
//
}

If you trust all the files in the pages dir try:
if (in_array($_GET['page'],glob("/pages/*.php"))) {
require($_SERVER['DOCUMENT_ROOT'] . "/pages/" . $_GET['page'] . ".php");
} else echo "Nice try hacker!";
Here's another solution using parts of a function I use to clean uploaded filenames:
OPTION #2 thanks Daniel, Rok!
$page = preg_replace('/[^a-zA-Z0-9_ %\[\]\.\(\)%&-]/s', '', $_GET['page']);
$filename = $_SERVER['DOCUMENT_ROOT'] . "/pages/" . str_replace("/",'',$page) . ".php";
if (file_exists($filename)) {
require($filename);
} else echo "Nice try hacker!";
Note that this will only work if there are no special characters in your file names

use regExp to check your $_GET['page']!

Related

PHP include dynamically generated filename?

while($x<=$num_of_cpkgs){
$cpkg_navtray = '\'' . $cpkg_array[$x] . '.html\'';
include $cpkg_navtray;
$x++;
}
I'm getting an error when I try this ... it works when I manually include the same value however ... for example, if $cpkg_navtray = 'test.html', I'm getting an error; however, when I directly include 'test.html' like include 'test.html';, it works. Why?
You dont need quotes in filename variable -
$cpkg_navtray = $cpkg_array[$x] . '.html';
Looking same Question but tag and desire different: Jut do these, just a simple concatenate.
while($x<=$num_of_cpkgs){
$cpkg_navtray = $cpkg_array[$x].'.html';
include $cpkg_navtray;
$x++;
}

PHP add query string if it does not exist

Before I start, I am completely new to PHP. This is probably a stupid error and I am probably doing this in the worst way possible.
I have this code:
<?php
if (!isset($_GET['p'])) {
$url .= '?p=home';
header('Location:' . $url);
exit;
}
elseif (!isset($_GET['sp'])) {
header("Location: ".$_SERVER['REQUEST_URI'].'&sp=index.php';);
die();
}
include('/Page/' . htmlspecialchars($_GET["p"]) . '/' . htmlspecialchars($_GET["sp"]));
?>
Basically the url format is www.example.com/?p=PAGE&sp=SUBPAGE.php
The internal format from this will be /Page/PAGE/SUBPAGE.php
Reasons:
Each 'Post' will have it's own folder for it's resources. (?p=) Then they can put anything within their folder and link to it with the SUBPAGE (&sp=).
This keeps everything organised and stops any internal linking to anywhere but the /page/ area.
What's wrong:
If there is no Page (p) set I need to add ?p=home as the default and if their is no SubPage (sp) set I need to add &sp=index.php by default.
If there is no Page then the SubPage will be reset to default.
If you are on a page www.example.com/?p=blog then it will add the subpage without removing the page (?p=blog to ?p=blog&sp=index.php)
However if there is no page then the subpage will be reset to default.
The question:
How can I come about this?
Thank you, in advance.
I would approach the situation differently.
Set up some variables, for page and inner page with the default values and only re-assign them if the $_GET params are set
$page = 'home';
$inner_page = 'index.php';
if( isset( $_GET['p'] ) )
{
$page = htmlspecialchars( $_GET['p'] );
}
if( isset( $_GET['sp'] ) )
{
$inner_page = htmlspecialchars( $_GET['sp'] );
}
include $_SERVER['DOCUMENT_ROOT'] . '/Page/' . $page . '/' . $inner_page;
I've added $_SERVER['DOCUMENT_ROOT'] in too because if you use /Page then it is an absolute path, probably not what you were expecting, so prepending $_SERVER['DOCUMENT_ROOT'] ensures you're looking at the path inside your web directory.
Something else worth noting; Don't assume the data is good, people could try manipulate the files that are included.
http://your.domain/index.php?p=../../../../../&sp=passwd
So it would be worth trying to sanitize the data first.
Your current code has a big security flaw.
One of the most important rule when you write an app, never trust data coming from client. Always assume, they will send you wrong or bogus data.
I would recommend you to create a configuration file defining what are the allowed routes.
By executing the following line, you just allowed anyone to access any file that would be readable by your webserver.
include('/Page/' . htmlspecialchars($_GET["p"]) . '/' . htmlspecialchars($_GET["sp"]));
What happens If you sent a valid value for $_GET['p'] and this for $_GET['sp'] :
"/../../../../../../../../../../../etc/apache2/httpd.conf"
In this example, it will output your apache configuration file (assuming that this is the right path, if not an hacker can just keep trying path until he finds it).
To avoid this, you have two solutions.
1# Quick fix - You can sanitize & filter $_GET['p'] and $_GET['sp'] to ensure that you are not getting something '/../'. Make sure to add at least a file_exists before to avoid getting unwanted warning messages.
2# More elegant fix - You can create a configuration file that would contain the routes that you are accepting. If you are using a framework, there is a very high chance that you have a routing class or a routing module that you can just use. Otherwise, if you feel like implementing your own basic routing mechanism, you could do something as simple as in your case :
<?php
/**
* Defines the different routes for the web app
* #file : config.routes.php
*/
return array(
'page1' => array(
'index.php',
'subpage2.php',
'subpage3.php',
),
);
Then, your code you would check if the $_GET['p'] and $_GET['sp'] are allowed values or not.
<?php
// Load config file containing allowed routes
$allowedRoutes = require(__DIR__ . '/config.routes.php');
$defaultPage = 'home';
$defaultSubPage = 'index.php';
$page = isset($_GET['p']) ? $_GET['p'] : defaultPage;
$subPage = isset($_GET['sp']) ? $_GET['sp'] : $defaultSubPage;
// If it is an invalid route, then reset values to default
if (!isset($allowedRoutes[$page][$subPage]))
{
$page = $defaultPage;
$subPage = $defaultSubPage;
}
include $_SERVER['DOCUMENT_ROOT'] . '/Page/' . $page . '/' . $subPage;

Wrong "if" logic PHP

I think I didn't understand the PHP logic yet. My "if's" in javascript works fine, but in PHP it's always ignored. I have this form (party of it) in insert_car.php:
<input type="file" name="imagem01" id="imagem01" title="Imagem 01" onchange="readURL01(this);" class="button" />
... (and 5 more inputs for images and others for texts)
this is the correspondent party in insert_db.php:
$gravar_imagem01 = $_FILES['imagem01'];
preg_match("/\.(gif|bmp|png|jpg|jpeg){1}$/i", $gravar_imagem01["name"], $ext);
$nome_imagem01 = md5(uniqid(time())) . "." . $ext[1];
$caminho_imagem01 = "../../images/" . $nome_imagem01;
move_uploaded_file($gravar_imagem01["tmp_name"], $caminho_imagem01);
$sqlinsert = "INSERT INTO tb_carros (... imagem01,...) value (... '$nome_imagem01',...)";
It works fine, but know I want to put an default image if one of the inputs file is empty. So I did this in insert_db.php:
if (empty($imagem01))
{
$gravar_imagem01 = "sem_imagem.jpg";
$nome_imagem01 = $gravar_imagem01;
}
else
{
$gravar_imagem01 = $_FILES['imagem01'];
preg_match("/\.(gif|bmp|png|jpg|jpeg){1}$/i", $gravar_imagem01["name"], $ext);
$nome_imagem01 = md5(uniqid(time())) . "." . $ext[1];
$caminho_imagem01 = "../../images/" . $nome_imagem01;
move_uploaded_file($gravar_imagem01["tmp_name"], $caminho_imagem01);
}
The default image (sem_imagem.jpg) is been placed, but even if the input "imagem01" is not empty the default image appears. So, what is wrong in my code?
Ps.: If I switch the "if" and "else" condition the result is the reverse (the default image don't appears even with the input imagem01 empty). That's why I said that my "if" is been ignored.
Try this with isset
change this
if (empty($imagem01))
to
$gravar_imagem01 = $_FILES['imagem01'];
if (isset($gravar_imagem01))
The if isn't being "ignored"; you likely misunderstood the meaning of the function empty. Look it up in the documentation, and check that it does what you think it does.
In particular, it doesn't magically understand the concept of "files" — empty looks at variables. It is quite conceivable that $_FILES['imagem01'] still exists in some form even in the case in which you're perceiving the image file to be "empty". I suggest examining it in this case to find out which conditional to use.
Edit: It also helps if you use the correct variable name:
if (empty($imagem01))
becomes:
if (empty($_FILES['imagem01']))
try this i think always $imagem01 is empty you must get imagem01 data from form like $imagem01= $_FILES['imagem01']; then check for empty you can't use JavaScript variable directly it better in this case use var_dump($var); for see variable value
$imagem01= $_FILES['imagem01'];
if (empty($imagem01))
{
$gravar_imagem01 = "sem_imagem.jpg";
$nome_imagem01 = $gravar_imagem01;
}
else
{
$gravar_imagem01 = $_FILES['imagem01'];
preg_match("/\.(gif|bmp|png|jpg|jpeg){1}$/i", $gravar_imagem01["name"], $ext);
$nome_imagem01 = md5(uniqid(time())) . "." . $ext[1];
$caminho_imagem01 = "../../images/" . $nome_imagem01;
move_uploaded_file($gravar_imagem01["tmp_name"], $caminho_imagem01);
}
There is no variable named $imagem01 anywhere else in your code so it is always going to be undefined and empty($imagem01) will always return true. You may need to check for a different condition in your if statement.

Cannot call PHP function even though it is "included"

I've started using PHP lately... all is good except one thing.
I am trying to call a function from another php file... but it's not working.
It's probably really simple, but I haven't found anything useful to solve it.
I've used "required_once " but it still does not work.
Does anyone know where I'm going wrong?
<?php
require_once "/Applications/MAMP/htdocs/me/database_functions.php";
require_once "/Applications/MAMP/htdocs/me/encode_decode.php";
if (isset($_POST['url']) && $_POST['url'] != "http://")
{
//Get the url posted
$long_url = $_POST['url'];
//Create record in long_url table and return it's id
$long_id = create_long_url($long_url);
Everything works so far.. But
the problem is this next function call.. it doesn't even go into the function.
$short_url = $encode($long_id);
}...............etc...
encode_decode.php looks a bit like this...
<?php //encode_decode.php
function encode($number)
{
echo "<br />in encode";
//Encode numer to 6 char
$s = strtr(rtrim(base64_encode(pack('i', $number)), '='), '+/', '-_');
echo $s;
return $s;
}
Any help is greatly appreciated...
You don't need the $ before your function call
$short_url = $encode($long_id);
should be
$short_url = encode($long_id);
The dollar sign would only be needed if the function is stored in a variable (which it isn't).
$short_url = encode($long_id);
remove the dollar sign from in front of the function. a dollar sign in PHP indicates a variable
As all others have said:
$short_url = encode($long_id);
But also you could clean up your require_once statements:
define('DS', DIRECTORY_SEPARATOR);
require_once(dirname(__FILE__) . DS . 'database_functions.php');
require_once(dirname(__FILE__) . DS . 'encode_decode.php');
Instead of the define() and reference to DS you could of course just prefix your file names with '/'. This also assumes your files are relative (but if not just prefix the folder to the filename) - this would make sure you don't get any problems if you move your site from different servers (i.e., testing, production).

define a variable in a query (?)

I have to define two variables:
<?php
$path = 'http://' . $_SERVER['SERVER_NAME'] . '/root/images/folderX/';
$files = scandir('images/folderX/');
?>
In the place of 'folderX' I should use a dynamic value, which comes from a query, like
<?php echo $row_rsQuery["item_name"];?>
How can it be done?
I'm not too familiar with php, and I will perhaps never learn it (..too old..), but I solve most of my problems with Dreamweaver, however the above problem is beyond its (and my) capabilities...
String concatenation (appending one string to another) is done via the . operator:
$files = scandir('images/'.$row_rsQuery["item_name"]);
$path = 'http://' . $_SERVER['SERVER_NAME'] . '/root/images/'.$row_rsQuery["item_name"].'/';
$files = scandir('images/'.$row_rsQuery["item_name"].'/');

Categories