How to secure REST GET method? - rest

HTTP GET method will transfer data over the url as in https://www.example.com/users?id=1. If I use HTTPS the connection will be secure but the sensitive data in the link could still be logged on the server uppon processing the link requested by the client, exposing secrets to be acquired by some hacker later.
OWASP recommends not storing anything on the links, as it can be logged on the web server.
But REST uses GET to retrieve data, as a "Read" would in a CRUD operation.
So the question is, How can I make a secure GET call on REST?
EDIT: One example: OWASP says to NOT include an API Key on the URL address, but since all data sent on a GET request is placed on the URL, how would I send the API Key to the server in other to authorize the GET response from that user, since I can't place it on the URL itself?
OWASP doesn't explain how to achieve this.

EDIT: One example: OWASP says to NOT include an API Key on the URL address, but since all data sent on a GET request is placed on the URL, how would I send the API Key to the server in other to authorize the GET response from that user, since I can't place it on the URL itself?
You're wrong that all data must be specified in the URL. There's a lot of stuff that actually goes into HTTP headers! Instead of an API key in a url, you should use an Authorization header.

Related

Login and Register Requests in API's

I'm currently working on a small project where I need to create login and register functionalities for a web application. A colleague of mine had the opinion, that a login request should be done with a post request where the user credentials are stored in the body of the request. I was used to do login requests with a Get-Request where the login credentials are stored in the authentication header (e.g. with Basic-Authentication). So I've read some threads and most of them say, that a POST-Request is better than a GET-Request for login. But also some threads said, that it is better to store user credentials in a request header instead of the body. In case the credentials are stored in the header I don't understand why a GET-Request should be better than a POST-Request.
So I was wondering what you think. What are the benefits/disadvantages of Login with POST-Request and User Credentials stored in the Request-Body compared to storing them in the header via Base-Authentication (encrypted with Base64).
Thanks for any opinions.
A POST is preferable for login request, because the authentication information will be sent in the HTTP messages body rather than the URL. Although it will still be sent plain text, unless you're encrypting via HTTPS.
GET method data is sent to the server followed by the URL which will be seen to everyone.
Both GET and POST method are used to transfer data from client to server in HTTP protocol but main difference between POST and GET method is that GET carries request parameter appended in URL string, while POST carries request parameter in message body which makes it more secure way of transferring data from client to server in HTTP protocol.

Can a HTTP GET request on REST web service be safe?

I'm currently working on a new REST Web Service, developed in Django REST Framework, and while defining URLs I had a doubt about it's security. Following the standards that defined GET method for list data from a database, I doesn't understand if this can be a safe method to bring data.
Imagine this situation:
I access an URL /patients defined to return a list of patients. This list is not public and can only be requested by authorized users. Since not all users can see all patients, I create an hash code that works as key, allowing to list patients for that specific user. If no hash code provide, the method returns an 403 forbiden.
It work something like this: /patients/HASHCODE
Since my hash code is request in the URL and not inside of the body of HTTP message, like it would be if done by POST method, this looks unsafe me. I know that SSL can hide some information of requests, but not about a GET request. And of course this hash should not be visible for no one.
Can I say this is a safe method to access my API? If not, how should I implement this?
First of all, you must use HTTPS, as it ensures that both body and headers will be encrypted. Pick a certificate issued by a certification authority and stay away from self-signed certificates.
If what you call hash means an access token, then it belongs to the Authorization header with the Bearer authentication scheme (refer to this answer for details). Alternatively, you may want to use a cookie with both HttpOnly and Secure flags set.
I also advise you to look into some sort of authorization mechanism for your application: according to the user roles or authorities, retrieve the data they can access or refuse the request. It's very likely your web framework already provides you some sort for authorization mechanism. Let me also highlight that you should't write your own security-related stuff (unless you really know what your are doing).
Any sort of sensitive information (such as credentials, access tokens, you name it) must never ever be sent in the URL: The requested URL may be logged by servers and proxies; If the URL is requested by a browser, the URL goes to the browser history. You surely want to avoid that.
GET is meant for data retrieval while POST is kinda a catch all verb, that is, the representation sent in the payload will be processed according to the resource's own specific semantics). If you need to send sensitive information to the server, I would advise you to use POST, sending any sensitive data in payload which will be encrypted over HTTPS.

REST api - How should the client supply userid to the request URL for its user resource?

A client needs to login with a username/password the first time. A JWT token is returned for future requests. The token will have a userid so that the server can fetch the user's resource from the database.
The problem I have is the client needs to form the request URL to update its resource let's say POST /users/{userid}. How should I get the userid for the client? I can't access the JWT token which is stored in a httpOnly secure cookie. Should I store the userid on the client somehow? So that it can use it for the URL?
I see your problem now. You are afraid of losing some of the advantages of a RESTFUL api, a unique resource locator,
I often have a set of URIs that start with the path that indicates that operations are on the currently authenticated user.
/current/profile
/current/blog_posts
In such cases I pull the user out of the request context on the server, which I can get by parsing the JWT token.
And when I want to operate on other users I use the identifier instead
/{{user_id}}/profile
/{{user_id}}/blog_posts
I'm not sure whether this is strictly RESTFUL, but it does give users of my API a stable and discoverable URI. I've used this pattern with a number of projects and teams without complaint.
If you really must get a user identifier two ideas idea comes to mind:
Return the user_id along with the jwt token.
Make an extra API call
to get the user_id from the server and then use that for all
subsequent calls.
Oh, another option comes to mind. Change your notion of a user_id and use the username (which you already have) instead.

How to verify email and name on a server using FB access token received by javascript SDK on a client side

I have a client (HTML+JavaScript) and a server (ASP MVC) and I need to provide a user some private information. To achieve that I need to verify that
user authenticated and
use users email address to retrieve its
private information.
I want to use FB authentication. It looks pretty straight forward but has a flaw which I am sure people can tell me how to solve or what am I missing.
client initializes FB SDK and requests user to authenticate using FB
result of successful step #1 is access token.
We can place another call to FB using this access token to retrieve
email and name.
How can my server know what is the email and name of the authenticated user?
My understanding that client should not send email and name to the server (it can be hacked and can not be trusted) but instead client should send the received access token, which server should use to get user's email and name, but on the server side.
Please explain, give me an example, point me to a link on how can I achieve that on the server as all my searches for that failed.
One more time, my backend is ASP MVC.
On the server, make a call to the Graph API:
https://graph.facebook.com/me?fields=name,email
Use the Access Token and you will get the correct data:
https://graph.facebook.com/me?fields=name,email&access_token=xxx
Btw, you should also read this: https://developers.facebook.com/docs/graph-api/securing-requests
I guess I was confused with what I need to do in ASP MVC in order to get a user info having an access token.
The suggested link: https://developers.facebook.com/docs/graph-api/using-graph-api helped me to understand that all I really need is to make a HTTPS GET call (from the server) to "graph.facebook.com" passing access cookie (received from the client) to retrieve the information I need and exclude a possibility of hijacked/compromised client passing me a wrong email.
Using GRAPH API means placing https calls to GRAPH.facebook.com - that was no clear to me.

How to design a RESTful API to check for user's credentials?

I'm designing an API for a mobile app, and I hope to keep it RESTful.
API's are authorized using Basic HTTP Auth, however, When the user open the app for the first time, he need to login first, so I need to design an API to check for user's credentials, which will accept a pair of username and password, return success or fail accordingly.
the problem is what the url should be so it is restful? I don't think /login is a good one.
It's typically viewed as poor practice to pass sensitive data via an HTTP GET request.
Password information is sensitive data and is one of the exceptions that breaks the rule that idempotent operations should be GET requests.
Why is this an exception? Browser History and Server Logs will store GET requests. Meaning that this sensitive information is visible as plain text in both places. So if someone gets a hold of either - then that information is now in their hands.
You should use an HTTP POST request to pass this sensitive information to the RESTful API as browsers will not store them and servers will not log them. However, the first line of defense is to use Secure HTTP (HTTPS) to ensure that this information is protected from outsiders.
So pass this information in the body of an HTTP request to an HTTPS URL.
A good approach is to perform a GET request for the account/profile info of the current user. and have it return the username, settings, avatar url, etc. me is a frequently used as a shorthand identifier of the authenticating user.
GET https://api.example.com/profiles/me
HTTP/1.1 200 OK
{
"username": "bob",
"id": "xyz",
"created_at": 123,
"image_url": "https://example.com/bob.png"
}
From wikipedia:
The client–server communication is further constrained by no client
context being stored on the server between requests. Each request from
any client contains all of the information necessary to service the
request, and any session state is held in the client.
Because the server stores no session state from the client, your API shouldn't expose any login/logout capability: In each request you should send user credentials, and the server should validate them each time.
Check this discussion in SO, it claryfies this concept.
I agree with Carlos - in a normal restful API, there is no session so you can't authenticate once and then reuse the session, you would actually need to pass the credential set on every call (not ideal).
In this scenario it sounds like you would be better of using one of the openAuth (http://www.oAuth.net) - this works by authenticating when the app is first run and then generating an access token to allow access within every call (+a refresh token).
(you could argue that the access token is state - which it kind of is - however, at least it's generally significantly longer lived).
GET https://api.example.com/auth
With Authorization header set.