PHP include from URL that redirects - php

I've inherited a bad sitation where at our network we have many (read: many) hosted sites doing this:
include "http://www.example.com/news.php";
Yes, I know that this is bad, insecure, etc, and that it should be echo file_get_contents(...); or something like that (the output of "news.php" is just HTML), but unfortunately this is what they use now and we can't easily change that.
It used to work fine, until yesterday. We started to 301-redirect all www.example.com requests to just example.com. PHP does not appear to follow this redirect when people include the version with www, so this redirect breaks a lot of sites.
To sum it up: Is there a way to get PHP to follow those redirects? I can only make modification on the example.com side or through server-wide configuration.

You said, in a comment: "I can go and change all the includes, but it'd just be a lot of work".
Yes. That's the "bad, insecure, but-I-don't-have-a-reason-to-change-it code" coming back to bite you. It will be a lot of work; but now there is a compelling reason to change it. Sometimes, cleaning up an old mess is the simplest way out of it, although not the easiest.
Edit: I didn't mean "it's your code and your fault" - rather, "bad code is often a lot of work to fix, but it's usually less work than to keep piling hacks around it for eternity, just to keep it kinda-working".
As for "going and changing it", I'd recommend using cURL - it works much better than PHP's HTTP fopen wrappers.

Can't you use curl? In curl_setopt it has an option to follow redirects.

Let's start with the redirecting http repsonse.
<?php
error_reporting(E_ALL);
var_dump( get_headers('http://www.example.com/news.php') );
// include 'http://www.example.com/news.php'
The output should contain HTTP/1.0 301 Moved Permanently as the first entry and Location: http://example.com/news.php somewhere.

I don't think any of those solutions provided by PHP itself would help... I just don't think any of them follow headers and what not. For what it's worth, I do think, though, that this behaviour is correct: you're asking for the result of a certain request and you got it. The fact that the result is telling you to look elsewhere is, in and of itself, a valid result.
If I were you, I'd look at cURL. There's a PHP extension for it and it will allow you to tell it to follow headers and get to where you're trying to get. If this is not usable (as in, you absolutely, positively have to use the approach you currently are), you will need to revert the redirects on the 'source' server: maybe you could have it return the information or the redirect based on requesting IP address or something similar?

Related

Best alternative to http_referer for internal redirect?

after discovering the unreliability of HTTP_REFERER, I was wondering what was the best alternative to indicate an operation the correct url of origin which then perform an internal redirect.
After reading various topics I seemed to understand that only possible solutions are:
1) specify the referer url directly as a parameter of the operation.
2) create a custom referer storage system using session.
In my opinion, the first solution is logically more correct and free of contraindications.
Using the second solution and storing the referrer in session on every page request is possible that using the site in the various tabs referrer stored does not correspond to the page where we're actually sending the operation; Despite this bug (in my opinion quite ugly) this second solution seemed the most recommended by experts. Why? Did I miss something?
Thank you all for your attention and sorry for my low level of English.
storing the referrer in session on every page request is possible that using the site in the various tabs referrer stored does not correspond to the page where we're actually sending the operation; Despite this bug (in my opinion quite ugly) this second solution seemed the most recommended by experts
You could notify server to update session with current page before leaving - this way next loaded page will know what was the previous one without passing anything in URL.
That said though this solution still have some faults - it will break on any connection failure or if someone loads multiple pages in multiple tabs and requests go out of synch (it's relying on an assumption that between javascript sending request on leaving the page and server receiving request to load a next page nothing else occurs).
Best way would be to use both - this and HTTP_REFERER as a fall-back option.
Other than that mentioned passing of current pages in URL will do, but it's understandable why you try to avoid it.

Should I handle redirection via PHP or Javascript?

I'm refactoring some old code and trying to understand headers a bit better.
I read an awesome answer in the following post on No output before sending headers!
Now I understand the 'why' but when it comes to implementation Its still a bit fuzzy.
My current page redirects back when the cancel button is clicked with the value searched.
I store the page the request was made from and the value in session variables allowing me to do this:
if (isset($_SESSION['searchPage'])){
header('Location:searchForm.php?ticket='.$_SESSION['product'].'&searchbtn=Search');
exit();
}
However to make this work in the display page I had to to use ob_start().
To avoid this workaround I found that I could redirect via javascript:
if (isset($_SESSION['searchPage'])){
echo '<script>window.location="searchForm.php?product='.$_SESSION['product'].'&searchbtn=Search";</script>';
exit();
}
Now to my questions
Which method is better or acceptable?
I can't seem to think of a way to design my page in such away where no output is sent before using header(). If a button click event causes redirection how do you handle redirection in php without using ob_start() ?
edit
First and foremost, you might want to read up some more on redirecting using header. Instead of just setting header('Location:...');, redirect using the following code:
header ('HTTP/1.1 301 Moved Permanently');
header('Location:searchForm.php?ticket='.$_SESSION['product'].'&searchbtn=Search');
A 301 redirect is generally better for SEO, and most browsers will cache the redirect, so the client history stack will be more reliable, which is good news for the JS scripts that might use the history...
Which is the better approach?
PHP. Relying solely on JS for redirecting the client is not a great idea. Clients might turn of your script, or if some error creeps in the JS code, the redirection won't work. Some borred teen might feel like messing with your code, and find possible security issues in your site.
2. How to use ob_*, or how to use header without ob_*?
Just start your entry script (index.php) with an ob_start() call, to make sure. Perhaps use ob_implicit_flush(true), to implicitly flush your output buffer. But more importantly, just call ob_flush() right after setting your headers.
Alternatively look into using a framework like Symfony2 and/or ZendFW. Code to handle redirects has been written for you many times, why not use it?
If you want to steer clear of output buffering, perhaps you might want to consider following certain patterns, or design principles (like MVC, IPO and the like) and write your code to (+-) always follow this order to take care of business:
Get the request
Process data from request, determine what data client is asking for
structure data
render page
send response
Right after you've processed the request, you'll be able to redirect, and since you're not even close to rendering the output, let alone sending the headers, you're safe to redirect and or set the headers...
Update:
Just a link in response to your follow-up question Gruyere has a special secion on XSS attacks you might want to read... Though the main purpouse of the document is, I believe, how to safely use mashups (which are actually bonafide XSS injections). Anyway, they do a far better job at explaining why and how JS can be used to undermine security of any webapp.
It’s always better to do it server-side. Both from an SEO point of view and because JavaScript redirects if a user has JavaScript disabled or there’s a problem downloading your JS file, or there’s an error in it that stops execution.
PHP redirection is best. Because even if a user has disable the script in his browser.
If you're using a noscript redirection then you can go for JS instead of PHP, so that in this case you can avoid ob_start().
If you want just to send a user to another page on a button click, why not just to implement a link:
go back
or button:
<button onclick="window.location='searchForm.php?ticket=<?=$product?>&searchbtn=Search'">go back</button>
I suggest a following approach:
function universal_redirect($url, $force_js = false) {
if (headers_sent() || $force_js) {
print('<script type="text/javascript">');
printf("location.href='%s';", $url);
print('</script>');
} else {
header('Location: ' . $url);
}
}
It is not always applicable but it is a good solution if you build admin-pages or when your project is big and complicated enough that you can't always guarantee that output was not yet started.
In general PHP redirect is much better for reasons given by #Elias Van Ootegem.

No require, no include, no url rewriting, yet the script is executed without being in the url

I am trying to trace the flow of execution in some legacy code. We have a report being accessed with
http://site.com/?nq=showreport&action=view
This is the puzzle:
in index.php there is no $_GET['nq'] or $_GET['action'] (and no
$_REQUEST either),
index.php, or any sources it includes, do not include showreport.php,
in .htaccess there is no url-rewriting
yet, showreport.php gets executed.
I have access to cPanel (but no apache config file) on the server and this is live code I cannot take any liberty with.
What could be making this happen? Where should I look?
Update
Funny thing - sent the client a link to this question in a status update to keep him in the loop; minutes latter all access was revoked and client informed me that the project is cancelled. I believe I have taken enough care not to leave any traces to where the code actually is ...
I am relieved this has been taken off me now, but I am also itching to know what it was!
Thank you everybody for your time and help.
There are "a hundreds" ways to parse a URL - in various layers (system, httpd server, CGI script). So it's not possible to answer your question specifically with the information you have got provided.
You leave a quite distinct hint "legacy code". I assume what you mean is, you don't want to fully read the code, understand it even that much to locate the piece of the application in question that is parsing that parameter.
It would be good however if you leave some hints "how legacy" that code is: Age, PHP version targeted etc. This can help.
It was not always that $_GET was used to access these values (same is true for $_REQUEST, they are cousins).
Let's take a look in the PHP 3 manual Mirror:
HTTP_GET_VARS
An associative array of variables passed to the current script via the HTTP GET method.
Is the script making use of this array probably? That's just a guess, this was a valid method to access these parameter for quite some time.
Anyway, this must not be what you search for. There was this often misunderstood and mis-used (literally abused) feature called register globals PHP Manual in PHP. So you might just be searching for $nq.
Next to that, there's always the request uri and apache / environment / cgi variables. See the link to the PHP 3 manual above it lists many of those. Compare this with the current manual to get a broad understanding.
In any case, you might have grep or a multi file search available (Eclipse has a nice build in one if you need to inspect legacy code inside some IDE).
So in the end of the day you might just look for a string like nq, 'nq', "nq" or $nq. Then check what this search brings up. String based search is a good entry into a codebase you don't know at all.
I’d install xdebug and use its function trace to look piece by piece what it is doing.
EDIT:
Okay, just an idea, but... Maybe your application is some kind of include hell like application I’m sometimes forced to mess at work? One file includes another, it includes another and that includes original file again... So maybe your index file includes some file that eventually causes this file to get included?
Another EDIT:
Or, sometimes application devs didn’t know what is a $_GET variable and parsed the urls themselves -> doing manual includes based to based urls.
I don't know how it works, but I know that Wordpress/Silverstipe is using is own url-rewriting to parse url to find posts/tags/etc. So the url parsing maybe done in a PHP script.
Check your config files (php.ini and .htaccess), you may have auto_prepend_file set.
check your crontab, [sorry I don't know where you would find it in cpanel]
- does the script fire at a specific time or can you see it definitely fires only when you request a specific page?
-sean
EDIT:
If crontab is out, take a look at index.php [and it's includes] and look for code that either loops over the url parameters without specifically noting "nq" and anything that might be parsing the query string [probably something like: $_SERVER['QUERY_STRING'] ]
-sean
You should give debug_backtrace() (or debug_print_backtrace() a try. The output is similar to the output of an Exception-stacktrace, thus it should help you to find out, what is called when and from where. If you don't have the possibility to run the application on a local development system, make sure, that nobody else can see the output
Are you sure that you are looking at the right config or server? If you go the url above you get an error page that seems to indicate that the server is actually a microsoft iis server and not an apache one.

User tracking through urls and avoiding manual tampering

I'd like to keep track of how many people follow a link sent through an email.
At the moment, I'm thinking of having a separate page which is called through the link with a get variable to indicate this was done from an email.
Obviously, this can be tampered with manually through the address bar of a navigator. What approaches could I use to limit this?
1)Use a completely different URL to redirect to the real one:
http://www.mysite.com/emailOffer -> http://www.mysite.com/specialpage
emailOffer would do the logging, and then send a Location HTTP header pointing to the real page (specialpage)
http://www.mysite.com/emailOffer would look like this:
/* SOME LOGGING CODE GOES HERE - PROBABLY MYSQL STUFFS */
header("Location: http://www.mysite.com/specialpage");
2)Add a GET parameter like: http://www.mysite.com/specialpage?email
then in php, you can do: if(array_key_exists('email',$_GET)) addToCounter();
3)You could log the HTTP Referer header for everyone who hits the page and run a query for referers containing "mail" (e.g., mail.google.com, hotmail.com)
To help prevent tampering, you could make the parameter seem worth while:
http://www.mysite.com/specialpage?secretOffer
Good luck! :)
PS - sorry for the terrible formatting of my answer...
In most cases people probably just use the GET method, in all cases though, it can be tampered with, pretty much every element can be changed if a person really wants to, but as far as telling where someone is going from you're pretty much stuck with GET or checking the referrer, which can be highly suspect, and you'd have to check all sorts of things.
If you aren't concerned with the actual link they're following in the email, you could create a secondary page, that hits your counter, outputs nothing, and just redirects them like
<?php
... do counter stuff ....
header('Location: http://actual.address.com/');
?>
Their navigation bar will change to the new address, and they'll barely even notice the original.

Is it possible to setup a redirect in a PHP file which is guaranteed to work?

I want to make a call to/include a PHP script which would force a re-direct to another page. (The other page will contain a captcha and will re-direct back if entered correctly).
I need the most reliable PHP redirect code possible, so no one can escape/avoid it. If the redirect fails then the rest of the page will be shown and that's not what I want.
The most reliable is probably issuing:
header('Location: http://example.org');
exit;
Although rare a browser might choose not to follow the redirect though and as far as I know you will not find a way of redirecting the user that is guaranteed to work if they actively seek to escape it.
Like I say though it would be a rare browser that did not recognise or accept a Location header and a user would have to actively disable it some how. It is part of the original HTTP spec after all.
No.
A redirection can be avoided if someone is actively seeking to avoid it or is using a browser which doesn't handle it correctly.

Categories