REST API GET with sensitive data - rest

I'm designing api with method that should be an idempotent, and should not modify any data on the server. It should be method that process request and return response for given parameters.
One of the parameters is sensitive data. It's not an option to use additional encryption. Data is already encrypted, but security requirements are very demanding and even encrypted data should be treated very carefully.
According to REST spec, idempotent query method should be implemented as a GET HTTP method. Problem in this case is sensitive data that shouldn't be pass as a GET parameter in URL. Only option in HTTP standard is to pass sensitive data in a body part of HTTP request.
My question is what is better? Broke rest api design, and send query request as a POST, or pass encrypted data in URL? Maybe is there better solution I don't see?

According to REST spec, idempotent query method should be implemented
as a GET HTTP method.
2016
As far as I can tell with my limited English SHOULD != MUST. You won't break REST API design by sending a POST in this case. You can send your sensitive data in a HTTP header if that is possible. And ofc. you should use HTTPS if you want to send sensitive data to anywhere.
2019
I checked the HTTP 1.1 standard meanwhile. They don't explicitly use the MUST or SHOULD words in the specs for idempotency, but I got the impression they mean SHOULD. Another HTTP related thing here, that we use GET mostly because we can cache response with it. You don't necessarily want to cache sensitive data, so it might not make sense to insist on using GET on retrieval when security is more important by the parameters. You can find some tips about how to set cache-control headers here, but you can read the HTTP standard for that too.
From security perspective my non-expert opinion is the following:
Normally query parameters are not that sensitive, usually they are just random ids or keywords. So maybe the problem is with your design and you should hide these sensitive parameters (e.g. social security number) behind random ids instead of querying them explicitly. Another thought here, that user credentials must be in the Authorization header for example, not in the query string, so if the sensitive data is that kind, then you are doing it wrong.
As far as I understand the issue about sending sensitive data in URLs is that it can show up in browser history, cache, address bar and in server logs unencrypted. Even though many people call REST webservices directly from browser via AJAX (or the fetch API), that is not the intended way they should be used. Webservices are mostly for server side usage to scale out your application to multiple threads, cores or servers. So if you use a server side HTTP client which does not have history or cache to call the REST webservice programmatically, then all you need to do is encrypting your logs. If the client has cache, then you can encrypt that too if you feel it necessary. I think it is possible to filter these params from logs and store the cached content based on the salted hash of the URL, but I don't have much experience with that.
If you have a 3rd party client or a browser where you don't have that kind of control, then you can still assume that it follows the HTTP standard. So you can use the cache-control headers to disable cache for sensitive content. The address bar and history is not a problem by single page applications unless they move the sensitive data to there with the history API, but that can happen no matter what you do. It is possible to disable the Referrer header too. Only if you serve HTML with your webservice will you have a problem with browsers, because that assumes that javascript is disabled (so you cannot use location.replace to override browser history along with the sensitive querystring) and that the browser is your REST client. I think that is a very unlikely scenario, though it is possible to do it relative well with XML+XSL reusing most of the code or nowadays maybe with nodejs or some sort of transpiler on different languages.
So I think this can be solved even without POST if you do everything right. But this is just an opinion, I wait for security expert to correct me...

Related

Which REST HTTP verb to use for "Q&A" scenario?

An auth system I work on has this new function:
1. Auth system allows users to specify Relying Parties they transact with,
2. The Relying Party can approve/deny/maybe the request (authorisation) - maybe causes a redirect to the RP website for further authorisation questions by the RP.
The RP has to implement a web service specified by the Auth System to perform the approve/deny/maybe request that the auth system generates.
My problem is what this looks like as a REST service. As the auth system can't really dictate the URI style for the RP system, i would like to specifying that the path does not have any parameters in it, auth system just needs to know the URI of the service. The data of the request (user name/id) might be in a bit of json in the request body (suggesting POST http verb. GET might be OK, but loath to expose user ids in the URI). The auth system does not care what the RP does with the request data, the auth system just wants a "yes/no/maybe" reply (so may not really be a GET/POST/PATCH/DELETE/etc paradigm).
What would be the best verb to use? and how to facilitate the reply; its not really a success/failure response as there are 3 possible results to the query, is it acceptable to have some json returned with the response (then what http verb to use)?
I'm a bit baffled by this. GET seems the most obvious
GET /api/user_link_authorize/{userid}
except then i'm forced to put user ids in the URI (which I dont want to do)...
Any suggestions?
My problem is what this looks like as a REST service.
Think about how it would look as a web site.
You would start with some known URI in your list of bookmarks. Fetching that page would give you a representation of a form, which would have input controls that describe what data needs to be provided (and possibly includes default values). The client provides the data it knows about, and submits the form. The data in the form is used to create a HTTP request as described by HTML's form processing rules. The response to that request includes a representation of the answer, or possibly the next bit of work to be done.
That's REST.
Retrieving the form (via the bookmarked URI) would be a GET of course; we're just updating our locally cached copy of the forms "current" representation. Submitting the form could be a GET or a POST; we don't necessarily need to know that in advance, because that information is carried in the representation of the form itself.
GET vs POST involves a number of trade offs. Semantically, GET is safe, it implies that the resource can be fetched at any time, that spiders can crawl it, that accessing the resource in that way is "free". Which is great when the resource is free, because clients on an unreliable network can automatically retry the request if the response is lost. On the other hand, announcing to the world that the request is safe when it is actually expensive to produce responses is not a winning play.
Furthermore, GET doesn't support a message body (more precisely, the payload has no defined semantics). That means that information provided by the client needs to be part of the target resource identifier itself. If you are dealing with sensitive information, that can be problematic -- not necessarily in transit (you can use a secured socket), but certainly in making sure that the URI with sensitive information is not logged where the sensitive data can leak.
POST supports including a payload with the request, but it doesn't promise that the query is safe, which means that generic components won't know if they can automatically retry the request when a response is lost.
Given that you don't want the user id in the URI, that's a point against GET, and therefore in favor of POST.

Sending passwords over HTTPS: GET vs POST

I'm creating a headless API that's going to drive an Angular front end. I'm having a bit of trouble figuring out how I should handle user authentication though.
Obviously the API should run over SSL, but the question that's coming up is how should I send the request that contains the user's password: over GET or POST. It's a RESTFUL API, so what I'm doing is retrieving information meaning it should get a GET request. But sending the password over get means it's part of the URI, right? I know even a GET request is encrypted over HTTPS, but is that still the correct way? Or is this a case to break from RESTFUL and have the data in the body or something (can a GET request have data in the body?).
If you pass the credentials in a request header, you will be fine with either a GET or POST request. You have the option of using the established Authorization header with your choice of authentication scheme, or you can create custom headers that are specific to your API.
When using header fields as a means of communicating credentials, you do not need to fear the credentials being written to the access log as headers are not included in that log. Using header fields also conforms to REST standards, and should actually be utilized to communicate any meta-data relevant to the resource request/response. Such meta-data can include, but is not limited to, information like: collection size, pagination details, or locations of related resources.
In summary, always use header fields as a means of authentication/authorization.
mostly GET request will bind data in URL itself... so it is more redable than POST..
so if it is GET, there is a possibility to alive HISTORY LOG
Using ?user=myUsername&pass=MyPasswort is exactly like using a GET based form and, while the Referer issue can be contained, the problems regarding logs and history remain.
Sending any kind of sensitive data over GET is dangerous, even if it is HTTPS. These data might end up in log files at the server and will be included in the Referer header in links to or includes from other sides. They will also be saved in the history of the browser so an attacker might try to guess and verify the original contents of the link with an attack against the history.
You could send a data body with a get request too but this isn't supported by all libraries I guess.
Better to use POST or request headers. Look at other APIs and how they are handling it.
But you could still use GET with basic authentication like here: http://restcookbook.com/Basics/loggingin/

GET vs POST in REST Web Service

I'm in the process of developing a REST service that allows a user to claim their listing based on a couple of pieces of information that appear on their invoice (invoice number and billing zip).
I've read countless articles and Stack Overflow questions about when to use GET and when to use POST. Overall, the common consensus is that GET should be used for idempotent operations and POST should be used for operations that create something on the server side. However, this article:
http://blog.teamtreehouse.com/the-definitive-guide-to-get-vs-post
has caused me to question using GET for this particular scenario, simply because of the fact that I'm using these 2 pieces of information as a mechanism to validate the identity of the user. I'm not updating anything on the server using this particular method call, but I also don't necessarily want to expose the information in the URL.
This is an internal web service and only the front-end that calls the service is publicly exposed, so I don't have to worry about the URL showing up in a user's browser history. My only concern would be the unlikely event that someone gain server log access, in which case, I'd have bigger problems.
I'm leaning toward POST for security reasons; however, GET feels like the correct method due to the fact that the request is idempotent. What is the recommended method in this case?
Independently of POST vs GET, I would recommend NOT basing your security as something as simple as a zip code and an invoice number. I would bet on the fact that invoice numbers are sequential (or close), and there aren't that many zip codes around - voila, I got full access to your listings.
If you're using another authentication method (typically in HTTP header), then you're good - it doesn't matter if you have an invoice number if the URL, so might as well use GET.
If you're not, then I guess POST isn't as bad as GET in term of exposing confidential content.
There isn't really any added security in a POST vs a GET. Sure, the request isn't in the URL, but it's REST we are talking about here, and the URL wouldn't be seen by a human anyway.
You question starts with some bad presumptions. Firstly, GET is not just for any old idempotent operation, it is for GETting resources from the server; it just happens that doing so should be side effect free. Secondly, the URL is not the only way for a GET request to send data to the server, you can use a payload with a GET request (at least as far as HTTP is concerned, some implementations are bad and don't support this or make it hard). Third, as pointed out, you have chosen some terrible data fields to secure your access. Finally, you are using a plain text protocol any way, so what neither method really offers and better security.
You should use the the verb that best describes what you are doing, you are getting some information from the server, so use GET. Use some proper security, such as basic HTTPS encryption. If you want to avoid these fields 'clogging' up the URL, you can send data in the payload of the request, something like:
GET /listings HTTP/1.1
Content-Type = application/json
{ "zip" : "IN0N0USZ1PC0D35",
"invoice" : "54859081145" }

ASP.NET Web API Authentication Options

What options are available for authentication of an MVC3 Web API application that is to be consumed by a JQuery app from another domain?
Here are the constraints/things I've tried so far:-
I don't want to use OAuth; for private apps with limited user bases I cannot expect end users to have their accounts on an existing provider and there is no scope to implement my own
I've had a fully functioning HMAC-SHA256 implemention working just fine using data passed in headers; but this doesn't work in IE because CORS in IE8/9 is broken and doesn't allow you to send headers
I require cross-domain as the consuming app is on a different domain to the API, but can't use jsonp becuase it doesn't allow you to use headers
I'd like to avoid a token (only) based approach, as this is open to replay and violates REST by being stateful
At this point I'm resigned to a HMAC-SHA256 approach that uses either the URL or querystring/post to supply the hash and other variables.
Putting these variables in the URL just seems dirty, and putting them in the querystring/post is a pain.
I was succesfully using the JQuery $.ajaxSetup beforeSend option to generate the hash and attach it to the headers, but as I mentioned you can't use headers with IE8/9.
Now I've had to resort to $.ajaxPrefilter because I can't change the ajax data in beforeSend, and can't just extend data in $.ajaxSetup because I need to dynamically calculate values for the hash based on the type of ajax query.
$.ajaxPrefilter is also an issue because there is no clean/simple way to add the required variables in such a way that is method agnostic... i.e. it has to be querystring for GET and formdata for POST
I must be missing something because I just cannot find a solution that:-
a) supports cross-domain
a) not a massive hack on both the MVC and JQuery sides
c) actually secure
d) works with IE8/9
There has to be someone out there doing this properly...
EDIT
To clarify, the authentication mechanism on the API side is fine... no matter which way I validate the request I generate a GenericPrincipal and use that in the API (the merits of this are for another post, but it does allow me to use the standard authorization mechanisms in MVC, which I prefer to rolling my own... less for other developers on my API to learn and maintain)
The problem lies primarly in the transfer of authentication information from the client to the API:-
- It can't rely on server/API state. So I can't pass username/password in one call, get a token back and then keep using that token (open to replay attack)
- Anything that requires use of request headers is out, because IE uses XDR instead of XHR like the rest of the browsers, and it doesn't support custom headers (I know IE10 supports XHR, but realistically I need IE8+ support)
- I think I'm stuck generating a HMAC and passing it in the URL somewhere (path or querystring) but this seems like a hack because I'm using parts of the request not designed for this
- If I use the path there is a lot of messy parsing because at a minimum I have to pass a username, timestamp and hash with each request; these need to be delimited somehow and I have little control over delimiters being used in the rest of the url
- If I use data (querystring/formdata) I need to change the place I'm sending my authentication details depending on the method I'm using (formdata for POST/PUT/etc and querystring for GET), and I'm also polution the application layer data space with these vars
As bad as it is, the querystring/formdata seems the best option; however now I have to work out how to capture these on each request. I can use a MessageHandler or Filter, but neither provide a convienient way to access the formdata.
I know I could just write all the parsing and handling stuff myself (and it looks like I will) but the point is I can't believe that there isn't a solution to this already. It's like I have (1) support for IE, (2) secure and (3) clean code, and I can only pick two.
Your requirements seem a little bit unjustified to me. You can't ever have everything at the same time, you have to be willing to give something up. A couple of remarks:
OAuth seems to be what you want here, at least with some modifications. You can use Azure's Access Control Service so that you don't have to implement your own token provider. That way, you have "outsourced" the implementation of a secure token provider. Last I checked Azure ACS was still free. There is a lot of clutter when you look for ACS documentation because people mostly use it to plug into another provider like Facebook or Google, but you can tweak it to just be a token provider for your own services.
You seem to worry a lot about replay attacks. Replay attacks almost always are a possibility. I have to just listen to the data passing the wire and send it to your server, even over SSL. Replay attacks are something you need to deal with regardless. Typically what I do is to track a cache of coming requests and add the hash signature to my cache. If I see another request with the same hash within 5 minutes, I ignore it. For this to work, I add the timestamp (millisecond granularity) of the request and some derivative of the URL as my hash parameters. This allows one operation per millisecond to the same address from the same client without the request being marked as replay attack.
You mentioned jQuery which puzzles me a bit if you are using the hashing method. That would mean you actually have your hash algorithm and your signature logic on the client. That's a serious flaw because by just inspecting javascript, I can now know exactly how to sign a request and send it to your server.
Simply said; there is not much special in ASP.NET WebAPI when it comes to authentication.
What I can say is that if you are hosting it inside ASP.NET you'll get support by ASP.NET for the authentication and authorization. In case you have chosen for self-hosting, you will have the option to enable WCF Binding Security options.
When you host your WebAPI in ASP.NET, you will have several authentication options:
Basic Authentication
Forms Authentication - e.g. from any ASP.Net project you can enable Authentication_JSON_AppService.axd in order to the forms authentication
Windows Authentication - HttpClient/WebHttpRequest/WebClient
Or explicitly allow anonymous access to a method of your WebAPI

When should I use GET or POST method? What's the difference between them?

What's the difference when using GET or POST method? Which one is more secure? What are (dis)advantages of each of them?
(similar question)
It's not a matter of security. The HTTP protocol defines GET-type requests as being idempotent, while POSTs may have side effects. In plain English, that means that GET is used for viewing something, without changing it, while POST is used for changing something. For example, a search page should use GET, while a form that changes your password should use POST.
Also, note that PHP confuses the concepts a bit. A POST request gets input from the query string and through the request body. A GET request just gets input from the query string. So a POST request is a superset of a GET request; you can use $_GET in a POST request, and it may even make sense to have parameters with the same name in $_POST and $_GET that mean different things.
For example, let's say you have a form for editing an article. The article-id may be in the query string (and, so, available through $_GET['id']), but let's say that you want to change the article-id. The new id may then be present in the request body ($_POST['id']). OK, perhaps that's not the best example, but I hope it illustrates the difference between the two.
When the user enters information in a form and clicks Submit , there are two ways the information can be sent from the browser to the server: in the URL, or within the body of the HTTP request.
The GET method, which was used in the example earlier, appends name/value pairs to the URL. Unfortunately, the length of a URL is limited, so this method only works if there are only a few parameters. The URL could be truncated if the form uses a large number of parameters, or if the parameters contain large amounts of data. Also, parameters passed on the URL are visible in the address field of the browser not the best place for a password to be displayed.
The alternative to the GET method is the POST method. This method packages the name/value pairs inside the body of the HTTP request, which makes for a cleaner URL and imposes no size limitations on the forms output. It is also more secure.
The best answer was the first one.
You are using:
GET when you want to retrieve data (GET DATA).
POST when you want to send data (POST DATA).
There are two common "security" implications to using GET. Since data appears in the URL string its possible someone looking over your shoulder at Address Bar/URL may be able to view something they should not be privy to such as a session cookie that could potentially be used to hijack your session. Keep in mind everyone has camera phones.
The other security implication of GET has to do with GET variables being logged to most web servers access log as part of the requesting URL. Depending on the situation, regulatory climate and general sensitivity of the data this can potentially raise concerns.
Some clients/firewalls/IDS systems may frown upon GET requests containing an excessive amount of data and may therefore provide unreliable results.
POST supports advanced functionality such as support for multi-part binary input used for file uploads to web servers.
POST requires a content-length header which may increase the complexity of an application specific client implementation as the size of data submitted must be known in advance preventing a client request from being formed in an exclusively single-pass incremental mode. Perhaps a minor issue for those choosing to abuse HTTP by using it as an RPC (Remote Procedure Call) transport.
Others have already done a good job in covering the semantic differences and the "when" part of this question.
I use GET when I'm retrieving information from a URL and POST when I'm sending information to a URL.
You should use POST if there is a lot of data, or sort-of sensitive information (really sensitive stuff needs a secure connection as well).
Use GET if you want people to be able to bookmark your page, because all the data is included with the bookmark.
Just be careful of people hitting REFRESH with the GET method, because the data will be sent again every time without warning the user (POST sometimes warns the user about resending data).
This W3C document explains the use of HTTP GET and POST.
I think it is an authoritative source.
The summary is (section 1.3 of the document):
Use GET if the interaction is more like a question (i.e., it is a safe operation such as a query, read operation, or lookup).
Use POST if:
The interaction is more like an order, or
The interaction changes the state of the resource in a way that the
user would perceive (e.g., a subscription to a service), or
The user be held accountable for the results of the interaction.
Get and Post methods have nothing to do with the server technology you are using, it works the same in php, asp.net or ruby. GET and POST are part of HTTP protocol.
As mark noted, POST is more secure. POST forms are also not cached by the browser.
POST is also used to transfer large quantities of data.
The reason for using POST when making changes to data:
A web accelerator like Google Web Accelerator will click all (GET) links on a page and cache them. This is very bad if the links make changes to things.
A browser caches GET requests so even if the user clicks the link it may not send a request to the server to execute the change.
To protect your site/application against CSRF you must use POST. To completely secure your app you must then also generate a unique identifier on the server and send that along in the request.
Also, don't put sensitive information in the query string (only option with GET) because it shows up in the address bar, bookmarks and server logs.
Hopefully this explains why people say POST is 'secure'. If you are transmitting sensitive data you must use SSL.
GET and POST are HTTP methods which can achieve similar goals
GET is basically for just getting (retrieving) data, A GET should not have a body, so aside from cookies, the only place to pass info is in the URL and URLs are limited in length , GET is less secure compared to POST because data sent is part of the URL
Never use GET when sending passwords, credit card or other sensitive information!, Data is visible to everyone in the URL, Can be cached data .
GET is harmless when we are reloading or calling back button, it will be book marked, parameters remain in browser history, only ASCII characters allowed.
POST may involve anything, like storing or updating data, or ordering a product, or sending e-mail. POST method has a body.
POST method is secured for passing sensitive and confidential information to server it will not visible in query parameters in URL and parameters are not saved in browser history. There are no restrictions on data length. When we are reloading the browser should alert the user that the data are about to be re-submitted. POST method cannot be bookmarked
All or perhaps most of the answers in this question and in other questions on SO relating to GET and POST are misguided. They are technically correct and they explain the standards correctly, but in practice it's completely different. Let me explain:
GET is considered to be idempotent, but it doesn't have to be. You can pass parameters in a GET to a server script that makes permanent changes to data. Conversely, POST is considered not idempotent, but you can POST to a script that makes no changes to the server. So this is a false dichotomy and irrelevant in practice.
Further, it is a mistake to say that GET cannot harm anything if reloaded - of course it can if the script it calls and the parameters it passes are making a permanent change (like deleting data for example). And so can POST!
Now, we know that POST is (by far) more secure because it doesn't expose the parameters being passed, and it is not cached. Plus you can pass more data with POST and it also gives you a clean, non-confusing URL. And it does everything that GET can do. So it is simply better. At least in production.
So in practice, when should you use GET vs. POST? I use GET during development so I can see and tweak the parameters I am passing. I use it to quickly try different values (to test conditions for example) or even different parameters. I can do that without having to build a form and having to modify it if I need a different set of parameters. I simply edit the URL in my browser as needed.
Once development is done, or at least stable, I switch everything to POST.
If you can think of any technical reason that this is incorrect, I would be very happy to learn.
GET method is use to send the less sensitive data whereas POST method is use to send the sensitive data.
Using the POST method you can send large amount of data compared to GET method.
Data sent by GET method is visible in browser header bar whereas data send by POST method is invisible.
Use GET method if you want to retrieve the resources from URL. You could always see the last page if you hit the back button of your browser, and it could be bookmarked, so it is not as secure as POST method.
Use POST method if you want to 'submit' something to the URL. For example you want to create a google account and you may need to fill in all the detailed information, then you hit 'submit' button (POST method is called here), once you submit successfully, and try to hit back button of your browser, you will get error or a new blank form, instead of last page with filled form.
I find this list pretty helpful
GET
GET requests can be cached
GET requests remain in the browser history
GET requests can be bookmarked
GET requests should (almost) never be used when dealing with sensitive data
GET requests have length restrictions
GET requests should be used only to retrieve data
POST
POST requests are not cached
POST requests do not remain in the browser history
POST requests cannot be bookmarked
POST requests have no restrictions on data length
The GET method:
It is used only for sending 256 character date
When using this method, the information can be seen on the browser
It is the default method used by forms
It is not so secured.
The POST method:
It is used for sending unlimited data.
With this method, the information cannot be seen on the browser
You can explicitly mention the POST method
It is more secured than the GET method
It provides more advanced features