symfony4 get header in api key authentificator - php

i want to pass the API token obtained in the login controller as an HTTP header to allow the ApiKeyAuthentificator to read it using $apiKey = $request->headers->get('apikey');.
I used to make it work using query parameters but this seems unsafe.
In the login controller
I set an apikey http header before returning the reponse:
$response = $this->redirectToRoute('home');
$response->headers->set('apikey', $data->token);
return $response;
In the home controller
After successful redirection to home, if I var_dump the headers, the header is not set and request->headers->get('apikey') returns null.
However, after redirection, if I open the network inspector and look for the POST request from the login controller, the header is set.
But the header is not set in the GET request of the home, which I guess is why I cannot get it in the home controller using $apiKey = $request->headers->get('apikey');
In the ApiKeyAuthentificator
Same issue. Cannot access the HTTP header using $apiKey = $request->headers->get('apikey');
If I set a cookie, I manage to get it in the home controller and the authentificator, why can't I with a header ?
How to correctly set and access an HTTP header using symfony requests / responses, and make it accessible from the authentificator ?

You've misunderstood the purpose of HTTP request/response headers here. Headers themselves are not designed in this raw form, as you are doing, to indicate any kind of session or persistence. HTTP itself is very stateless, with no request being related to any other that comes along.
Your application can, and is, giving a header in its response but there is literally no reason at all why a web browser should include that same header again in future requests for the purpose of linking requests. Only a custom HTTP client/implementation, such as a bespoke native mobile/tablet app, would ever deliberately include an API key/token in HTTP headers directly. (No standard web browser would so this without some beefy Javascript implementation to handle literally all navigation.)
Cookies are exactly what you need here. Typically you don't need to worry about them too, because PHP has session variables of which you can store as much as you like, with a single cookie being used to associate future requests with a set of session variables. (Session identifier cookie, typically named "PHPSESSID".)
The login controller should be storing anything related to the user's authenticated session in PHP's session variables once it has verified the user is genuine. Once that has been done a cookie will be passed to the client web browser with no further action required from you.
--
This explanation is just conceptual though. Symfony being a very complete framework has taken care of this concept for you. The comment // or if you want to use an "apikey" header, then do something like this: is mainly for a custom web client (apps). If your goal is having a custom client side HTTP/web client then it's your job to remember token variables elsewhere in the app's memory, which would not be in a HTTP module as standard.
I think what you may need from the article I linked is specifically the part about storing authentication in the session. The HTTP client will then only need to provide an API key once.
--
As for safety, a HTTP header is no safer than a query variable to anyone smart enough to know how a HTTP request is structured. (This is basic knowledge of HTTP.) This is on par with post variables being no safer than query variables.
If you're using a standard web browser the only benefit is not seeing the API key in the address bar, but then you should be using a session cookie for these clients anyway rather than an API key in every subsequent request.
If you're creating a custom web client for an app then the custom header would be visible to someone snooping in on the HTTP traffic anyway just as easily as a query variable.
Enforcing HTTPS is the only way you could effectively hide a custom HTTP header or query variable from traffic sniffers, offering exactly the same protection to each part of the request, and subsequent response.

Related

How can PHP see client side cookies?

How can PHP see client side cookies?
To elaborate:
When working with PHP & Javascript, I understand that PHP gets processed on the server side. While Javascript happens on the client side.
In Javascript I can check and set these client cookies. That makes sense.
However, with PHP, if I check a client cookie value as part of a conditional statement that also sets , how is PHP able to see the clients cookie value while the PHP is happening on the server side?
Here's an example of the PHP conditional that lives in a php file:
<?PHP
if ($_COOKIE["name"] == “Mickey”) {
setcookie(“fulsome”, “Mickey Mouse”, time()+3600);
}
?>
There is no such thing as a client side cookie.
A cookie is a piece of data associated with a set of URLs in a browser. Every time the browser makes an HTTP request to one of those URLs, the cookie is included in the Request headers.
They were originally designed to be set via HTTP Response headers.
An API was added to browsers that allows them to be created and set by JavaScript. These are still regular cookies though and will be included in every request to the associated URLs.
It is possible to mark a cookie as http_only which will cause browsers to prevent access to that cookie from JavaScript. There is no direct equivalent for imposing a similar limit going the other way. The closest you could come to that would be to use something like Local Storage instead of cookies.
how is PHP able to see the clients cookie value while the PHP is
happening on the server side?
The reason is that each request to server also bring cookies in headers like i have inspected in chorome network tab, my php website and got this:
Cookies are store on client side but are accessible on server side through request header. As #Quentin stated in his answer "Every time the browser makes an HTTP request to one of those URLs, the cookie is included in the Request headers."
(Based on the comments, I wanted to leave a full answer as I understand it).
HTTP headers include existing cookies for the domain/site.
When PHP checks a cookie, the cookie & it's value got there via the HTTP Header that was sent in the call to the php file.
When PHP sets a cookie, it will be sent with the HTTP Header going back to the client, where it will then be set up on the client.
For a full list of what is sent in the Header, and the response back Header, see this:
http://en.wikipedia.org/wiki/List_of_HTTP_header_fields
You'll see Cookie in the Header Field List, and Set-Cookie in the list of response fields.

User authentication on different domains

I have a PHP API on example.com that authenticates users based on Sessions.
I am working on a mobile app for that, but whenever the user does a POST Ajax request to the API, it responds with set-cookie headers.
Obviously cookies cannot be sent on the mobile application because they're coming from a different domain.
How can I make the authentication process work on mobile?
Rule #1 of RESTful APIs: HTTP is stateless - keep it that way.
If you want a neat fix to your dilemma, consider implementing something to get the session ID out of a GET, POST parameter or out of a header (I usually do it using the Authorization header, personally). This then allows you to not have to rely on cookies unless you have to.
A hackish fix to your problem would be to set the cookie domain to *.example.com, which would map every domain, or to force the cookie to be added using jQuery (if you use it)'s beforeSend callback (which allows you to modify the headers of the request). Short of modifying your API's log-in method, these are your only options.

Secure AJAX request to URI

I know there have been lots of question about AJAX security. I've searched and read but am still unclear as to what the best approach is.
I have a very specific senario:
I have an application that is build on top a PHP MVC framework. I've turned presentation elements such as a "navigation menu" modular. The navigation menu module has a controller (sever side). The controller uses a model to retrieving data from the database and then it responds with a php echo of the data. I can make the http request to the controller using AJAX because the controller is routed to by a URI. I believe this is call a RESTful API. When the user clicks a link in the navigation menu a static content area is update with the data that was retrieved from the AJAX request. Lets say that I Make a different action in the same controller that is capable of writing data to the database. Having a publicly available URI that allows writing to the database is obviously bad. How does one secure the URI interface so that AJAX can retrieve and write data, but those individuals with malicious intent can do harm?
You must treat an ajax request as you treat a get request or post request.
In other words never trust the user. You have server side control, ajax is client side so never trust "CLIENT SIDE" that makes a request(check the data, if data is ok then return a response if not return another response).
Controller is able to write to database:
There is no true way to secure an public URI interface so that it is only able to be accessed by the part of your application that exists on the client side. The idea is then to not make the interface so public, meaning it cannot be accessed by everyone! If a URI were to point to a “controller” (MVC architecture) and in turn the controller has access to manipulate a critical database, you best make it so the client who sends the request to the controller must “Authenticate”. This concept is true whether the http requests are coming from a web form or Ajax. Typically before Authentication credentials are transmitted using https (http + SSL) to keep a “Man In The Middle” from seeing the credentials.
Controller is able to read from the database:
When a read request is made you can simply return the data, or if its sensitive data require an authenticated client.
The “Navigation menu module” should only be edited by an administrator, so authentication is a must. However, any web surfer who views a page containing the module should not have to authenticate to use the navigation, that would be silly.
The main rule is to validate all inputs - check all data coming in and clear from unwanted chars.
Also, it all depends if You allow user change Your DB without loging in or not. Logged users are easier to verify and You always can put on serwer - side checking scripts - if current user is allowed to do this operation.
Things are harder when You allow annonymous user to write to Your DB. Then, its good to operate mainly on ID`s and if You allow user to insert data from inputs - filter all from unwanted things. The good way of doing it is to create whitelists of chars You approve and cut everything else.
You have to remember, that Ajax is nothing else but sending POST request to url - and You should do the same protection as with standard forms. Also good practice is to add a token to Your send data - wich You can verify by server side.

Using HTTP Authentication

I am building a REST API in PHP to work with a JavaScript based app. All requests are handled as JSON and some requests require authentication.
An example request would be:
$.ajax({
type: 'GET',
url: 'http://domain.com/api/posts/recent.json',
headers: {
Authorization: 'X-TRUEREST ' + $.param({
username: 'johndoe',
password: '********'
})
},
success: function(response){
// Handle response here (includes auth errors too)
},
error: function(a,b,c) {
}
});
I have based the use of HTTP Authentication headers on the code in this plugin: https://github.com/kvz/cakephp-rest-plugin/blob/master/Controller/Component/RestComponent.php#L532
As you can see they take passed parameters with the header and then they are used to log a user into the system if they are not already. From what I can tell they expect the auth credentials to be passed WITH the request for data.
An example of this is (note not using CakePHP in my example app):
if ( $loggedIn ) { // logged in is true of false based on session existing
// Then return the JSON as normal
} else {
// Grab HEADERS INFO
$headers = $_SERVER['HTTP_AUTHORIZATION'];
$parts = explode(' ', $_SERVER['HTTP_AUTHORIZATION']);
// Then use the parts to find a user in the DB... and populate $user
if($user){
$this->Auth->login($user); // login the user with our authentication code
// Then return JSON as normal
} else {
print json_encode(array('auth'=>false))
}
}
A few questions that I have though:
Question 1: Why use the HTTP Authentication and headers? As as far as I can tell, they are not offering me anything unless I am using them incorrectly? Why not just pass the username and password in the data param of the JS?
Question 2: As stated earlier I have based my API design on the Cake plugin above, but from what I can see they ALWAYS pass the username and password with every request and then decide to use it or not if the user is logged in. Is this correct? To me, it seems more likely that authentication and requests for data should be handled separately. Otherwise I would have to store the username and password in my JavaScript somewhere so that I can send it with each request.
Which brings me to the next question...
Question 3: How do I know if a user is logged in? I could set a variable to true and then pass that as part of my JSON with every request, but can a session work with an external device?
If you are designing a REST api, you should adhere to REST principles. There are two important ones to highlight for authentication:
Identification of resources through URIs
State transitions through server-supplied links.
To adhere to principle 1, you need to keep your authentication out of your URI. http://example.org/list-of-stuff?auth-token=12345 is not a different resource from http://example.org/list-of-stuff?auth-token=67890, so it should not have a different URI. Having different URIs also makes it impossible to cache the resource across different users.
In general, if the resource would be different depending on some condition, that condition needs to be in the URI. For example, many websites have a /profile url, but what profile you see depends on the invisible "who is logged in" state. This is not RESTful. Instead the url should contain the user, e.g. /profiles/username. Whether you actually get to see that resource depends on whether you are authorized to see it, which depends on whether you are authenticated as a user that is authorized. Authentication is a separate layer from resource identification. (For example, suppose you have an admin user which can see other people's profiles. If you have just a /profile url, how would you architect a method for him to see other profiles? Clearly the presence of a resource is something different from the ability to see it and from who is looking at it.)
So we have established that authentication should not be via parameters in the URI. Since we are using HTTP, we can either provide it in a header, or provide it outside HTTP itself.
Although it's not very common, some REST apis handle authentication at the SSL layer using client certificates. This is great from a technical standpoint, but the user experience is baffling and terrible. Although this article is from 2008, nothing has improved. This approach is also not easily scriptable from browser JS, and even outside the browser it's cumbersome to write an application that has to provide client certificates. Development on the server side is difficult, too, because most web scripting environments do not give you easy access to SSL-layer stuff at all, let alone more esoteric SSL features like client-certificates. Your application may not be able to know what certificate identity was provided with the request.
So that leaves HTTP in the header. We can either use a traditional cookie-based auth, where we "log in" at a special url and get a token back, or HTTP authentication which is natively supported by HTTP.
HTTP authentication is far superior in terms of RESTful principles because it is stateless. (This makes your third question nonsensical--there is no "logged in" or "logged out" state--you either provided the right credentials for the request or you didn't!) You don't need to ensure you first visited a special url and got a magic token you need to save (which might suddenly expire), you just issue a request with your credentials every time. If you are not authorized to access a resource, there's a specific HTTP response code (401) and header (WWW-Authenticate, Authorization) and set of well-defined behaviors. It's also extensible with different authorization methods. There's a fair amount of javascript support too, at least if you stick to XmlHTTPRequest. (Heck, jQuery 1.7.2 even has username and password options, so you don't even need to base64-encode it yourself!)
The downside is that the only HTTP auth methods that are in common use and well supported are Basic and Digest, and both of them are not very secure. They're probably fine if you only use https, but otherwise they are terrible.
Also HTTP auth is useless for normal browser use by humans: no custom login pages, no way to present "forgot password" functionality or other authentication customizations, and still browser makers have provided no easy way to "log out" (i.e., forget the credentials for the current realm)!
Cookie-based auth provides you the most control, but you need to keep server- and client-side authentication state and worry about a whole host of other security issues, such as session fixation or even what constitutes a session! Is it IP address, user agent, some combination? How long should an authenticated session be valid before we expire it? What if there's a proxy involved and the IP address changes frequently? What should we do when the magic token expires? What should we do when the user is not authorized? (You can't use an HTTP 401 response--you need to define your own method specific to your site.) In essence, you need to define your own complex session and authentication protocol or adopt someone else's. At least with HTTP auth, the only thing you need to worry about is an attacker reading your Authenticate headers, and using SSL solves that problem.
Question 1: Why use the HTTP Authentication and headers? As as far as I can tell, they are not offering me anything unless I am using them incorrectly? Why not just pass the username and password in the data param of the JS?
HTTP Authentication here appears to be a personal choice of the developer. You could use OpenID. You could use a token. You could use HTTP Header Authentication. You could use sessions/cookies. Heck, you could even use RSA Key Authentication or SSL Client Certificates if you liked.
Question 2: As stated earlier I have based my API design on the Cake plugin above, but from what I can see they ALWAYS pass the username and password with every request and then decide to use it or not if the user is logged in. Is this correct? To me, it seems more likely that authentication and requests for data should be handled separately. Otherwise I would have to store the username and password in my JavaScript somewhere so that I can send it with each request.
You shouldn't expose the username and password of anything in plaintext, ever (technically you shouldn't even store it as such, but that's not what the question is about). Use a public token with an API, or a unique cookie ID. Personally, I use $_SESSION["id"] to see if a user is logged into anything. Let the AJAX submit and then map the ID to a token internally, if you have to.
Question 3: How do I know if a user is logged in? I could set a variable to true and then pass that as part of my JSON with every request, but can a session work with an external device?
I have a function I use for this linked in this answer. You should ideally check for a valid login using a session and setting the value of an index (such as $_SESSION["id"]) to a value that is unique to that account (usually, this is their database ID).
Edit: after reading the comments on the OP, you would have to make sure the session cookie was on any device that was logged in before making the request
Do not take a value: true field to be a login, as this is a security vulnerability.
I think you are mixing (perhaps on purpose) between passing information to the REST api using the URI and authorizing access to the specific server with http simple Authentication.
HTTP authentication can also be used to handle users, but It wouldn't be a very good choice (as elobrated in other answers). users, sessions, security tokens etc should be handled by the app logic while api access can also be safe guarded by the server (with http simple or digest security, NTLM, IP filtering or whatever). letting the web server take some of the security burden/seperating concerns/some kind of testing site/etc'.
an example scenerio is handling http security to protected server access in a Testing zone server, while the app REST api would accept and handle different users, tokens, permission levels etc to everyone who passed the server security checks.
look for this question for more reference
Question 1: Why use the HTTP Authentication and headers? As as far as
I can tell, they are not offering me anything unless I am using them
incorrectly? Why not just pass the username and password in the data
param of the JS?
The query string is part of the URI. The URI is a resource identifier by REST, so it is part of the resource state. The identity, credentials, etc... of the user is part of the client state. Mixing the client state and the resource state by adding client state to the URI would be a violation of the stateless constraint of REST. The data part of other requests, like POST, PUT, DELETE is for describing resource representations, so you should not send auth data with it. Sending headers is the best approach and since HTTP has a dedicated Authorization header, you should use that.
Question 2: As stated earlier I have based my API design on the Cake
plugin above, but from what I can see they ALWAYS pass the username
and password with every request and then decide to use it or not if
the user is logged in. Is this correct? To me, it seems more likely
that authentication and requests for data should be handled
separately. Otherwise I would have to store the username and password
in my JavaScript somewhere so that I can send it with each request.
Your server should authenticate every request, in order to stay stateless. I am not sure about the logic of this lib, I think login is the wrong term to describe what happens, but from REST perspective the implementation details does not matter as long as it uses the HTTP standard properly, and the communication is stateless. The code has changed since you asked your question.
Question 3: How do I know if a user is logged in? I could set a
variable to true and then pass that as part of my JSON with every
request, but can a session work with an external device?
The server does not care whether the client is logged in, since it is client state. If you send a request that requires permissions, then you have to send the data necessary to authenticate the user.

Return HTML or XML based on request in PHP

There's an existing website written in PHP. Originally only the website existed, but now an Android application is being built that would benefit from re-using some of the PHP logic.
The PHP site was structured such that there are many pages that perform an action, set success/error information in $_SESSION, and then redirect to a visual page without outputting any content themselves. For example, there's action_login.php:
The page accepts a username and password (from GET or POST variables), validates the credentials, sets success/failure messages in $_SESSION, and then redirects to the logged-in homepage on success or back to the login screen on failure. Let's call this behavior the "HTML response".
The Android application will need to call the same page but somehow tell it that it wants an "XML response" instead. When the page detects this, it will output success/error message in an XML format instead of putting them in $_SESSION and won't redirect. That's the idea anyway. This helps prevent duplicate code. I don't want to have action_login.php and action_login.xml.php floating around.
I've read that the Accept Header isn't reliable enough to use (see: Unacceptable Browser HTTP Accept Headers (Yes, You Safari and Internet Explorer)). My fallback solution is to POST xml=1 or use {url}?xml=1 for GET requests. Is there a better way?
No frameworks are being used, this is plain PHP.
That's what the Accept Header is for. Have the Android request the page as application/xml and then check what was requested in your script. You might also be interested in mod_negotiation when using Apache. Or use WURFL to detect the UserAgent and serve as XML when Android.
I'd go with the android app sending a cookie for every request (really I would prefer the Accept header, but with the problems you pointed out with webkit I understand your reluctance to do so). The cookie simplifies the code server-side to not have to check for $_GET['xml'] or $_POST['xml'], and if some android user shares an URL of your application and it had a ?xml=1, the user who opens this in a computer browser would receive XML instead of the normal web output.
I wouldn't rely on $_SESSION for mobile applications because users (or at least I do) on mobile platforms tend to open your app, play 5 minutes, put mobile on pocket and 2 hours later return to your app. Do you want to set a session lifetime so long?
why not set a specific session for the app and then only set the header if the session is set something along the lines of
$_SESSION['app'] = "andriod app";
if ($_SESSION['app'] == "andriod app") {
header..
not really sure how to implement this into an app as I've done really little work with apps but hope this helps your thought process

Categories