What would be the safest way to include pages with $_GET without puttingt allowed pages in an array/use switch etc. I have many pages so no thank you.
$content = addslashes($_GET['content']);
if (file_exists(PAGE_PATH."$content.html")) {
include(PAGE_PATH."$content.html");
}
How safe is that?
Thanks.
This is very bad practice. You should setup a controller to handle dispatching to the code that needs to be executed or retrieved rather than trying to directly include it from a variable supplied by a user. You shouldn't trust user input when including files, ever. You have nothing to prevent them from including things you do not want included.
You'll sleep safer if you check the input for a valid pattern. e.g. suppose you know the included files never have a subdirectory and are always alphanumeric
if (preg_match('/^[a-z0-9]+$/', $_GET['page']))
{
$file=PAGE_PATH.$_GET['page'].".html";
if (file_exists($file))
{
readfile($file);
}
}
I've used readfile, as if the .html files are just static, there's no need to use include.
The possible flaw with your approach is that you can engineer a path to any HTML file in the system, and have it executed as PHP. If you could find some way to get an HTML file of your own devising on the filesystem, you can execute it through your script.
Match it against a regex that only accepts "a-zA-Z-".
edit: I don't think that blocking specific patterns is a good idea. I'd rather do, like I said, a regex that only accepts chars that we know that won't cause exploits.
Assuming the "allowed" set of pages all exist under PAGE_PATH, then I might suggest something like the following:
Trim page name
Reject page names which start with a slash (could be an attempt at an absolute path)
Reject page names which contain .. (could be an attempt at path traversal)
Explicitly prefix PAGE_PATH and include the (hopefully) safe path
If your page names all follow some consistent rules, e.g. alphanumeric characters, then you could in theory use a regular expression to validate, rejecting "bad" page names.
There's some more discussion of these issues on the PHP web site.
It looks generally safe as in you are checking that the page actually exists before displaying it. However, you may wish to create a blacklist of pages that people should not be able to view with the valid $_SESSION credentials. This can be done either with an array/switch or you can simply have all special pages in a certain directory, and check for that.
You could scan the directory containing all HTML templates first and cache all template names in an array, that you can validate the GET parameter against.
But even if you cache this array it still creates some kind of overhead.
Don't. You'll never anticipate all possible attacks and you'll get hacked.
If you want to keep your code free of arrays and such, use a database with two columns, ID and path. Request the page by numeric ID. Ignore all requests for ids that are not purely numeric and not in your range of valid IDs. If you're concerned about SEO you can add arbitrary page names after the numeric id in your links, just like Stack Overflow does.
The database need not be heavy-duty. You can use SQLite, for example.
The safest method involves cleaning up the request a bit.
Strip out any ../
Strip out ^\/
From there, make sure that you check to see if the file they're requesting exists, and can be read. Then, just include it.
You should use at least something like that to prevent XSS attacks.
$content = htmlentities($_GET['page'], ENT_QUOTES, 'UTF-8');
And addslashes won't protect you from SQL Injections.
Related
I learned a lot at Stackoverflow, it's my favorite programming website, and researching here I found the answers for many of my questions.
Now that I've finished the code I need to know: does it have any security flaw?
It needs to get the domain name from the url in order to see if a var file containing that expression exists on the directory and output it's content.
Your help is really appreciated!
Would be enough if I sanitize HTTP_HOST using htmlspecialchars and preg_replace? Using strip_tags would be overkill, no? Removing those special characters from the array is also redundant, don't you think?
Edit:
I'll alter the code and also add protection to the include files themselves. Many thanks!
No. You should be using a white-list of allowed expressions. For something as dangerous as include you definitely don't want to rely on black-list and simple sanitization.
You would also hardcode which directory contains your PHP files.
Supposing you keep all the *var.php files in a special directory (let's say /var/www/include/vars/) you could read them into an array, and confine the selection within the boundaries of that array, instead of just is_file()ing:
$vardir='/var/www/include/vars/';
$varfiles=array();
foreach(scandir($vardir) as $fn)
if(($fn!='.')&&($fn!='..'))
$varfiles[]="$vardir$fn";
/* Next, do whatever sanitizing you see fit */
if(array_find($fnvar)) include_once $fnvar;
Note that this, essentially, is a whitelist, mentioned in the comments: If you create a new {xyz}var.php in the $vardir directory, you are actually inserting a new entry in the whitelist.
So as #ack__ points out too, you can't avoid a whitelist one way or another...
I'm thinking of including files into a script, that have names based on a cookie
Something like this:
include("sometext".$mycoockie_here."some_text.php");
Is the code above vulnerable to such attacks? - even with the "sometext" and "sometex.php" hard coded?
Of course it is. Everyone can tweak the values of cookies send to your web application. Imagine someone sending you a cookie with the content
/../../../../etc/passwd[null-byte]
So you will end up with the path
sometext/../../../../etc/passwd[null-byte]some_test.php
The PHP file handling functions pass the path on to the OS, which uses null-terminated strings, so you will end up including the contents of
sometext/../../../../etc/passwd
Which you probably don't want.
I have been searching everywhere to try and find a solution to this. I have recently been running scans on our websites to find any vulnerabilities to XSS and SQL Injection. Some items have been brought to my attention.
Any data which is user inputted is now validated and sanitized using filter_var().
My issue now is with XSS and persons manipulating the URL. The simple one which seems to be everywhere is:
http://www.domainname.com/script.php/">< script>alert('xss');< /script >
This then changes some of the $_SERVER variables and causes all of my relative paths to CSS, links, images, etc.. to be invalid and the page doesn't load correctly.
I clean any variables that are used within the script, but I am not sure how I get around removing this unwanted data in the URL.
Thanks in advance.
Addition:
This then causes a simple link in a template file:
Link
to actually link to:
"http://www.domainname.com/script.php/">< script>alert('xss');< /script >/anotherpage.php
This then changes some of the $_SERVER variables and causes all of my relative paths to CSS, links, images, etc.. to be invalid and the page doesn't load correctly.
This sounds you made a big mistake with your website and should re-think how you inject link-information from the input into your output.
Filtering input alone does not help here, you need to filter the output as well.
Often it's more easy if your application recieves a request that does not match the superset of allowed requests to return a 404 error.
I am not sure how I get around removing this unwanted data in the URL.
Actually, the request has been already send, so the URL is set. You can't "change" it. It's just the information what was requested.
It's now your part to deal upon it, not to blindly pass it around any longer, e.g. into your output (and then your links are broken).
Edit: You now wrote more specifically what you're concerned about. I would go in one with dqhendricks here: Who cares?
If you really feel uncomfortable with the fact that a user is just using her browser and enters any URL she feels free to do so, well, the technically correct response is:
400 Bad Request (ref)
And return a page with no or only fully-qualified URIs (absolute URIs) or a redefinition of the Base-URI, otherwise the browser will take the URI entered into it's address bar as the Base-URI. See Uniform Resource Identifier (URI): Generic Syntax RFC 3986; Section 5. Reference ResolutionSpecs.
first, if someone adds that crap to their url, who cares if the page doesn't load images correctly? also if the request isn't valid, why would it load any page? why are you using SERVER vars to get paths anyways?
second, you should also be escaping any user submitted database input with the appropriate method for your particular database to avoid sql injection. filter_var generally will not help.
third, xss is simple to protect from. Any user submitted data that is to be displayed on any page needs to be escaped with htmlspecialchars(). this is easier to ensure if you use a view class that you can build this escaping in to.
To your concern about XSS: The altered URL won't get into your page unless you blindly use the related $_SERVER variables. The fact that the relative links seem to include the URL injected script is a browser behavior that risks only breaking your relative links. Since you are not blinding using the $_SERVER variables, you don't have to worry.
To your concern about your relative paths breaking: Don't use relative paths. Reference all your resources with at least a root-of-domain path (starting with a slash) and this sort of URL corruption will not break your site in the way you described.
I'm developing a PHP-based web-application in which you have a form with textarea inputs that can accept links via anchor tags. But when I tested it after adding a hyperlink as follows, it pointed to a non-existent local subdirectory:
link
I realized that this was because I had not appended http:// before the link.
there might be cases where a user might input the link just as I did above. In such cases I don't want the link to be pointing as it did above. is there any possible solution, such as automatically appending http:// before the link in case that it doesn't exist? How do I do that?
----------------------------------------Edit---------------------------------------------
Please consider that the anchor tags are amidst other plaintext and this is making things harder to work with.
I'd go for something like this:
if (!parse_url($url, PHP_URL_SCHEME)) {
$url = 'http://' . $url;
}
This is an easy and stable way to check for the presence of a protocol in a URL, and allows others (e.g. ftp, https) that may be entered.
What you're talking about involves two steps, URL detection and URL normalization. First you'll have to detect all the URLs in the string being parsed and store them in a data structure for further processing, such as an array. Then you need to iterate over the array and normalize each URL in turn, before attempting to store them.
Unfortunately, both detection and normalization can be problematic, as a URL has a quite complicated structure. http://www.regexguru.com/2008/11/detecting-urls-in-a-block-of-text/ makes some suggestions, but as the page itself says, no regex URL detection is ever perfect.
There are examples of regular expressions that can detect URLs available from various sites, but in my experience none of them are completely reliable.
As for normalization, Wikipedia has an article on the subject which may be a good starting point. http://en.wikipedia.org/wiki/URL_normalization
Hello everyone, I'm developing a photo sharing web site using the CodeIgniter PHP framework. The idea is that people could upload their photos, manage them (through some sort of file browser which allows them to create subfolders, drag files around, etc) and edit them (some basic things like resizing, rotating and cropping to start with, and later on, I'll add some advanced features).
I've already implemented a third party authentication solution for CI (Redux Authentication 2 Beta) and I'm now integrating a JS/PHP file manager (AjaxExplorer), but the problem is that the PHP backend for managing files (moving, copying, etc) is trusting too much on the user input from the ajax calls. For instance, it's doing things like this (simplified for the sake of clarity):
move_uploaded_file($_FILES['upload']['tmp_name'], $root.$username.$_POST['destination_dir']);
As you can see, there are obvious security concerns as it blindly accepts whatever path the user throws in! I can already see someone sending something like "../AnotherUser/" as the $_POST['destination_dir'] value.
My question is: What's the best way to "sandbox" a user, in order to only allow him to manage his own data? Do I just validate+filter the inputs, hoping to catch every attempt of intrusion? Are there any libraries/packages dedicated to address this specific issue?
I think this problem must be somehow solved in any (mature enough) project, which gives its users the power of managing their files through a web browser, so I expected to find some clear guidelines around this (as there are a lot about SQL Injection, XSS, CSRF, etc) but I guess I'm not using the right keywords.
What's the best way to "sandbox" a user, in order to only allow him to manage his own data?
Allow any filenames/directory names the user wants, but simply don't use them on the server side filesystem. Instead, write the path names into a database with a primary key, and use the primary key as a filename like ‘34256.dat’ in a flat storage directory (or even as a BLOB in the database if you prefer). Then serve up via a download script or URL rewrite to make the desired filename appear in the URL.
Sanitising incoming filenames is hard. Detecting ‘..’ is only the beginning. Too-long filenames; too-short filenames; combinations of leading and trailing dots; combinations of leading and trailing whitespace; the different directory separators of different platforms; characters that are invalid on some platforms; control characters; Unicode characters and the environment-specific ways of addressing them; ADSs; filenames (‘.htaccess’) or extensions (‘.php’, ‘.cgi’) that might be ‘special’ to your web server; Windows's reserved filenames...
You can spend a lifetime tracking down funny little quirks of filepath rules on various platforms, or you can just forget it and use the database.
I'm not sure what your destination_dir looks like, but what I thought of was assigning directories keys, and then getting the directory based on that key. For example:
//$_POST['destination_dir'] = '4hg43h5g453j45b3';
*_query('SELECT dir FROM destinations WHERE key = ? LIMIT 1'); //etc.
However you have to predefine keys before hand. Another alternative could be the opposite: md5/sha1 the input and use that as the destination_dir, then store that key in the database with the associated label.
There are no library's that I know of.
However in your particular example, strip all (back)slashes and dots from the string and then append a slash to the end of it, that way the user can't change folders.
$destdir = str_replace(array('.', '/', '\\'), '', $_POST['destination_dir']);
$destdir .= "/";