how can i create a sort-of last response middleware on a Laravel application that checks if the response does not contain any userland-generated data like, for example, authentication data?
I've seen that a standard Cookie contains the following keys:
_token
_csrf
_previous
_redirect
_flash
PHPDEBUGBAR_STACK_DATA -- This is injected by barryvdh/laravel-debugbar
Why would I need this? Because I need Varnish to reply from cache, if the request is stateless. In other words, Users that just want to navigate the (20000+) static pages of the website.
My goal is to have a final middleware that physically forces the response stack to not send any set-cookie header, if there is no need of setting it (not-authed user).
Related
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.
I use Event Listener from this SO answer to redirect users with specific roles. But now, for one role I have to redirect user to external link, with some POST data.
Since in onKernelResponse() I have to set $event response and RedirectResponse can't do forward with POST (at least that's what I've been told), I'm a bit lost here. How should I do it?
In HTTP 1.1 you have 307 status code which says request should be repeated. So you can create Http Requestwith this code.
301/302 won't work for POST. The other way is to use CURL but it's different because you use other client then.
10.3.8 307 Temporary Redirect
The requested resource resides temporarily under a different URI. Since the redirection MAY be altered on occasion, the client SHOULD continue to use the Request-URI for future requests. This response is only cacheable if indicated by a Cache-Control or Expires header field.
The temporary URI SHOULD be given by the Location field in the response. Unless the request method was HEAD, the entity of the response SHOULD contain a short hypertext note with a hyperlink to the new URI(s) , since many pre-HTTP/1.1 user agents do not understand the 307 status. Therefore, the note SHOULD contain the information necessary for a user to repeat the original request on the new URI.
If the 307 status code is received in response to a request other than GET or HEAD, the user agent MUST NOT automatically redirect the request unless it can be confirmed by the user, since this might change the conditions under which the request was issued.
https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html
The code:
$response = new RedirectResponse($this->router->generate('your route'), Symfony\Component\HttpFoundation\Response::HTTP_TEMPORARY_REDIRECT);
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.
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.
Ok, It looks like I made a mistake with my initial question. So, here are some corrections. The answer still applies, because the second redirect is stopped when there is a change in protocol to HTTPS (SSL).
In my case, I have a redirect occurring multiple times, and the browser doesn't follow the second redirect. The first redirect is followed but returns an error.
I keep reading that JavaScript AJAX responses containing redirects are followed automatically, but it look like not in my case. The first redirect is automatically followed by the browser, and the first redirect is returned without following the second redirect in the header. My problem is that I want all the redirects to be automatically followed by the browser.
The redirects are part of the phpCAS library. I have an API written in PHP which checks the user authentication, each time, before returning the results.
Here is the sequence. The main thing to note is that the browser returns the second response, after following 1 redirect. I would prefer it went all the way and returned the last response when I make an AJAX call to localhost/example/api.
localhost/example
Calls localhost/example/api using jQuery.ajax()
Response 1: localhost/example/api
Redirects to https://localhost/accounts/cas/login?service=api.example.com&gateway=true (using SSL).
Response 2: (SSL) localhost/accounts/cas/login?service=api.example.com&gateway=true
When the query key 'gateway' is present, the login simply redirects back to the URL provided by the 'service' key with or without a ticket (to signal to service that the user is either logged in or not).
Response 3: localhost/api?ticket=TICKET
Verifies the ticket and redirects back to itself without the ticket.
Response 4: localhost/api
This time the CAS client looks at the $_SESSION to remember what the ticket was, and then processes the API request returning JSONP.
There's no particular reason I'm using CAS over OpenID or OpenAuth(orization). CAS was just the first authentication module I was able to get working in WordPress. I am open to suggestions in terms of using a different authentication library, CMS, framework, etc. Although, my hope is to just get this project finished. So the less re-tooling the better.
As you later found yourself as you added in your comments, ajax requests are subject to same origin policy.
Yes, you could use JSONP - however, if you are fortunate enough to have to support only IE8 and upwards, CORS might be a better solution.
Basically, adding headers such as
access-control-allow-origin: http://api.example.com
access-control-allow-credentials: true
to your server answer, you could work around cross origin policy.
Also see this jQuery ticket to make it kinda work with jQuery.