REST: Securing public GET URL - rest

I have a GET url http://ip.domain/api/items to fetch data from the database and display it (pagination -- the users aren't logged in, else I'd have used a token). But the thing is, that It's public and anyone can use it. Is it possible to accept calls only from my domain? I completely understand that It's impossible to totally secure it. But just to make it a bit difficult for those who will try to.

Sure, add the following header to your script:
Access-Control-Allow-Origin: http://ip.domain
Set the domain to your actual domain.
Here's a good article on it: https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS

Related

Facebook Login: Is there a way to receive URL fragment in redirect as querystring parameter?

So when using Facebook login, it turns out that if you set response_type to token or code%20token then the "response data is included as a URL fragment" on the URL that redirects to your app. Seriously, why? When would that ever be useful to anyone?
Anyway, I'm hoping that this is somehow security related and that it's there for a reason other than to annoy people, but I would otherwise like to know if there's a way to disable it, since I'm using Angular and it's a real pain to handle urls with hashbangs.
If I set a response_type of code only, the code is returned as a nice and clean query parameter, but I would like to receive both in order to perform additional validations. Is there a way to change this behaviour? Thanks.
EDIT:
Well it turns out that setting a response_type of code returns #/= at the end of the url, so there's no way to get a clean querystring. It has already been established that there is no way to change this behaviour, but I'm still interested in finding out why Facebook is doing it. Is it security related? What is the purpose of these url fragments?
Answers
To your first question, I imagine you would use token when you are handling everything in-browser and not processing at the server.
To your main question, as far as I know, you can not change how Facebook redirects successful authorizations. Facebook doesn't give you the token as a clean query parameter. If you use token or code token, what you want will be in the hash fragment. Sorry.
NOTE: This may not be a problem for you. I'm not sure what you want with "additional validations", but when you use code token, exchanging the resulting code gets you a different token than the one you just got embedded in the URI. Both are now valid and will expire separately. Really, you probably need either the code or the token; both won't help you since they're not linked.
Examples of using all three methods:
If you set response_type to code you get redirected to something like:
http://example.com/redirect_uri?state=thestatepassed&code=AQDN9E9GYjA8NbyCt
87_jV5vHnCQylNxmBswo6Z1BsrR7lmTPom6wjrzfan6P4GBLDt3EQrfPg0xSLoMLxBBfscsyfSY
JNM2vu9OoqEQXXSJCTUq_fMpUwqkYbCHp-GAqL4H1ymbMz7zPKAG61V9BtKTSuez39yhawOu7l-
6ww4thP41Ka9PVcknTQ6fPjPXKYSyxEmANps9zevCPFsXpBZCO7_dms65-ZZuG2wVBd16gFnBZH
q8EY0qih6-9o61wXh7bBvVPVSZ2im7Oj1nx47YgDpbD3X0XdlVhUoGYmBdER9hNmIC2PmmY7VAo
PlYCZc#_-_
From there, you need to exchange the code through Facebook's OAuth endpoint to receive an access token. The access token can then be used against the Facebook APIs.
If you set response_type to token you get redirected to something like:
http://example.com/redirect_uri#access_token=CAACYnSxGEhsBAJBg0ohZBhAf7pKEU
sm5ytZAZBzKjISFuRun2ZByZCqEsxrVIgtiO7iIlJZBBbGm6fRPQXItZCX6YgjPknUBsr78tJtv
W6fySULrUo9vdW57ZCMUUIlNaeZAcU8DzUXKmFpgotOyhE3jXYz1c3eu00Aii0AZBsPrtrwjpwQ
mV8VYQNiqKZBIsqOrIwZD&expires_in=4168&state=thestatepassed
You have everything you need to call the Facebook APIs. The access token returned is valid, but should probably be checked against Facebook's token inspection endpoint if you're doing something server-side. (Really, at that point, just use code. I've never done it this way, so good luck.)
As you noted, the access token is now contained within the hash fragment of the url.
If you set response_type to code token you get redirected to something like:
http://example.com/redirect_uri#code=AQAtzsjPivFPsJ538KFlPuhLaK6pDMlrGDiwmi
KDcpgNfWrO1EdX5i6zK_Op2D0QDEXZLyifXxh4TSeBZCWhnkl7YV1LMyEkbPURAWSoqRoeG7tfM
4nB4nDAHOK0H9umb0KnoypRT1pP05FJKhl2QjpCJrPPFDHl6y-1X9ZMj1uVHtmPNi4tG_6QAbuL
RaGadBkekb22uJ0iwSrWc9OKi6ET70lCTYb18hbwUkzHXtTq12nNEdsDJ7Ku2wEBwMygFwErYDX
CrnPoFoah_z0UPCfv3XZLy98Dhlzw_lnx8nnCB-PCppOWRqmydvQJehPd86k&access_token=C
AACYnSxGEhsBALXHRQwfm4UoauRlZBJDVpZCiM6ZCuM3bE965F5JVBfBB8inTFdhfJ5obnonSqa
m3v8FbWhHXrhRSx4ugwAmmDaWyxmPELWqSrkrDO5ueTUXhhjiEZBTd7HjCVCSOXXhOSo3DjEVSC
lOaZBfqmXsprYyc6LJC39sroCcHYCZCv&expires_in=5183426&state=thestatepassed
Now you have both an access token and a code (that expiration applies to the token, not the code). As stated earlier, that code can be exchanged for an access token in the usual way, but the returned access token will be different from the one you just got embedded in the URI.
But, again, what you care about is in the hash fragment.
See the AngularJS doc on $location for accessing the hash. Someone more knowledgable than me can speak to how that works with routes and how best to scrape the parameters.
Well today I had the same situation and managed to resolve it in a way I could get the access token from my server.
After getting the code using response_type=code I called via GET the following url:
https://graph.facebook.com/v3.2/oauth/access_token?app_id=MY_APP_ID&code=MY_CODE&client_id=MY_APP_ID&client_secret=MY_APP_SECRET&redirect_uri=YOUR_LOGIN_REDIRECT_URI
This route returns a JSON response, which has the access_token parameter, in this way:
{
"access_token": "ABAECAEFAEFAEA...",
"type": "bearer",
"expires_in": 838383838
}
So there you go :) I hope this works for you too

Url's containing authentication secrets and app ID's

We received a request to create a REST api. I was a little confused in the example of provided by our client. As you can see below, they've identified the app_id and secret in the URL before the #. The remainder of the URI looks like what I would expect.
Is this valid? I thought maybe this is some weird cURL format I haven't seen before.
https://{application_id}:{api_secret}#api.example.com/entity/{entity_id}/
https://{application_id}:{api_secret}#api.example.com/entity/{entity_id}/entity_locations/{locations_id}/
Just seeing if anyone has seen this format before?
A URI is made up of various parts, one of them being the authority part, which can feature optional username:password element.
The full scheme is:
scheme://username:password#domain:port/path?query_string#fragment_id
This way your REST api remains stateless [not relying on previous app states like storing stuff in session]. But I advice you not to explicitly go with the username:password#stuff route, but to rely on Basic HTTP Auth, so the credentials are sent encoded in Base64 at least.
EDIT: a brief note about BasicAuth now you're asking - things go like this:
you make a request to http://johndoe:12345#service/api/foo/bar;
are credentials good? Ok, you get a 200 OK response with proper body;
are they not? You get a 401 Unauthorized response.
In the latter case, it's the browser [or any other program / script performing the request] that should prompt the user with the login popup.
Usually browsers ask you to cache credentials not to ask them every time, but this does not mean that they are not sent - it's just that every request to protected resources are featured with such header:
Authorization Basic base64encode(username:password)
Where base64encode is your custom way to encode the username:password string.

Place API key in Headers or URL

I'm designing a public API to my company's data. We want application developers to sign up for an API key so that we can monitor use and overuse.
Since the API is REST, my initial thought is to put this key in a custom header. This is how I've seen Google, Amazon, and Yahoo do it. My boss, on the other hand, thinks the API is easier to use if the key becomes merely a part of the URL, etc. "http://api.domain.tld/longapikey1234/resource". I guess there is something to be said for that, but it violates the principle of the URL as a simple address of what you want, and not how or why you want it.
Would you find it logical to put the key in the URL? Or would you rather not have to manually set HTTP headers if writing a simple javascript frontend to some data?
It should be put in the HTTP Authorization header. The spec is here https://www.rfc-editor.org/rfc/rfc7235
If you want an argument that might appeal to a boss: Think about what a URL is. URLs are public. People copy and paste them. They share them, they put them on advertisements. Nothing prevents someone (knowingly or not) from mailing that URL around for other people to use. If your API key is in that URL, everybody has it.
It is better to use API Key in header, not in URL.
URLs are saved in browser's history if it is tried from browser. It is very rare scenario. But problem comes when the backend server logs all URLs. It might expose the API key.
In two ways, you can use API Key in header
Basic Authorization:
Example from stripe:
curl https://api.stripe.com/v1/charges -u sk_test_BQokikJOvBiI2HlWgH4olfQ2:
curl uses the -u flag to pass basic auth credentials (adding a colon after your API key will prevent it from asking you for a password).
Custom Header
curl -H "X-API-KEY: 6fa741de1bdd1d91830ba" https://api.mydomain.com/v1/users
passing api key in parameters makes it difficult for clients to keep their APIkeys secret, they tend to leak keys on a regular basis.
A better approach is to pass it in header of request url.you can set user-key header in your code .
For testing your request Url you can use Postman app in google chrome by setting user-key header to your api-key.
I would not put the key in the url, as it does violate this loose 'standard' that is REST. However, if you did, I would place it in the 'user' portion of the url.
eg: http://me#example.com/myresource/myid
This way it can also be passed as headers with basic-auth.

how to get facebook profile image real url in https

I am wondering if there is a way to get facebook user profile image's real url in https.
Like I use https://graph.facebook.com/20926460/picture to get a the profile image,
It will redirect to http://profile.ak.fbcdn.net/hprofile-ak-snc4/41539_20926460_5421452_q.jpg.
Is there a way to get the "https" version of the second url? or is the url existing?
This might have changed in the docs since you last looked, I know everyone got excited about https after that snooping tool came out.
"If you need a picture to be returned over a secure connection, you can set the return_ssl_resources argument to 1: https://graph.facebook.com/xx_userid_xx/picture?return_ssl_resources=1."
Hopefully that won't redirect you.
Update 10 sept 2012
https://graph.facebook.com/20926460/picture now redirects to https urls.
You can just replace http by https in the target url but keep in mind that it is only temporary and may time out.
there is also no valid ssl certificate, but if you ignore that, the file will be served.
if you need a valid certified https url for pictures you need to set up a proxy script on your server that passes through the file.
edit:
as for your comment here is an example of what i meant by "proxy script".
you can put it on your server and request it with whatever protocl/scheme you like.
just like it was a local picture. you should probably validate the mime type. do some error handling and prevent injections etc. but just to give you ap icture:
<?
header("Content-Type: image/jpeg");
echo file_get_contents('https://graph.facebook.com/'.intval($_GET["id"]).'/picture');
fyi i put the int cast there to prevent injection hacking.
script is untested but should work as file_get_contents will follow redirects.

How to disallow access to an url called without parameters with robots.txt

I would like to deny web robots to access a url like this:
http://www.example.com/export
allowing this kind of url instead:
http://www.example.com/export?foo=value1
A spider bot is calling /export without query string causing a lot of errors on my log.
Is there a way to manage this filter on robots.txt?
I am assuming you have problems with bots hitting the first URL in your example.
As said in the comment, this is probably not possible, because http://www.example.com/export is the resource's base URL. Even if it were possible as per the standard, I wouldn't trust bots to understand this properly.
I would also not send a 401 Access denied or similar header if the URL is called without a query string for the same reason: A bot could think that the resource is out of bounds entirely.
What I would do in your situation is, if somebody arrives at
http://www.example.com/export
send a 301 Moved permanently redirect to the same URL and a query string with some default values, like
http://www.example.com/export?foo=0
this should keep the search engine index clean. (It won't fix the logging problem you state in your comment, though.)