securing a webpage without headers - php

I just read this article on tdwtf.com. Generally, it describes an archiving bot destroying things because it ignores headers. I then realized that I don't know how to do security in a page WITHOUT headers. Therefore my question is:
What security measures can i take besides using headers?
I develop mostly in php, so I'm familiar with header("Location: ") function. But what else is out there?
Ideally I'm looking to replace the logic of
if (!$something_important) header("Location: somehereharmless.php");
with something else (more) secure?

This one works pretty well
if (!$something_important) {
header("Location: somehereharmless.php");
exit();
}
Even if it's bot, so it doesn't respect Location, you will call an exit so the execution flow is halted anyway, so no harm

header: location is fine, as long as you include an exit at the end.
You might also want to include a link or something.
I usually use something like this:
<?php
function redirect($url)
{
header('Location: ' . $url);
exit('Redirecting you to: ' . $url . '');
}
redirect('somepage.php');
?>
This way people can't bypass the redirect, and know that they should be redirected.
[Edit]
Also, always use POST when deleting stuff. It is very easy to create a fake GET (for example <img src="http://www.example.org/action.php?do=SetAsAdmin&userid=MyUserId" />).

Make sure all your gets are idempotent
Idempotent means that doing same request many times has the same effect as doing it once.

I'd say that if you have a PHP script that performs some action which only, say, logged-in users should be able to perform, you must put the check for being logged in right there in the very same script, so you can look at it at a glance and see that the code is secured. My rule is that there are only two valid patterns for protecting secured code:
if (user_is_authorized()) {
// restricted code here
}
or Alekc's
if (!user_is_authorized()) {
// send headers or whatever if you want
exit();
}
// restricted code here
To be perfectly honest, I was rather shocked... or at least disappointed... when I read that article - I can't understand how someone came to the conclusion that a website could be secured with HTTP headers. A header is nothing more than some text that your server sends out. It's an instruction that may be followed or ignored by the client at will (at least, you have to think about it that way for security purposes). As far as I'm concerned, outgoing (response) HTTP headers are pretty much useless for security. (This is not counting things like HTTP authentication, where you send a header and get one back in response... but in that case it's the contents of that reply header that you base your security on, not the header you sent out.)

The reason for the incident reported in the link you provided was the missing exit; statement after the header();. The bot can't do any harm if the script stops.-

if (!$something_important) {
header("Location: somehereharmless.php");
//close all your db connections and other stuff you need to end..parhaps calling a function?
die("If the redirect doesnt start in 3 seconds, please click here");
}

Your solution is
<?php
die($errormessage);
Die will just halt your script, not go through start, don't collect any data that you shouldn't.

Addition to Alekc's answer. If you have many header("Location:") statements and the person qualifies for them all. The last one will fire.
if($foo && $bar)
{
header("Location: somehereharmless.php");
}
if($foo && $baz)
{
header("Location: someotherplace.php");
}
So if that user has all 3 variables set, he will get redirected to someotherplace.php. Unless you have an exit(); or a die(); after the header();

Related

is there a way to filter/suppress HTML from making it to the client?

i'm new to php, and i'm having a hard time establishing proper session mgmt. controls to prevent unauthorized access to a specific section of my site. I'll give an example...
myimaginarysite.com/application/index.php has a form to auth the user and it will redirect you to 'portal.php' after successful auth. 'portal.php' will check for a valid session as part of an include and then based on that it will either send u back to authenticate via header("location....) or just load up the HTML content. Now, if an unauthorized user hits 'portal.php' directly.. because they won't have a valid session.. they will get redirected back to the index, however, if you proxy the traffic you will see that the whole HTML content for 'portal.php' will actually be sent to the client (although not displayed on the browser) before redirecting back to the login page. So my question is... am I missing something, is there a way to make sure the HTML content is suppressed and is not sent to the client??
below is a snippet of my code for 'portal.php'
<?php
include "includes/checksession.php";
?>
<html>
<body>
Who Am I ??
<br></br>
Log Off
.....bunch of authenticated content.....
</body>
</html>
You need to stop script execution after sending the redirect headers with die() or exit(). Header redirection only sets the http headers, otherwise the page content is the same unless you instruct it otherwise.
Stopping script execution, like Juhana suggested, is probably the easiest solution for now, but there are other possibilities of course. You can just make the output conditional:
<?php
if (checkSession())
{
// redirect to login page
}
else
{
// output HTML.
}
If your site grows larger, it will probably (hopefully) also be more structured. If so, it might be easier to include other page fragments. So your code could look like this at first:
if (!checkSession())
{
include 'loginpage.php';
}
else
{
include 'portalpage.php';
}
And eventually maybe:
if (!checkSession())
{
ApplicationContext.setController(new LoginPageController());
}
Whatever the case, exit works fine and may be useful, especially for a case like this, but it terminates your script quite abrubtly, so it might get in the way of other processes that you may want to include, like debug-output or logging, profiling, and stuff like that.

PHP header(); reliability

I need to redirect users if I don't want them to be able to access a certain page. How reliable is header('Location: ../acc/login.php'); for example? Can browsers ignore 302 errors, and is this the right way? Thanks in advance!
It depends a lot what you're trying to do. Technically spoken, header() is somewhat reliable. Only somewhat, because many PHP users have problems with it and to not get it to work.
PHP will prevent it from working if output has been already send to the browser. A drastic example:
<protected page content here>
<?php
header('Location: login-first.php');
exit();
?>
This would not work at all. You would eventually see even an error message with a warning.
Headers - by design - need to be send out before any other content (response body). They can not be send any longer if the response body has already started and PHP can't help you then in that case.
However, if you send headers before the response body, that function will work. Also the risk obviously to mess something up is not that drastic any longer, too:
<?php
header('Location: login-first.php');
exit();
?>
<protected page content here>
You can rely on header(), but make sure you called die(), exit() or return after that. Otherwise, script will continue its execution, which is potential security issue.
The browser can ignore header('Location: '); forwarding.
That is why you should always return after a call to a header() forward so the rest of your code does not execute should the browser not honor the forwarding.
It is the correct way to do things tho.
I would send the header command and then the exit command "exit()" (to stop running the php code on the server) before displaying the rest of the page. This way the user would never be sent the page content even if they ignored the 302 redirection.
And yes the user can ignore the 302 redirection:
http://www.webmasterworld.com/html/3604591.htm
header is 100% reliable.
However header('Location: ../acc/login.php') will be evaluated in the browser to a real location on your website, and ../acc/login.php wil not form a url that is valid!

Can you carry POST variables page to page if redirecting?

To start, I am not asking if I can create a POST response from one page to another without use of a form or one of the similar questions which may come to mind. At the start of several of my pages, I automatically force https security with the following require statement:
<?php
if($port == 80) {
if($_SERVER['SERVER_PORT'] == 443) {
header('Location: http://'. $_SERVER['HTTP_HOST'] . $_SERVER["REQUEST_URI"]);
exit;
}
} elseif ($port == 443) {
if($_SERVER['SERVER_PORT'] == 80) {
header('Location: https://'. $_SERVER['HTTP_HOST'] . $_SERVER["REQUEST_URI"]);
exit;
}
}
?>
where $port is set directly before calling the PHP require. In some instances where directing from a http to https (or simply changing the URL by person), any POST variables generated from the form on page 1 would be lost on the redirect.
Maybe I am asking the same question as the 'no form' but if so, any advice on how to handle based on the requirements is appreciated.
Thoughts
I could put everything into SESSION but this seems like a huge waste of resources. Unless somebody can really show otherwise, I don't consider this a solution.
I've seen other questions that ask essentially the same question, and I believe it's not really possible to do what you want effectively. My own opinion is it's going to be a whole lot MORE work to make what you want than just to deploy SESSION:
<?php
session_start();
if (!is_array($_SESSION['posted'])) {
$_SESSION['posted'] = array('test'=>'test');
} else {
$_POST = $_SESSION['posted'];
unset($_SESSION['posted']);
}
echo '<pre>';
echo "<strong>POST:</strong>\n";
print_r($_POST);
echo "\n";
echo "<strong>SESSION:</strong>\n";
print_r($_SESSION);
?>
* Note: I don't have SSL setup on my server, so I can't demonstrate that specifically. This is meant to demonstrate reinflating a POST array only from a SESSION-stored array.
http://jfcoder.com/test/postsession.php (Refresh to see it change.)
So if you can rebuild a POST array so easily^, why not just do that? The resources needed to do it across requests that are needed and actually used I believe will be negligible, since you're really only doing it for a moment.
Unless you have hundreds of thousand or millions of concurrent hits, I can't imagine the above being a problem resource wise. If it was, then just process it before redirecting. They've already sent the data in the clear at that point anyway.
^ Also, you will need to handle file uploads as well, if you need that.
If you really don't want to do any server-side storage, use a 307 redirect. Should work with any HTTP/1.1 compliant browser... however note that not only will you be using twice the bandwidth for the POST data (since it is sent twice), but browsers are required to ask for permission before resubmitting to the new URL.
header('HTTP/1.1 307 Temporary Redirect');
header('location: .... );
[edit: Storing it server-side temporarily is probably better. Avoiding the need to redirect at all is best.]

Sending a request to another site that has a callback that targets my original page

In my test.php file, I sent a request to a Flickr app I have using
header("Location: " . $request);
where $request is the URL that I am trying to reach on Flickr.
For my Flickr app, I have to set a callback URL. When Flickr is done with processing my request, it will call the callback URL.
I would like the callback URL to be my original page, test.php. When I try this, I get stuck in an infinite loop, because test.php is re-sending the request back to Flickr, and Flickr calls my test.php again (repeat ad infinitum until the browser quits).
Is there a way to put some kind of conditional in test.php to check if the request came from Flickr, or at least some way to let the script know that the request has been sent, so don't send it again.
I've already tried it where I changed the callback URL to another page of mine, and that works fine. I'm just seeing if I could re-use the same page.
Its ugly.
The two posted solutions won't work because:
The referer isnt changed on redirect (well it is cleared if its a http meta redirect, but not if its a header redirect. but it doesnt become something else so easy).
Putting exiting after a sent header is generally a good idea if there is something else normaly executed afterwards, but its not related to the problem.
Simply put, if it should be the SAME page, you need to to store in a file or database or something the redirect counts per ip adress/user and break or something but NONE of this is really reliable. You can make it more secure by having a secured token that cannot be reverse engeneered etc but all this doesn't make sense. You could also use cookies. Which is just as unreliable as well.
Regarding your problem, flickr does NOT redirect back to the samep age.
Regarding to their specifications they append ?frob=[frob].
http://www.flickr.com/services/api/auth.spec.html
Check for that:
<?php
if(!isset($_GET["frob"])) {
header("Location: " . $request);
exit();
}
?>
try checking the referer with the $_server['HTTP_REFERER']
[Edited]
I just wanted to say that, you should try adding if condition
// just and example, use some regular expression to check the refere
if($_SERVER['HTTP_REFERER'] != http://flicker.com){
header("Location: " . $request);
}else{
// another code
}
Thanks
As an alternative to checking for the (non-)existence of $_GET["frob"], couldn't you set the callback url in Flickr to be www.mysite.com/test.php?from_flickr=1 and then do
if (!$_GET['from_flickr']) {
header('Location: '.$request);
exit;
}

Should I use "return;" after a header()?

Quick question, I noticed that on some of my header directors I was getting some lag while the header processed. Is using return standard after using headers? Also if you use a header on pages you don't want directly accessed, such as processing pages will return; stop that processing even if the page is not directly accessed? IF return is a good idea would it be better to use exit()?
header("Location: ......"); exit; is a fairly common pattern.
You do not need to supply return; after calling header but I know some people use the convention of supply exit; after header call to ensure the code below will not execute during a redirect.
Keep in mind you can use header() for other things besides Location: redirects:
header("Content-type: image/jpeg"); // for example
The reason you would exit after a header redirect is, any content output after a header() redirect, will (most likely) not be seen by the browser.
More importantly you wouldn't want any code to be executed after a header() redirect, so calling exit() after a redirect is good practice.
When you send the header, it is but a mere advisory to the client(the browser) that you think they should request another url instead. However, nothing can stop them from not following your recommendation. They can continue reading more data from the current url, if your server keeps feeding it to them. This is why you generally see php code that calls exit() after sending a redirect header, because if you stop outputting more data, there is nothing for them to read.
Aside from keeping them from reading unintended data, there's other reasons:
Maybe it's just plain senseless for the rest of the script to continue executing, wasting resources.
Maybe runtime errors would occur if the script were to continue(ex, there were missing variables, or a db connection failed).
Maybe logic errors would occur if the script were to continue(ex, user input validation/authentication failed).
It's up to the client to determine what to do after an header("Location: ...").
Any code after header() will be executed regardless. Putting an exit(); just after the header is a safeguard and is required for securing your site.
If you have some candy after header("Location: ..."), the only thing the browser have to do is to ignore the request. Then it'll be clear as day. With exit(); you're stopping execution of the page and hopefully there are no other attack vectors to your app!

Categories