I'm constructing an application with 2 sides: client (iPhone) and Server (PHP). Communication using https. The mobile phone gets a 4SQ access token. Then, it sends that token to the server, and the server will make 4SQ API calls using it. My question is about how to send this token.
My idea was to include the token in the HTTP Authentication request's header, but after reading about basic/digest authentication, I suspect it isn't the way of doing it. Actually, the calls to 4SQ API are done using a request parameter
oauth_token=ACCESS_TOKEN
instead of putting the token in Authentication header, or any other place. I'm sure there's a good reason for that, but I can't find it.
Then, which option is the best?
Phone sends token to PHP server as request parameter, like 4SQ does
Phone sends token to PHP server in Authentication header (which kind oh authentication is?)
Any other way
Many thanks in advance, and best regards
I think the most secure and reasonable way would be a HTTPS POST. When the token is part of the query string in a HTTPS request, it is also encrypted. But it will appear clear text in the server log, or, when a browser is used, it could also appear in the browser history. Depending on the HTTP helper library, it could also log the HTTPS URL, when, for example, a request fails.
In my eyes, sending the token in the Authentication header would be strange, since it is not used for authentication between the server and the client.
Related
I wrote some API. It requires an API token.
I only access this API through backend.
Should I receive the API token through headers only, or is it ok to receive it from query string parameters?
Are there differences security-wise?
Edit: forgot to mention, of course I use SSL
All the Authorization is in Headers only headers are more secure
In query parameter these are expose for the public
for eg. if you send in Like a query it will be public to all
Don't do this Ever
curl -X GET http://localhost:5051/v1/user/verifytoken?token=bearer-xdrRxfdfdfdf
You may need a refresher on the differences between cookies and tokens to assist you in finding your answer.
The purpose of cookies is to bring state to what is inherently a stateless protocol which is http, the http protocol has no concept of state and it's only by introducing these cookies or tiny bits of data on requests that identify us to the server.
Cookies are included on all http requests by default, they manifest themselves as a property on the header of any request. A server can choose to place information on a users cookie that identifies them uniquely to that particular server.
So if they were logging into a website I were making I could stick some information into that cookie that says this is user13794 and on any follow up request they would have a cookie 13794 that says this is the same user coming back, it's another request from the same person.
Cookies are automatically included on all requests and very importantly, are unique to each domain, such as Google.com versus eBay.com. A cookie you have that is tied to google.com is not and cannot be shared by default with ebay.com, that is how we get some level of security on all of our requests. So if I logged on to google.com and then went to hacker.com, the hacker.com website could not lift my cookie from Google and hijack my session.
SO cookies cannot be sent to different domains, that is something that exists for security purposes so you cannot easily hijack peoples sessions.
Opposed to cookies are the ideas of tokens, this was introduced as a convention, to use tokens in place of cookies where cookies stop being useful.
There is nothing done automatically for us with tokens, we have to manually include a header with our token which might be a string of letters and numbers and we might include it on a specific header so we have to manually wire up our tokens at all times.
The benefits of tokens is that we can send them to any domain that we wish, so if I am on google.com and I want to make an authenticated request to an entirely different domain, I can do so by using a token.
I would make my request to that other domain, include my particular token and boom! I am authenticated on that other domain.
So that's my long winded way of saying, like with cookies, tokens are manually wired up through headers only, not query parameters.
I have a Lambda function which triggered by API Gateway service, however this API is accessed by front-end application, this application not requiring the users to login or sign up to use it.
However I would like to secure my API to allow only from my front-end application.
After my research I found that I can use custom authorization in API Gateway, this custom authorization will check the authorization header of the incoming request and validate it.
the question is, can I use Amazon Cognito for something like this(implicit grant type)?
if not what is the thing that the front-end application will send to me to be validated and how can I keep it always changeable, so no one can guess it?
Thank You.
You could check the headers, but if they're always the same, someone can send an HTTP request with those headers - from any client - and trick your Lambda into thinking it's coming from your UI.
Even if you generate a unique token every time your UI is loaded and include it in the headers, someone could take that token and send requests from another client as well.
You could build fancy JavaScript tricks to make headers more dynamic, but it would only make it harder to use your API from another client, not impossible.
I'm having some trouble deciding how to implement authentication for a RESTful API that will be secure for consumption by both a web app and a mobile app.
Firstly, I thought to investigate HTTP Basic Authentication over HTTPS as an option. It would work well for a mobile app, where the username and password could be stored in the OS keychain securely and couldn't be intercepted in transit since the request would be over HTTPS. It's also elegant for the API since it'll be completely stateless. The problem with this is for the web app. There won't be access to such a keychain for storing the username and password, so I would need to use a cookie or localStorage, but then I'm storing the user's private details in a readily accessible place.
After more research, I found a lot of talk about HMAC authentication. The problem I see with this approach is there needs to be a shared secret that only the client and server knows. How can I get this per-user secret to a particular user in the web app, unless I have an api/login endpoint which takes username/password and gives the secret back to store in a cookie? to use in future requests. This is introducing state to the API however.
To throw another spanner into the works, I'd like to be able to restrict the API to certain applications (or, to be able to block certain apps from using the API). I can't see how this would be possible with the web app being completely public.
I don't really want to implement OAuth. It's probably overkill for my needs.
I feel as though I might not be understanding HMAC fully, so I'd welcome an explanation and how I could implement it securely with a web app and a mobile app.
Update
I ended up using HTTP Basic Auth, however instead of providing the actual username and password every request, an endpoint was implemented to exchange the username and password for an access key which is then provided for every authenticated request. Eliminates the problem of storing the username and password in the browser, but of course you could still fish out the token if you had access to the machine and use it. In hindsight, I would probably have looked at OAuth further, but it's pretty complicated for beginners.
You should use OAuth2. Here is how:
1) Mobile App
The mobile app store client credentials as you state yourself. It then uses "Resource Owner Password Credentials Grant" (see https://www.rfc-editor.org/rfc/rfc6749#section-4.3) to send those credentials. In turn it gets a (bearer) token it can use in the following requests.
2) Web site
The website uses "Authorization Code Grant" (see https://www.rfc-editor.org/rfc/rfc6749#section-4.1):
Website sees unauthorized request and redirects browser to HTML-enabled autorization endpoint in the REST api.
User authenticates with REST service
REST site redirects user back to website with access token in URL.
Website calls REST site and swaps access token to authorization token.
Here after the website uses the authorization token for accessing the REST service (on behalf of the end-user) - usually by including the token as a "bearer" token in the HTTP Authorization header.
It is not rocket science but it does take some time to understand completely.
3) Restricting API access for certain applications
In OAuth2 each client is issued a client ID and client secret (here "client" is your mobile app or website). The client must send these credentials when authorizing. Your REST service can use this to validate the calling client
I resolved this for my own API quite easily and securely without the need to expose any client credentials.
I also split the problem into 2 parts. API authentication - is this a valid request from a recognised entity (website or native app). API authorisation, is that entity allowed to use this particular endpoint and HTTP verb.
Authorisation is coded into the API using an access control list and user permissions and settings that are set up within the API code, configuration and database as required. A simple if statement in the API can test for authorisation and return the appropriate response (not authorised or the results of processing the API call).
Authentication is now just about checking to see if the call is genuine. To do this I issue self signed certificates to clients. A call to the API is made from their server whenever they want - typically when they generate their first page (or when they are performing their own app login checks). This call uses the certificates I have previously provided. If on my side I am happy the certificate is valid I can return a nonce and a time limited generated API key. This key is used in all subsequent calls to other API endpoints, in the bearer header for example, and it can be stored quite openly in an HTML form field or javascript variable or a variable within an app.
The nonce will prevent replay attacks and the API key can be stolen if someone wants - they will not be able to continue using after it expires or if the nonce changes before they make the next call.
Each API response will contain the next nonce of if the nonce doesn't match it will return an authentication error. In fact of the nonce doesn't match I kill the API key too. This will then force a genuine API user to reauthenticate using the certificates.
As long as the end user keeps those certificates safe and doesn't expose the method they use to make the initial authentication call (like making it an ajax request that can be replayed) then the API's are nice and secure.
One way of addressing the issue of user authentication to the API is by requesting an authentication token from the API when the user logs in. This token can then be used for subsequent requests. You've already touched on this approach - it's pretty sound.
With respect to restricting certain web apps. You'll want to have each web app identify itself with each request and have this authentication carried out inside your API implementation. Pretty straight forward.
I'm building an Angular app with an API backend. On a combination of pieces of advice, I built the API with a flavor of token authentication. The flow is roughly as follows:
POST to login endpoint with credentials
Validate credentials and authorization, then generate a new token
Return token to client
Client uses token via HTTP Basic to access API resources
This is all working well. The problem arises in creating a session based on this token. I don't believe I should simply hold the token on the client in a cookie, but I do need a session to persist between page refreshes, etc. My Angular app is stateless and completely populated via API calls.
I'm looking for a recommendation as to hanging on to this token on the client. I feel there's danger in holding the token in a cookie because the cookie could be stolen and simply used to authenticate as someone else, but perhaps this is incorrect.
Thanks in advance for your assistance!
The only known way for me to identify a user is to use some token on the client.
HTTP is stateless and can't know which request is coming from which user (browser). You can't identify the user by his ip address (many users are behind a router and share a connection). You could try browser fingerprinting, it can work on some browsers but not on all.
I would recommend using a cookie to store this token on the client.
They are send to the server on every request and you can do some protection to keep them from getting stolen.
To protect this cookie from man in the middle attacks you need to use an encrypted connection over HTTPS to the server.
Set the following attributes on the cookie:
HTTPOnly: cookie can't be accessed by javascript (XSS protection)
Secure: cookie will only be send over https
Path: cookie will only be send on specified path e.g. /login
I would also define an expiration date on the cookie, so the cookie is invalid in like 2 days or something.
But you are right. If this token gets stolen someone else can login as this user.
Since its an Angular app, I'd assume all authenticated methods will only be served to ajax requests (you can tell your server to only respond to ajax) in which case CORS will help you.
The only way to be completely secure is HTTPS, however this method is probably more secure than you think. Read up on CORS a bit for more info, but essentially the idea is that servers will only respond to ajax requests coming from html pages that were served by that same domain.
Pre-flight OPTIONS requests are often sent to verify this. The browser sends an OPTIONS request with an Origin header (the origin of the page) before the actual request. If the origin matches the domain of the server receiving it, the subsequent request is allowed. Otherwise, it violates the Same Origin Policy and will be rejected.
This prevents someone from sniffing out the token and sending a request with the token from a page that your server didn't serve (like something running on the hackers local machine).
If you are doing credit card transactions or anything super secure, you should use HTTPS though.
http://en.wikipedia.org/wiki/Cross-origin_resource_sharing
The OAuth 2.0 draft v2-22 Section 3.2 says:
The client MUST use the HTTP "POST" method when making access token
requests.
However, if you look at the Facebook and Foursquare OAuth2 implementations, they ask the clients to make a simple GET request for requesting an access token. They ask the clients to place the client_id and client_secret in the URL.
I am building an OAuth 2 server and after seeing Facebook's and Foursquare's implementations, I am strongly considering also breaking the protocol to allow clients to request the access token via GET. My site's communication is using SSL, similar to Facebook and Foursquare.
So my question is this: Are there any good reasons why I shouldn't allow clients to request access tokens via the GET method over HTTPS?
The most common argument is that you should not put sensitive information in a query string (GET parameter) as Web servers typically log the HTTP request URL. POST data can be arbitrarily long, so is not usually logged. Therefore when you're dealing with something like client_secret or code (although it's one time use), it makes sense to have that passed in the POST payload.
IMHO, if you're using an OAuth 2.0 flow that doesn't require client_secret's (or you put that in the HTTP Authorization header, as recommended) - I don't see an issue with allowing GET.