Securing a PHP Web service (SOAP) - php

I have a PHP web service that actually helps the CMS to carry out some updations to the database. I've been trying to search for a solution on Internet but haven't got my answer yet.
Is there any way to check if the user making request to the webservice is authorized to do so i.e. check the user session?
Here is my dummy service (services.php)
<?php
function GetMyUserName($i)
{
return "admin101";
}
$server = new SoapServer(null,array('uri' => ROOT."includes/services.php"));
$server->addFunction('GetMyUserName');
$server->handle();
?>
Here is the JavaScript (jQuery) for consuming the service [uses a SOAP envelop]
function GetMyUName() {
var req1 = "";
req1 += '<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope">\n';
req1 += '<soap:Body xmlns:m="includes/services.php">\n';
req1 += "<m:GetMyUserName>\n";
req1 += "</m:GetMyUserName>\n";
req1 += "</soap:Body>\n";
req1 += "</soap:Envelope>";
$.ajax({
url: "includes/services.php",
type: "POST",
data: req1,
cache: false
}).done(function (data) {
$("#UsernameTb").html($(data).find("return").text());
});
}
Is there any thing like the one we have in ASP's WCF to allow Sessions in the webservice.
I am using UserCake for authentication if this info is somewhat helpful.

Overview
Frankly UserCake looks like it was written almost a decade ago. Just look at login.php from UserCake, it calls die() uses header("Location: account.php") to redirect the client and echos HTML.
None of these things lend themselves to a service paradigm. Most importantly UserCake's reliance on redirects will make it practically impossible to leverage behind a SOAP or REST interface without substantial modifications. Just look at the securePage function...
//Check if a user has access to a page
function securePage($uri){
// earlier code omitted for readability here...
elseif(!isUserLoggedIn())
{
header("Location: login.php");
return false;
}
// ...
}
Services typically don't redirect. They return formatted response payloads (eg JSON or XML) and may use HTTP codes to indicate what the result of the service inquiry was. There are exceptions like OAuth, but that's entirely unrelated to the problem at hand.
I'd recommend selecting a proper framework, Code Igniter if you want something simple, Symfony if you want something robust. Both are fully capable of supporting pure HTML pages, API requests and authentication / authorization. But if it must be UserCake...
Beating UserCake into submission
A quick search tells us Javascript must follow the redirect. The client would need to determine if the response is HTML or JSON, then handle accordingly. Code lifted from this answer and this one illustrates how this might be done with jQuery.
$.ajax({
type: "POST",
url: "services.php",
data: {action: 'someSecuredAction', data: 'some data for the command'},
success: function(response, status, xhr){
var ct = xhr.getResponseHeader("content-type") || "";
if (ct.indexOf('html') > -1) {
// If data looks like HTML, this is some page from UserCake
// likely served by a redirect, just display it
var newDoc = document.open("text/html", "replace");
newDoc.write(response);
newDoc.close();
}
if (ct.indexOf('json') > -1) {
// If data looks like JSON we have a
// successful 'service' response from the server
}
}
});
In theory the browser will pass along any relevant cookies with the request, so the session should be available on the server. Feel free to correct me on this, but from reading around it sounds like the session cookie will be passed over the AJAX request.
Then your example 'service' (services.php) file could become something like this (the switch is just some contrived thing to give you an idea how to access the data from the request)
// If this ends up redirecting,
// the client should just pass it on through
securePage($_SERVER['PHP_SELF']);
switch($_POST['action']) {
case 'someSecuredAction':
// Again, if this redirects the client should be able to cope...
$loggedInUser->checkPermission(['someSecuredAction']);
// Do secured stuff here
$aResponse = someSecureAction($_POST['data']);
break;
}
// Now be nice enough to return the response as JSON
// like we might expect from an actual service
header('Content-Type: application/json;');
echo json_encode($aResponse);

Related

Cross subdomain AJAX request, CORS error [duplicate]

How would I go around the cross-domain issue when parsing XML from a different server/domain? Could someone provide me with an example? The example doesn't have to be restricted to jQuery only, as JavaScript will also suffice.
To fully understand why pure cross-domain XML will not work, it helps to first look at how cross domain JSON is facilitated.
First, let's look at what happens when you make an AJAX request in jQuery:
$.ajax({
url: '/user.php?userId=123',
success: function(data) {
alert(data); // alerts the response
});
In the above example, the AJAX request is made relative to the domain. We know that if we attempt to add a different domain before the path, the request will fail with a security exception.
However, that's not to say that the browser cannot make requests to another domain. Here is an example that may be familiar to you:
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
Based on our knowledge of how to import JavaScript on the page, we see that it is possible to load a resource that exists on another domain!
JSONP is a concept that exploits this knowledge. JSONP stands for "JSON with padding", and it's success hinges on the fact that JavaScript Objects can be expressed using a string notation, and the fact that JavaScript script tags can load and run content from external domains.
Under the hood, jQuery's JSONP looks something like this although it may not be exact:
// programmatically load a script tag on the page using the given url
function loadRemoteData(url) {
var script = document.createElement("script");
script.setAttribute("type","text/javascript");
script.setAttribute("src", url);
document.getElementsByTagName("head")[0].appendChild(script);
}
Also, on the page somewhere, we define a callback handler:
function processData(jsonResult) {
alert(JSON.stringify(jsonResult)); //alert the JSON as a string
}
Here, we make the request:
// make a request for the data using the script tag remoting approach.
loadRemoteData("http://example.com/users.php?userId=123&callback=processData");
For this to work properly, our PHP script must both return the data in JSON format, and it must also add "padding" around the string in the form of a JavaScript function name that we may pass in as a parameter (i.e. "callback")
Thus, the response from the server may look something like this, if we were to look at it in the Firebug or Chrome NET tab:
processData( { "userId" : "123" , "name" : "James" , "email" : "example#example.com" } );
Because we know JavaScript content runs as soon as it's downloaded, our processData function we defined earlier is immediately called and is passed our JSON string as a parameter. It is then alerted, using JSON.stringify to convert the object back into a string.
Since it's an object, I could also access it's properties, like so:
function processData(jsonResult) {
alert(JSON.stringify(jsonResult)); //alert the JSON as a string
// alert the name and email
alert("User name is " + jsonResult.name + " and email is " + jsonResult.email);
}
Finally, let's move onto the main question: Can JSONP be used to fetch XML, or can we parse XML cross-domain? The answer, as others have pointed out, is a resounding NO, but let's look at why by using an example:
processData(<?xml version="1.0"><user><userid>12345</userid><name>James</name><email>example#example.com</email></user>);
Now, what will happen if raw XML is passed into the function? It will break, as JavaScript has no way to convert XML into JSON.
However, suppose we put the XML in quotes:
processData("<?xml version="1.0"><user><userid>12345</userid><name>James</name><email>example#example.com</email></user>");
Now, in this example, the jsonResult variable actually takes a string, which we can work with. Using some JavaScript XML parsing utilities, we could load that string into the XML DOM Parser and do stuff with it!
However, it's not pure XML, it's still a JavaScript response under the hood. The response type from the PHP server is still text/javascript, and we're still using a script tag to load what is really just plain JavaScript.
In summary, you could work with "XMLP" or XML with padding (I just made that up, it's not real!), but if you're going to go through all of the trouble of actually modifying your response to return a function callback wrapper, you may as well just convert your output to JSON and let the browser handle conversions automatically and natively and save yourself the trouble of having to use an XML parser.
But if for some reason it's easier to keep your data in XML format, you could modify the response and give it a JavaScript wrapper.
Cases where I could see this being useful might be if you have XML data from a legacy application stored in a database, and you return it to the client-side using script-tag remoting or JSONP calls.
I found a very good solution to retrieve xml from cross domain ajax request.
Since jQuery 1.5 you can use dataType "jsonp xml" (http://api.jquery.com/jQuery.ajax/) !
So i used this :
$.ajax({
type: "GET",
url: "http://yoururl",
dataType: "jsonp xml",
success: function(xmlResponse) { // process data }
});
Server side for my Webservices i used to encapsulate the xml string result within the callback created by jQuery:
private static Stream GetXmlPStream(string result, string callback)
{
if (result == null)
result = string.Empty;
result = EncodeJsString(result);
if (!String.IsNullOrEmpty(callback))
result = callback + "(" + result + ");";
byte[] resultBytes = Encoding.UTF8.GetBytes(result);
if (WebOperationContext.Current != null)
WebOperationContext.Current.OutgoingResponse.ContentType = "application/xml";
return new MemoryStream(resultBytes);
}
and the magic method (i found it in another Stack thread) that you'll need to sanitize your xml string (so javascript can parse it) :
private static string EncodeJsString(string s)
{
StringBuilder sb = new StringBuilder();
sb.Append("\"");
foreach (char c in s)
{
switch (c)
{
case '\"':
sb.Append("\\\"");
break;
case '\\':
sb.Append("\\\\");
break;
case '\b':
sb.Append("\\b");
break;
case '\f':
sb.Append("\\f");
break;
case '\n':
sb.Append("\\n");
break;
case '\r':
sb.Append("\\r");
break;
case '\t':
sb.Append("\\t");
break;
default:
int i = (int)c;
if (i < 32 || i > 127)
{
sb.AppendFormat("\\u{0:X04}", i);
}
else
{
sb.Append(c);
}
break;
}
}
sb.Append("\"");
return sb.ToString();
}
Hope this will help !
I realize this is an old question, but I found this while searching. And also, I think the answer is for a slightly different question than the one posted here, so I want to add this answer which should work in at least jQuery 1.12 and later. I haven't tested in earlier versions.
OK, I want to request this URL: http://sample.domain/feeds/itemdata.xml
And I want to find the Item in that looks like this:
<Item>
<ProductItemNo>1228101530</ProductItemNo>
...
</Item>
This works, cross-domain:
$.ajax({
dataType: "xml",
url: "http://sample.domain/feeds/itemdata.xml",
success: function(xml) {
var itemdata = $(xml).find("ProductItemNo:contains('1228101530')").parent();
}
});

simple jsonp not working with php server

I tried following some basic examples, and it is not working. I am not sure I completely understand jsonp, but I followed the basic tutorials and on an intuitive level, I can't see anything wrong. (Of course, I am missing something, hence the question).
JavaScript code:
postData = $(this).serialize();
console.log(postData);
$.ajax({
data: postData,
url: 'externaldomain.php',
dataType: 'jsonp',
success: function(data){
console.log(data);
alert('Your comment was successfully added');
},
error: function(){
console.log(data);
alert('There was an error adding your comment');
}
});
PHP code:
$tag = mysql_real_escape_string($_GET["callback"]);
The annoying part is that it is not even showing me an error to Google for.
Can anyone help out figuring the problem please?
Since you haven't posted your full or relevant PHP code I'm going to assume it looks like this
$tag = mysql_real_escape_string($_GET["callback"]);
echo $tag."(";
// print json here
echo ")"
I'm not really sure how jquery handles jsonp requests but what I used to do is add a new script tag to the DOM that looks like this
<script> function cb(json) { alert(json); } </script> // (I)
<script src="{url}?callback=cb"></script> // (II)
When (II) is loaded, and because we have a callback then the script that we are including in the DOM looks like this
cb({
// json goes here
})
which pretty much is like a function call to some function called cb that we are using. It is therefore natural to have an implementation of cb (which is in (I)). That implementation is similar to the success(data) function in jQuery's ajax. It is used to use and manipulate the json requested
However I noticed that you are doing a POST request along the ajax call with jsonp. Unfortuantely (according to this question How to make a jsonp POST request that specifies contentType with jQuery?) doing POST with JSONP is not feasable due to implementation pursposes.
You can't POST using JSONP... it simply doesn't work that way...
So you can usually only perform GET requests. You can NOT perform POST requests.
For details about how jsonp work look at this nice article. jsonp-how-does-it-work
For more clearification :
See Other SO question Link1 Link 2
But there is work around for that with some limitations look at this Using PUT/POST/DELETE with JSONP and jQuery. (for me nothing works at all)

Is it possible to 'echo' a sequence of responses from an ajax call

I'm learning and experimenting with jquery/ajax as I develop a website. I have a page that updates a database. I would like a 'sequence' of responses to display on the screen when the user submits their data (I've seen this done on many other sites).
For instance... user submits form and the page displays:
Received Input
Checking Database - recond number xy
Updating Database
Retrieving Information
etc etc
This is just an example but you get the idea.
I have an ajax call that is initiated on 'click' of the submit button (getFormData just serialises all the form data for me and works fine):
var toSend = getFormData($upgrade_db_form);
var formMessageBox = $("#displayResults");
$.ajax({
url: ajaxurl,
data: {
action: "database_action",
formData : toSend
},
type: 'POST',
dataType: 'TEXT',
beforeSend: function() {
//$form.fadeOut('slow');
formMessageBox.html("starting it up");
},
success: function (data) {
formMessageBox.empty();
formMessageBox.html(data);
error: function (xhr) {
// formMessageBox.html("Oops error!");
}
});
I have a function which gets called by ajax:
function upgrade_database_function() {
echo "testing ";
for($i = 0; $i < 99; $i++) {
echo "percent complete ".$i."%";
}
echo "done ";
die(); // this is required to return a proper result
}
I'm using Wordpress and all the ajax side of things works fine, it passes the form data correctly etc, it's just that I get one long output as though it's cache'ing all the echo's up instead of outputting them in sequence.
I've gone through the jquery ajax documentation and couldn't find how to make it behave the way I want it to. I can live with it the way it is but I think it would look a lot better if I could get it working the way I would like.
Can this be done this way or do I need lots of sequential ajax calls to make it work?
I don't know PHP, but i'm guessing that the echo is just writing to the response buffer... so when all the echos are done the whole response will be returned and you would get the effect that you are seeing... You would need to go with a polling system or something along those lines to get the latest status' from the server and display them I would think... Maybe there is some system in PHP that allows this, but as I said, I don't know PHP.
An Example of Long Polling can be found in this article.
http://www.abrandao.com/2013/05/11/php-http-long-poll-server-push/
WARNING: You may have to do some manual managing of locking of the session in PHP so that your long running call doesn't lock your polling ajax calls: See here:
http://konrness.com/php5/how-to-prevent-blocking-php-requests/
Note that you would likely be wanting to:
create one ajax call that starts the execution of some coded that will take a while... you could put messages that have been generated into a session variable for example in a list of some sort. You would need to lock/unlock the session as mentioned to prevent suspension of AJAX polling calls.
you would create a polling method like in the article that might check the session every 500ms or something to see whether there are any more messages, lock the session, remove those messages and return those messages to the client side and display them.
WARNING: Again, I'm not a PHP person, I may have done this once in my life in PHP (can't remember exactly) but I may be wrong and this may not work, from what I've seen though it looks like it is achievable. Hope this gets you on your way!

Mobile browsers doesn't support session variables?

I have a browser version of my web app and I have some values stored in cookies. Now I am making a mobile version and it seems that my cookies are not working.
Is it possible to use cookies on mobile devices?
I am trying to perform this code and my php is giving me an empty value:
$(document).ready(function() {
var session_lang= '<?php if(isset($_SESSION['SESS_LANGUAGE']))
echo $_SESSION['SESS_LANGUAGE'];?>';
if (session_lang!='')
{
check_and_change(session_lang);
}
});
Is there any other way to store data in internal memory so it can work as cookie?
Does mobile devices support session variables? I am looking on the firebug and I can see that I can create session variable but when I want to read it it is null.
What could be a problem and how to solve this?
EDIT:
I will put you almost entire code so you can see what am I doing...btw. this code is working normally on PC browser.
Javascript file:
$(document).ready(function() {
function languageChange()
{
var lang = $('#websites1 option:selected').val();
return lang;
}
$('#websites1').change(function(e) {
var lang = languageChange();
var dataString = 'lang=' + lang;
$.ajax({
type: "POST",
url: "pass_value.php",
data: dataString,
dataType: 'json',
cache: false,
success: function(response) {
check_and_change(response.message);
}
});
return false;
});
} );
function check_and_change(lang)
{
switch (lang)
{ //do something
}
}
Then this first part that I have put above is on the actual php site that I am looking and which is opening:
And the last thing is pass_value.php:
<?php
session_start();
$_SESSION['SESS_LANGUAGE'] = $_POST['lang'];
print json_encode(array('message' => $_SESSION['SESS_LANGUAGE']));
die();
?>
I really don't know why this code doesn't work on the mobile phones.
Cookies definitely work on mobile browsers. You say "I am looking on the firebug" which makes me think you aren't really looking at it on a phone.
Have you started the session, and turned on error reporting?
I had a similar situation and discovered that, before my tablet called the script I specified in the URL parameter of the .ajax( ) call, it was actually calling the index.php script again.
Same with my phone. Since I had initialized my session variables in index.php, they kept getting re-set to their initial values (making it look like they were not being correctly stored between pages).
I never figured out why index.php was getting re-called, but I added if !isset( ) checks around the initialization statements and that cleared it up.
On Android, turning on "Data Saver" effectively destroyed my session. I have a login script which will redirect to the previous page when login succeeds. Worked until I turned on Data Saver. Turning it off made it work again. Google does state that Data Saver may affect secure pages which I guess includes my script, which is not on a HTTPS website.

jquery sending cross domain data via A $.post

I am trying to send data over to a cakephp (mvc) website, via $.post(). below is the code
$('#testReq').click(function () {
console.log('Button Works');
$.post('http://play.anthonylgordon.com/usersessions/store/', { data: 'test7' }, function (data) {
//data contains the json object retrieved.
console.log(data.status);
}, "json");
})
Below is the cakephp data that retrieves the data and stores it. If you know cake, great but if not it's fine. I am really trying to figure out if i am sending the data correctly
<?php
class UsersessionsController extends AppController {
var $name = 'Usersessions';
var $helpers = array('Html', 'Form','Ajax');
var $components = array('RequestHandler');
function store()
{
Configure::write('debug', 0);
$this->autoRender = false;
echo 'hello';
if ($this->params['url']['data'])
{
$this->data['Usersession']['data'] = $this->params['url']['data'];
$this->Usersession->Save($this->data);
echo 'Success';
}
}
}
?>
As you can see I put 'hello' before it does any evaluating. I should be able to see that in my console but I dont. I tried this method with the get and I did see the response 'hello'. Which is leaving me to the conclusion that you can not send data CROSS domain via $.post. The only method that seems to work is getJSON() unless someone can prove me wrong.
You cannot perform ordinary cross domain ajax requests. You need to use JSONP and this works only with GET requests (that's because jquery injects a script tag to the DOM in order to perform the request and a script tag can only use GET to fetch javascript).
If you want to be able to do requests cross-domain, you'll need to implement a HTTP proxy on your domain which would make HTTP requests on your behalf via a server side utility/library like Curl or Apache HTTPClient or something.
Edit: JSONP is a solution, but I wouldn't recommend it unless you only need to make GET requests (because that's all that works). JSONP also isn't necessarily REST-friendly, especially in your case where you need to make a POST request. If POST satisfies the semantics of your resource and how you intend to manipulate it, switching to GET just to use JSONP feels ugly to me.

Categories