I'm developing a web API. authentication is through cookies. All endpoints receive parameters through JSON in the request body.
Do I need to implement a CSRF token to protect them?
How can this be exploitable? Is it possible to send JSON through a normal <form> element?
Is it possible for an attacker to have something like this?
<form type="application/json" method="POST">
<input name="json" value="{ my json code here }">
<input type="submit">Send</input>
<form>
Firstly, you have to secure your API to avoid HTML/JavaScript injections that can cause CSRF attacks on OTHER sites. To do it:
use HTTPS for all communications to avoid MITM attacks
sanitize all income data to prevent HTML/JavaScript/SQL/LDAP/Command/... injections. You can also use web application firewall or WAF that prevents different types of attacks.
Use HTTP headers:
X-XSS-Protection "1; mode=block" - this header enables the Cross-site scripting (XSS) filter built into most recent web browsers.
Content-Security-Policy - this header tells the browser that it can only communicate with the domains you explicitly allow.
In case your API provides any sensitive information than use CSRF token to avoid CSRF attacks on YOUR API. The CSRF attack to your API can be done for example by injected JavaScript to another website. In this case the injection can make correct AJAX request.
CSRF Token is a must, maybe you can add some hash based on the value and match it later, and you might be want to consider using ajax to send the value rather than put it inside an input, since JSON often have double quotes lie value="{name:""}" and that will make the HTML become invalid.
there's no attribute named type for HTML forms. The closest attribute is enctype, and you can find it's reference here. The only valid values for the attribute are:
-application/x-www-form-urlencoded, the default. All characters are encoded before sent (spaces are converted to "+" symbols, and special characters are converted to ASCII HEX values)
-multipart/form-data, No characters are encoded. This value is required when you are using forms that have a file upload control.
-text/plain Spaces are converted to "+" symbols, but no special characters are encoded.
Therefore a simple form can not submit a valid JSON payload.
Related
I have set up TLS to transfer passwords securely. Now I wonder if it is overkill to use form (POST) with enctype = "urlencoded" as also a layer of "protection"? (I know anyone can decode this). The other option is POST with enctype = "multipart" which is transparent / readable directly.
Appreciate all points of view
Encoding in this case is not a security feature (ie. it has nothing to do with security). It doesn't matter how you encode the password, the only purpose of such encoding is to be able to transmit it in a valid HTTP request, considering all the special characters it may have and so on. Security (encryption, server authentication, etc) is provided by TLS under HTTP.
I'm trying to learn Sails JS and obviously REST API.
I've created a user model wich I think works fine (it communicates datas with my db). I've also created a signup controller with 4 needed inputs to store a new record in my user collection. (Some other datas are generated by this controller to complete the record at the moment of the registration)
I would like to test this controller with POSTMAN, so I go to my routes.js and see :
'POST /api/v1/entrance/signup': { action: 'entrance/signup' },
But when i enter a POST request at 192.168.1.13:1338/api/v1/entrance/signup with my 4 needed inputs declared I have this answer : Forbidden
I don't know what I do wrong. I've also enabled rest, shortcuts and actions in my blueprints.js
Does someone has an idea ? :)
The issue is indeed related to cross-site request forgery, but disabling the corresponding security rule altogether is quite obviously not a solution. CSRF and its treatment in sailsjs are well described in the corresponding part of the manual. In short, for POSTs to work you have to include _csrf in your requests. E.g. in a view template:
<form>
<input type="hidden" name="_csrf" value="<%- _csrf %>" />
</form>
As said below, removing CSRF protection is not an answer as it may expose the api to a security breach. I currently use JWT but it doesn't seems to be as secure as CSRF token so the only right way is to include the token in every HTTP's request header.
I am building app with Play 2.0.
As far as Play form generator won't generate native http "Delete" request method, it should be replaced with either "Get" or "Post".
#form(routes.Application.delete(id), 'class -> "topRight") {
<input type="submit" value="Delete this computer" class="btn danger">
}
According to Play examples "Post" should be used for "delete" purposes. Though using "Get" is much comfortable as form can be replaced with a simple link (especially having a list of those links on a single page)
So is there any reasons to use POST for emulating DELETE?
The reason to use POST for emulating DELETE instead of GET is because some HTTP verbs (aka methods) are deemed to be safe by the HTTP specification. These methods are HEAD, GET, OPTIONS and TRACE. What this means is there should not be any side effects of application state when making requests using these HTTP methods. Logging, caching, or counter increments are not usually considered application state modification unless it is part of the application domain.
The reason to use POST for emulation of DELETE requests instead of directly using DELETE in a web form is because a number of browsers do not support DELETE directly. Many web frameworks that generate form markup with helpers, like Play and Rails, use the trick you refer to to map the request to the corresponding REST-ish action in the code. See HTTP Method Support in Browsers for more information. Please also see this SO question for more information on this topic. According to the W3C latest candidate recommendation for HTML5, the HTML5 FORM element does not support values for the method attribute other than GET or POST. The same is true for the FORM element in HTML 4.01.
For using non - GET or POST methods you should use JavaScript - for an example jQuery $.ajax() and its type setting.
You can also use Play's javascriptRoutes
Most browsers can't do HTTP requests other than GET or POST from HTML forms, so it's generally emulated using a HTTP POST with an override header or a special form variable.
See Doing a HTTP PUT from a browser
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.
I'm looking into a restful design and would like to use the HTTP methods (POST, GET, ...) and HTTP headers as much as possible. I already found out that the HTTP methods PUT and DELETE are not supported from the browser.
Now I'm looking to get different representations of the same resource and would like to do this by changing the Accept header of the request. Depending on this Accept header, the server can serve a different view on the same resource.
Problem is that I didn't find a way to tell my browser to change this header.
The <a..> tag has a type attribute, that can have a mime type, looked like a good candidate but the header was still the browser default (in Firefox it can be changed in about:config with the network.http.accept.default key).
I would partially disagree with Milan's suggestion of embedding the requested representation in the URI.
If anyhow possible, URIs should only be used for addressing resources and not for tunneling HTTP methods/verbs. Eventually, specific business action (edit, lock, etc.) could be embedded in the URI if create (POST) or update (PUT) alone do not serve the purpose:
POST http://shonzilla.com/orders/08/165;edit
In the case of requesting a particular representation in URI you would need to disrupt your URI design eventually making it uglier, mixing two distinct REST concepts in the same place (i.e. URI) and making it harder to generically process requests on the server-side. What Milan is suggesting and many are doing the same, incl. Flickr, is exactly this.
Instead, a more RESTful approach would be using a separate place to encode preferred representation by using Accept HTTP header which is used for content negotiation where client tells to the server which content types it can handle/process and server tries to fulfill client's request. This approach is a part of HTTP 1.1 standard, software compliant and supported by web browsers as well.
Compare this:
GET /orders/08/165.xml HTTP/1.1
or
GET /orders/08/165&format=xml HTTP/1.1
to this:
GET /orders/08/165 HTTP/1.1
Accept: application/xml
From a web browser you can request any content type by using setRequestHeader method of XMLHttpRequest object. For example:
function getOrder(year, yearlyOrderId, contentType) {
var client = new XMLHttpRequest();
client.open("GET", "/order/" + year + "/" + yearlyOrderId);
client.setRequestHeader("Accept", contentType);
client.send(orderDetails);
}
To sum it up: the address, i.e. the URI of a resource should be independent of its representation and XMLHttpRequest.setRequestHeader method allows you to request any representation using the Accept HTTP header.
Cheers!
Shonzilla
I was looking to do exactly the same thing (RESTful web service), and I stumbled upon this firefox addon, which lets you modify the accept headers (actually, any request headers) for requests. It works perfectly.
https://addons.mozilla.org/en-US/firefox/addon/967/
I don't think it's possible to do it in the way you are trying to do it.
Indication of the accepted data format is usually done through adding the extension to the resource name. So, if you have resource like
/resources/resource
and GET /resources/resource returns its HTML representation, to indicate that you want its XML representation instead, you can use following pattern:
/resources/resource.xml
You have to do the accepted content type determination magic on the server side, then.
Or use Javascript as James suggests.
ModHeader extension for Google Chrome, is also a good option. You can just set the Headers you want and just enter the URL in the browser, it will automatically take the headers from the extension when you hit the url. Only thing is, it will send headers for each and every URL you will hit so you have to disable or delete it after use.
Use some javascript!
xmlhttp=new XMLHttpRequest();
xmlhttp.open('PUT',http://www.mydomain.org/documents/standards/browsers/supportlist)
xmlhttp.send("page content goes here");