-1

I have a PHP application that I want to run through XMLHttpRequests on my front end part, this works fine as it's pratically the same as "normal". This works fine.

I get really confused when I start trying to do secure cross origin requests. For instance, some requests I want to only permit if a user is logged in. But, when testing if a session is still there, it doesn't exist anymore. I just don't want random people tapping into someones profile, for instance. Or gain any sort of data I don't want random people to see.


What I want

Requests through this model shown below, but make them secure. Because some data I want for protect to logged-in users only. How do you do that? I can't wrap my mind around that.

enter image description here

Basically, I now have the issue that I can't check on the PHP end if a user has a active session, as PHP sees it as a totally new thing. Essentially, how do you do it like web broswers do it? It's probably just really stupid, but I can't wrap my mind around it.


What I've tried

I've tried requesting where one sets the $_SESSION, then requesting it where it returns $_SESSION, but it return nothing. This means I can't check if the request comes from a loggedin user.

Community
  • 1
  • 1
Sjenkie
  • 207
  • 2
  • 3
  • 14
  • Downvoter, reasoning please? I would like to improve my question, if it doesn't follow guidelines. – Sjenkie Apr 18 '17 at 18:33
  • Where is your responsibility. The webservice? This is not some kind of CORS right? – frz3993 Apr 18 '17 at 18:38
  • @frz3993 Yes, I manage all sides. I've looked at multiple things about CORS, but can't *really* grasp how to secure certain requests for *logged in* users only. – Sjenkie Apr 18 '17 at 18:40
  • The origin in CORS refers to domain not devices. When you use the term REST, it suppose to be stateless. That being said, if you want to use session your client devices must save the session cookie received from the server sent by the set-cookie header. Then they must send the session cookie in every request – frz3993 Apr 18 '17 at 18:47
  • @frz3993 Ok, my brain has started to catch on right there. Let me try that for a second, I believe that is the problem I'm having. – Sjenkie Apr 18 '17 at 18:52
  • You might want to look at how oauth2 and REST API works. How they use and exchange auth token, access token and refresh token might give you some idea. – frz3993 Apr 18 '17 at 18:57
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/142005/discussion-between-sjenkie-and-frz3993). – Sjenkie Apr 18 '17 at 19:07

2 Answers2

1

You can use JSON Web Tokens for communicating securely across devices.

JSON Web Token (JWT) is an open standard (RFC 7519) that defines a compact and self-contained way for securely transmitting information between parties as a JSON object. This information can be verified and trusted because it is digitally signed. JWTs can be signed using a secret (with the HMAC algorithm) or a public/private key pair using RSA. Source

You basically send a token with each request to sources you want to secure behind a login. Then server side you veryfy that token. Upon login you generate that token and include it in your response. In your frontend you can store the token in local storage on the client machine. For example jQuery has this plugin for local storage.

Here is a super basic example of what you need to do in PHP.

Do your login using javascript/jQuery. Send username/password to login.php for example and authenticate the user like you would normally do.

login.php

use \Firebase\JWT\JWT;

$salt = 'some_salt_string';
$algo = 'HS256'; // allowed ones

$params = array(
    "iss" => 'http://example.com', // your own identification
    "aud" => ['user_id'=>4324], // client identification
    "iat" => time(), // start validity
    "exp" => time()+(3600*24) // end validity
);

$token = JWT::encode($params, $salt, $algo);

// example data
$data = [
    'example_1'=>'value 1',
    'example_2'=>'value 2'
];
$response = array_merge($data,['token'=>$token]);

header('Content-Type: application/json');
echo json_encode($response);

auth.php

use \Firebase\JWT\JWT;

/**
 * http://stackoverflow.com/questions/40582161/how-to-properly-use-bearer-tokens
 * Get header Authorization
 * */
function getAuthorizationHeader(){
    $headers = null;
    if (isset($_SERVER['Authorization'])) {
        $headers = trim($_SERVER["Authorization"]);
    }
    else if (isset($_SERVER['HTTP_AUTHORIZATION'])) { //Nginx or fast CGI
        $headers = trim($_SERVER["HTTP_AUTHORIZATION"]);
    } elseif (function_exists('apache_request_headers')) {
        $requestHeaders = apache_request_headers();
        // Server-side fix for bug in old Android versions (a nice side-effect of this fix means we don't care about capitalization for Authorization)
        $requestHeaders = array_combine(array_map('ucwords', array_keys($requestHeaders)), array_values($requestHeaders));
        //print_r($requestHeaders);
        if (isset($requestHeaders['Authorization'])) {
            $headers = trim($requestHeaders['Authorization']);
        }
    }
    return $headers;
}
/**
 * http://stackoverflow.com/questions/40582161/how-to-properly-use-bearer-tokens
 * get access token from header
 * */
function getBearerToken() {
    $headers = $this->getAuthorizationHeader();
    // HEADER: Get the access token from the header
    if (!empty($headers)) {
        if (preg_match('/Bearer\s(\S+)/', $headers, $matches)) {
            return $matches[1];
        }
    }
    return null;
}

$token = getBearerToken();
$salt = 'some_salt_string';
$algo = 'HS256';
$decoded_token = JWT::decode($token, $salt, $algo); // returns object

// you can access the audience properties to verify the user id against a requested resource
$user_id = $decoded_token->aud->user_id;

// finally check user id and either deny or allow access

javascript

<script src="https://code.jquery.com/jquery-2.2.4.min.js" integrity="sha256-BbhdlvQf/xTY9gja0Dq3HiwQF8LaCRTXxZKRutelT44=" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-storage-api/1.9.4/jquery.storageapi.min.js"></script>
<script>

    var storage=$.localStorage;

    function login() {

        $.ajax({
            url: 'https://example.com/api/login',
            type: 'POST',
            data: {
                username:'Username',
                password:'Password'
            },
            success: function (data) {
                storage.set('auth_token',data.token); // store returned token to local storage using the jQuery plugin"value"
            },
            error: function () {
                alert('Error occured');
            },
        });

    }
    function testApi() {

        $.ajax({
            url: 'https://example.com/api/test',
            type: 'GET',
            beforeSend: function (xhr) {
                xhr.setRequestHeader('Authorization', 'bearer '+storage.get('auth_token')); // append the token. Mind the space.
            },
            data: {
                query:'value'
            },
            success: function () {

            },
            error: function () { 

            },
        });
    }
</script>

Include the auth snippet in your secure pages or better said API endpoints.

Yolo
  • 1,569
  • 1
  • 11
  • 16
  • Yes, I understand that. I essentially got stuck with the part of saving it on the server side (believe it or not), as I tried saving it in a session (in order to have it stored as long as the user is logged in). But, that didn't work out so great. @frz3993 has mentioned the problem with that. – Sjenkie Apr 18 '17 at 18:52
  • I have added an example – Yolo Apr 18 '17 at 19:41
  • Ok, yes so Oauth2 essentially? Using a library supporting that.. Thanks, this is the helpfull answer. – Sjenkie Apr 18 '17 at 23:52
0

CORS or cross origin request are to allow other domains to access your web-services. The feature you are asking is user level access or we can say which is public and which is restricted to user roles. It's not something related to CORS. Secondly session is restricted to one system. Please read this page of w3schools for better understanding of session https://www.w3schools.com/php/php_sessions.asp

You can also maintain an user level variable in your mysql or whatever db you are using on the server side to know what is the user level and then bring it to the correct session and with each request check the session value for the type of user like $_SESSION["user_type"] which you can bring from your db and then destroy the session on logout.

Sagar
  • 475
  • 2
  • 8
  • Yes, that's exactly what I tried doing, but when accesing the session variable it isn't in there anymore. – Sjenkie Apr 18 '17 at 19:03
  • Their must be some other issue , please make sure that you write session_start(); at every page you are trying to make use of session – Sagar Apr 18 '17 at 19:20
  • I have that, but when issueing another request, the session is definitly gone. I tried it, cross origin, with one request I set the session. The other request, on button press, tried retrieving the session value, but without succes. Or am I missing something here? – Sjenkie Apr 18 '17 at 19:21
  • can you please provide the demo snippets ? – Sagar Apr 18 '17 at 19:25