PDA

View Full Version : CSS Dangit (PHP also now)



rubah
12-20-2006, 01:07 AM
Alright. I give.

Why does


#edges {
:bou::bou::bou::bou::bou::bou::bou::bou::bou::bou: absolute;
left: 204px;
top: 53px;
background: url("http://www.snowy-day.net/images/roundedcorners.png");
background-repeat: no-repeat;
overflow: visible;
}
not display the background image when called up in a div but



#topnav {
width: 99%;
height: 33px;
background: #1B205D;
background-image: url("http://www.snowy-day.net/images/roundedbground.png");
background-:bou::bou::bou::bou::bou::bou::bou::bou::bou::bou: 100% 0%;
background-repeat: no-repeat;
}
does?

I also have a background set for the whole body.

I was using the individual background thing at first, and it didn't work either. I added the overflow thinking maybe it wouldn't display it in an empty div.

I had it all working perfectly fine in a very nonCSS way by just using the edges div to display an image, but what's impressive is that before I reuploaded the page without that image removed, but after I uploaded the stylesheet (and moved the image) the page actually displayed it right, and the alt text was there. And now I can't recreate that for some reason and it makes me go GNAAH PHNAAH

the page I'm using to try this with is http://www.snowy-day.net/index.php?page=clique and there should be a cute little rounded edge under the () next to zeit. BUT IT IS NOT THERE. I swear the image is uploaded, unless it isn't.

Dr Unne
12-20-2006, 01:37 AM
Add a height and width to the #edges css. :)

EDIT: To explain, absolutely positioned divs end up being 0px in size unless they contain text or you specify an explicit hight and width.

rubah
12-20-2006, 02:05 AM
I was hoping the overflow would fix that :|

I thank you, good doctor. I was about to not thank you, but I think that might have been because sometimes pages refuse to reload, even after ctrl+f5, but it seems to work now? I really don't know.

Dr Unne
12-20-2006, 02:21 AM
Reloading pages (probably depending on the browser) seems to reload the page itself but sometimes not necessarily reload all of its dependencies like CSS stylesheets or external Javascript files or images. I don't know why either.

Our avatars are spinning in near-unison at different speeds and it's making me sick to my stomach.

rubah
12-20-2006, 03:09 AM
haha xD

I've noticed the not wanting to load anything when I started making snowy-day work with php, but I think that's more I am terrible at using php and have to reload several times to get anything right.

If you want I can adjust the animation in either one of our avs so they spin precisely together(so long as they're in cache anyways)

Speaking of php, you wouldn't happen to know how one could set the filename of a page as a variable, then have an include check that against the urls in links in the included page and then make it so that hwen it matched it would not be linked?

I mean I could just make a bunch of different includes for each page, but that is inefficient, and if I'm going to do this php stuff, I don't want to do it halfarsed.

Example so you know what I'm talking about.

You have pages 1, 2, and 3 that interlink to each other. I want there to be a placeholder for page 1 on page one, for page2 on page 2, etc I just don't know HOW to do it easily where I don't have to reupload a million files if i add a page.

Dr Unne
12-20-2006, 03:37 AM
Not sure I understand. Like this? (Untested code)


function make_link($this_page='') {
foreach(array('test', 'something', 'otherpage', 'whatever') as $page) {
if($this_page == $page) {
print '<div>' . $page . '</div>';
} else {
print '<div><a href="' . $page . '.php">' . $page . '</a></div>';
}
}
}

$this_page = 'something';

make_link($this_page);

Define $this_page in all your separate files, and put the function in a single file which is included into every separate file. Then you have to pass it the value of $this_page in some way. Here I'm sending it as a parameter to the function. You could also make it a global variable, or make a class to encapsulate it. There are different ways.

If you wanted to get tricky, you can fetch a script's own filename and do things with it. It's stored in the built-in variable $_SERVER['PHP_SELF'].

But you should be careful you're not doing something where you use the text in a link to dynamically access a bunch of files, or something like that. You should never use user input to do anything that might affect or access anything on your computer. Otherwise people will pass your script a link like "http://...../?page=../../../etc/passwd" and then you're in trouble.

I'm no PHP expert, there may be better ways of doing this.

rubah
12-20-2006, 04:41 AM
luckily this isn't my server, so~

actually, now that I think about it, a gallery type script that would output so many images per page would probably be just as well.

I need to find a better way to learn php. Reading the manual just doesn't do much for me.

Dr Unne
12-20-2006, 04:55 AM
There comes a point where you have to start learning the principles of programming in general. And then you would be a programmer.

Samuraid
12-20-2006, 10:05 PM
You should never use user input to do anything that might affect or access anything on your computer. Otherwise people will pass your script a link like "http://...../?page=../../../etc/passwd" and then you're in trouble.

I'm no PHP expert, there may be better ways of doing this.


&lt;?php

// By Samuraid
// Make a path safe(r) for inclusion

// Default page to load if no others are found
$default = 'defaultpage.php';

// Read the page path we need to include (don't rely on register_globals)
$in_path = (isset($_REQUEST['path'])) ? trim($_REQUEST['path']) : $default;

// Break the path at the slashes, and clean any invalid files that
// start with "." (so no one can hack paths or include hidden files)
$in_path = preg_split('#/#', str_replace('\\', '/', $in_path), -1, PREG_SPLIT_NO_EMPTY);
for ($i = 0, $ic = count($in_path); $i < $ic; $i++)
{
if ($in_path[$i][0] == '.')
{
unset($in_path[$i]);
}
}

// Recombine the cleaned path
$in_path = implode('/', $in_path);

// Build the full include path
$path_base = dirname(__FILE__) . '/';

// Check for recursive inclusion
if ($in_path == basename(__FILE__))
{
$in_path = $default;
}

// Read and output the file contents.
if (is_file($path_base . $in_path))
{
// Include the file
include $path_base . $in_path;
}
else
{
// File does not exist
print '&lt;span style="color: red; font-weight: bold;"&gt;The file ' .
htmlspecialchars($in_path) . ' does not exist.&lt;/span&gt;';
}

?&gt;

P.S. Please report bugs. :)

Dr Unne
12-21-2006, 12:29 AM
I'm probably not smart enough to find bugs or break your script, but I can see things that make me nervous.

I've heard (and I usually agree) that it's always better to define what you want to allow, rather than define what you want to disallow. You're disallowing periods and to some extent slashes, but you're allowing nearly anything else.

In reality you'd want a filename to match a pattern like /^[A-Za-z0-9][A-Za-z0-9.]*$/. (Or modify it to allow slashes, but I wouldn't even allow them at all, personally.) Anything that doesn't match your regex should be rejected immediately. I passed your script a filename like #$%%*#!!%#^ and nothing bad happened, but still it accepted it as a valid filename all the way to the point where it was testing the filesystem for its existence. That's probably not good. I was looking for ways to URL-escape a "." character, and couldn't find any that survived your script, but if there are some, it would defeat your script also.

People can also start passing arbitrary binary data in via POST. I'm always scared someone's going to send me a 50MB URL and it's going to overflow and start doing horrible things.

You're also disclosing to the user the names of all your files. There's no reason the user needs to know this. If your files are in some path not in DOCUMENT_ROOT, you're exposing what your server's file structure looks like.

One extremely simple way I know of to define what you want to allow is to make a lookup table. The user specifies a key into your lookup table. You just have to reject invalid keys.


<?php

$allowed_includes = array(
'file1' => 'some_file.php',
'file2' => 'some_other_file.php',
'file3' => '../../this/is/still/safe',
'file3' => '/home/user/.secret/.....as/is/this/if/you/really/want/to',
'file4' => 'and/you/can/hide/the/real/filenames/from/the/user'
);

if( array_key_exists($_REQUEST['path'], $allowed_includes) ) {
include($allowed_includes[ $_REQUEST['path'] ]);
} else {
print "No.";
}

?>

Here the single thing you're doing with user input is using it as an index into an array. I don't know of any security issues with that. I don't think you even have to escape the user input or manipulate in any way. If it does turn out there's something insecure with indexing an array in this way, you can very simply drop in another data structure in place of the array. The bad thing is you need to define the array manually and don't allow the user to specify entirely arbitrary filenames. (This may or may not be a good thing actually, depending on your point of view.) But you could get around that by having all your includes in a single directory and globbing it for filenames at runtime, and assigning each a key based on a cleaned version of the filename or an incrementing key value or whatever.

This way you also aren't required to forbid using .'s in the pathnames or any other limitation. You are controlling the file access entirely yourself so it's safe to include any file you want on your system in this way. (Depending on what you're doing with it once you include it, obviously.)

Again I may be entirely wrong. I don't know as much about this as I'd like.

Samuraid
12-21-2006, 03:28 AM
I'm probably not smart enough to find bugs or break your script, but I can see things that make me nervous.

I've heard (and I usually agree) that it's always better to define what you want to allow, rather than define what you want to disallow.
I agree completely.


You're disallowing periods and to some extent slashes, but you're allowing nearly anything else.
Why is this bad? Unix allows such characters (excluding the "/" and empty ASCII space to be part of the filename). Technically, although unlikely, such characters may be present in a valid filename.


In reality you'd want a filename to match a pattern like /^[A-Za-z0-9][A-Za-z0-9.]*$/. (Or modify it to allow slashes, but I wouldn't even allow them at all, personally.) Anything that doesn't match your regex should be rejected immediately. I passed your script a filename like #$%%*#!!%#^ and nothing bad happened, but still it accepted it as a valid filename all the way to the point where it was testing the filesystem for its existence. That's probably not good. I was looking for ways to URL-escape a "." character, and couldn't find any that survived your script, but if there are some, it would defeat your script also.
In Unix, "#$%%*#!!%#^" is a valid filename. :)
I don't think URL encoding would get past the check either. If (for some strange reason) it did, one could simply call rawurldecode() on the path before all the checking.


People can also start passing arbitrary binary data in via POST. I'm always scared someone's going to send me a 50MB URL and it's going to overflow and start doing horrible things.
People can send large amounts of post data, but the quantity is limited by PHP configuration settings.
post_max_size - Sets the maximum size of post data PHP will accept before bailing
max_input_time - Maximum time PHP will spend parsing post data
If 50MB would cause it to overflow, I would seriously lose all faith in those programming PHP. I don't think they would be foolish enough to provide open source code with any such overflow vulnerabilities.


You're also disclosing to the user the names of all your files. There's no reason the user needs to know this. If your files are in some path not in DOCUMENT_ROOT, you're exposing what your server's file structure looks like.
Well, the only way this script could be reasonably run would be within the web root directory anyway, so only webspace files could ever be included. As far as I can tell, there isn't a way to back up in the directory structure and get into any parent directories or files. Also, this is actually an abbreviated version of the script. (that I edited together quickly) The full version actually auto-appends the .php extension and will only include files of .php type. I simply provided a stripped down version here with the assumption that anyone using it would add and modify to fit the need. :)


Here the single thing you're doing with user input is using it as an index into an array. I don't know of any security issues with that. I don't think you even have to escape the user input or manipulate in any way.
I completely agree with this: having an allowed list is the safer solution.


This way you also aren't required to forbid using .'s in the pathnames or any other limitation.
Just as a note: my code only limits files and directories that start with a ".", any .'s later in the filename are allowed.

Dr Unne
12-21-2006, 05:57 PM
Why is this bad? Unix allows such characters (excluding the "/" and empty ASCII space to be part of the filename). Technically, although unlikely, such characters may be present in a valid filename.

I was thinking of other operating systems actually. I saw you were changing \ to /, so I thought you'd want this to run on Windows too. I don't know if Windows allows such filenames; I'm no Windows expert. I don't know what a valid pathname on OS X is, either. Or say VMS or some arcane OS. (Relying on / as the pathname delimiter likely eliminates a lot of OSes, but anyways...)

I have two choices: I can become an expert at what filenames are valid; or I can set an artificial limit and only allow simple letters and numbers, which I KNOW are valid pretty much everywhere. There are good and bad things about each way of doing it. One good thing is that my method lets me be lazy. But I see my regex excluded underscores for example, which is probably overly strict.

Even though Unix filesystems technically allow such things, I would be wary of anyone actually using files named $%@#$%^. From a readability perspective if from nothing else.


People can send large amounts of post data, but the quantity is limited by PHP configuration settings.
post_max_size - Sets the maximum size of post data PHP will accept before bailing
max_input_time - Maximum time PHP will spend parsing post data
If 50MB would cause it to overflow, I would seriously lose all faith in those programming PHP. I don't think they would be foolish enough to provide open source code with any such overflow vulnerabilities.

I only mention that because I am aware that such a vulnerability exists in Perl, because the limit for the max size of POST data is not set to a sane value by default in the CGI module. Or such a vulnerability existed a few years ago. And actually I think the vulnerability would only lead to denial of service attacks and not buffer overflows or anything, so my point is probably entirely irrelevant now that I think about it.


Well, the only way this script could be reasonably run would be within the web root directory anyway, so only webspace files could ever be included. As far as I can tell, there isn't a way to back up in the directory structure and get into any parent directories or files. Also, this is actually an abbreviated version of the script. (that I edited together quickly) The full version actually auto-appends the .php extension and will only include files of .php type. I simply provided a stripped down version here with the assumption that anyone using it would add and modify to fit the need. :)

Imagine you're including a file in $DOCUMENT_ROOT/include/samuraid. You possibly wouldn't want to tell people "hey look, samuraid!". It gives them your username, which may be the same username you use to log in to all sorts of nasty things. It's potentially not a problem with your script, only a problem with the person who named that directory. And it could be argued that picking stupid values for the keys into my array is just as bad as picking stupid filenames, and I'm only moving the same problem up a level of abstraction.

But I prefer not to give users enough rope to hang themselves with, especially when there's no reason why you SHOULD tell people your pathnames. And abstracting the filenames at least gives you a way to make it safe without potentially breaking something underlying; the abstraction is entirely specific to my script. It's only security through obscurity, and you shouldn't rely ONLY on such things, but a bit of obscurity surely never hurt anyone.

(Is there also maybe the chance that a server that supports symlinks could cause some evil possibilities? I don't know if is_file() returns true or false for symlinks, so this may not matter either.)

My other point is that "I don't know of any way this information could be used" is limited by your knowledge; there may be ways to use it that you aren't aware of. I think it's always good to err on the side of caution. Imagine you're running another script that has a vulnerability where it lets people access files, but only if they can guess an exact arcane pathname in a certain single directory, and that it's really hard to guess those pathnames. And then you have your script, which tells people pathnames but doesn't give them any hole through which to access them. The two together could cause you problems, even if each alone is theoretically safe.

I'm sure you're aware of all of these things and I'm not telling you anything you don't already know, but I like hearing myself type. :) And other people may be reading.

I don't see any way people could use your script in an evil way either, given a sane web server. But I'm always paranoid (over-paranoid) about what I may be missing.


Just as a note: my code only limits files and directories that start with a ".", any .'s later in the filename are allowed.

Yeah, I saw that. I misspoke.

Samuraid
12-21-2006, 06:40 PM
I completely agree. :)

The script was meant mostly for those who had an idea what they were doing with it and were careful. It is definitely not meant for anyone to just drop onto their website verbatim and use without care. (Although it was originally written as a replacement for someone who was just including files directly from the query string on their site, and thus exposing all the files in EoFF's account as well)

And you are right about other OS's. Windows hates a number of those characters in filenames, and Mac uses ":" as the directory delimiter, so the script would need to be far more robust to work correctly in anything beyond *nix. I believe PHP does some of the necessary directory delimiter translation automatically, but the script would certainly need a lot more testing in that case.

rubah
12-24-2006, 05:32 AM
so uh, does this occur if you have an empty div, but it's *not* absolutely positioned? ^_^