I'm building a RESTful web service which has multiple URIs for one of its resources, because there is more than one unique identifier. Should the server respond to a GET request for an alternate URI by returning the resource, or should I send an HTTP 3xx redirect to the canonical URI? Is HTTP 303 (see also) the most appropriate redirect?
Clarification: the HTTP specification makes it clear that the choice of redirect depends on which URI future requests should use. In my application, the 'canonical' URI is the most stable of the alternatives; an alternative URI will always direct to same canonical URI, or become invalid.
I'd personally plump for returning the resource rather than faffing with a redirect, although I suspect that's only because my subcoscious is telling me redirects are slower.
However, if you were to decide to use a redirect I'd think a 302 or 307 might be more appropiate than a 303, although the w3.org has details of the different redirect codes you could use.
Under W3C's Architexture of the World Wide Web, Volume One, there is a section on URI aliases (Section 2.3.1) which states the following:
"When a URI alias does become common currency, the URI owner should use protocol techniques such as server-side redirects to relate the two resources. The community benefits when the URI owner supports redirection of an aliased URI to the corresponding "official" URI. For more information on redirection, see section 10.3, Redirection, in RFC2616. See also CHIPS for a discussion of some best practices for server administrators."
For what it's worth, I would recommend a 302 redirect.
The answer from Ubiguchi had what I needed, except that I now think a redirect is the way to go, via the link to the HTTP 1.1 specifiction section on response codes. It turns out that I actually need a 301 redirect because the URI I'm redirecting to is more 'correct' and stable, and should therefore be used for future requests.
Related
I made a POST request to a HTTP (non-HTTPS) site, inspected the request in Chrome's Developer Tools, and found that it added its own header before sending it to the server:
Upgrade-Insecure-Requests: 1
After doing a search on Upgrade-Insecure-Requests, I can only find information about the server sending this header:
Content-Security-Policy: upgrade-insecure-requests
This seems related, but still very different since in my case, the CLIENT is sending the header in the Request, whereas all the information I've found is concerning the SERVER sending the related header in a Response.
So why is Chrome (44.0.2403.130 m) adding Upgrade-Insecure-Requests to my request and what does it do?
Update 2016-08-24:
This header has since been added as a W3C Candidate Recommendation and is now officially recognized.
For those who just came across this question and are confused, the excellent answer by Simon East explains it well.
The Upgrade-Insecure-Requests: 1 header used to be HTTPS: 1 in the previous W3C Working Draft and was renamed quietly by Chrome before the change became officially accepted.
(This question was asked during this transition when there were no official documentation on this header and Chrome was the only browser that sent this header.)
Short answer: it's closely related to the Content-Security-Policy: upgrade-insecure-requests response header, indicating that the browser supports it (and in fact prefers it).
It took me 30mins of Googling, but I finally found it buried in the W3 spec.
The confusion comes because the header in the spec was HTTPS: 1, and this is how Chromium implemented it, but after this broke lots of websites that were poorly coded (particularly WordPress and WooCommerce) the Chromium team apologized:
"I apologize for the breakage; I apparently underestimated the impact based on the feedback during dev and beta."
— Mike West, in Chrome Issue 501842
Their fix was to rename it to Upgrade-Insecure-Requests: 1, and the spec has since been updated to match.
Anyway, here is the explanation from the W3 spec (as it appeared at the time)...
The HTTPS HTTP request header field sends a signal to the server expressing the client’s preference for an encrypted and authenticated response, and that it can successfully handle the upgrade-insecure-requests directive in order to make that preference as seamless as possible to provide.
...
When a server encounters this preference in an HTTP request’s headers, it SHOULD redirect the user to a potentially secure representation of the resource being requested.
When a server encounters this preference in an HTTPS request’s headers, it SHOULD include a Strict-Transport-Security header in the response if the request’s host is HSTS-safe or conditionally HSTS-safe [RFC6797].
This explains the whole thing:
The HTTP Content-Security-Policy (CSP) upgrade-insecure-requests
directive instructs user agents to treat all of a site's insecure URLs
(those served over HTTP) as though they have been replaced with secure
URLs (those served over HTTPS). This directive is intended for web
sites with large numbers of insecure legacy URLs that need to be
rewritten.
The upgrade-insecure-requests directive is evaluated before
block-all-mixed-content and if it is set, the latter is effectively a
no-op. It is recommended to set one directive or the other, but not
both.
The upgrade-insecure-requests directive will not ensure that users
visiting your site via links on third-party sites will be upgraded to
HTTPS for the top-level navigation and thus does not replace the
Strict-Transport-Security (HSTS) header, which should still be set
with an appropriate max-age to ensure that users are not subject to
SSL stripping attacks.
Source: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/upgrade-insecure-requests
Ignoring 3xx responses for a moment, I wonder why the HTTP location header is only used in conjunction with POST requests/201 (Created) responses.
From the RFC 2616 spec:
For 201 (Created) responses, the Location is that of the new resource which was created by the request.
This is a widely supported behavior, but why shouldn't it be used with other HTTP methods? Take the JSON API spec as an example:
It defines a self referencing link for the current resource inside the JSON payload (not uncommon for RESTful APIs). This link is included in every payload. The spec says that you MUST include an HTTP location header, if you create a new document via POST and that the value is the same as the self referencing link in the payload, but this is ONLY needed for POST. Why bother with a custom format for a self referencing link, if you could just use the HTTP location header?
Note: This isn't specific to JSON API. It's the same for HAL, JSON Hyper-Schema or other standards.
Note 2: It isn't even specific to the HTTP location header as it is the same with the HTTP link header. As you can see the JSON API, HAL and JSON Hyper-Schema not only define conventions for self referencing links, but also to express information about related resources or possible actions for a resource. But it seems that they all could just use the HTTP link header. (They could even put the self referencing link into the HTTP link header, if they don't want to use the HTTP location header.)
I don't want to rant, it just seems to be some sort of "reinventing the wheel". It also seems to be very limiting: if you would just use HTTP location/link header, it doesn't matter if you ask for JSON, XML or whatever in your HTTP accept header and you would get useful meta-information about your resource on a HEAD request, which wouldn't contain the links if you would use JSON API, HAL or JSON Hyper-Schema.
The semantics of the Location header isn't that of a self-referencing link, but of a link the user-agent should follow in order to complete the request. That makes sense in redirects, and when you create a new resource that will be in a new location you should go to. If your request is already completed, meaning you already have a full representation of the resource you wanted, it doesn't make sense to return a Location.
The Link header may be considered semantically equivalent to an hypertext Link, but it should be used to reference metadata related to the given resource when the media-type is not hypermedia-aware, so it doesn't replace the functionality of a link to related resources in a RESTful API.
The need for a custom link format in the resource representation is inherent to the need to decouple the resource from the underlying implementation and protocol. REST is not coupled to HTTP, and any protocol for which there's a valid URI scheme can be used. If you decided to use the Link header for all links, you're coupling to HTTP.
Let's say you present an FTP link for clients to follow. Where would be the Link in that case?
The semantic of the Location header depends on the status code. For 201, it links to the newly created resource, but in 3xx requests it can have multiple (although similiar) meanings. I think that is why it is generally avoided for other usages.
The alternative is the Content-Location header, which always has a consistent meaning. It tells the client the canonical URL the resource it requested. It is purely informative (in contrast to the Location, which is expected to be processed by the client).
So, the Content-Location header seems to closer resemble a self-referencing link. However, the Content-Location also has no defined behavior for PUT and POST. It also seems to be quite rarely used.
This blogs post Location vs Content-Location is a nice comparison. Here is a quote:
Finally, neither header is meant for general-purpose linking.
In sum, requiring a standardized, self link in the body seems to be good idea. It avoids a lot of confusion on the client side.
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
URI starting with two slashes … how do they behave?
Absolute URLs omitting the protocol (scheme) in order to preserve the one of the current page
shorthand as // for script and link tags? anyone see / use this before?
I was looking through the source of HTML5 Reset when I noticed the following line:
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.5.1/jquery.min.js"></script>
Why does the URL start with two forward slashes? Is this a shorthand for http://?
The "two forward slashes" are a common shorthand for "request the referenced resource using whatever protocol is being used to load the current page".
Best known as "protocol relative URLs", they are particularly useful when elements — such as the JS file in your example — could be served and/or requested from either a http or a https context. By using protocol relative URLs, you can avoid implementing
if (window.location.protocol === 'http:') {
myResourceUrl = 'http://example.com/my-resource.js';
} else {
myResourceUrl = 'https://example.com/my-resource.js';
}
type of logic all over your codebase (assuming, of course, that the server at example.com is able to serve content through both http and https).
A prominent real-world example is the Magento 1.X E-Commerce engine: for performance reasons, the category and product pages use plain http by default, whereas the checkout is https enabled.
If some resources (e.g. promotional banners in the site's header) are referenced via non protocol relative URLs (i.e. http://example.com/banner.jpg), customers reaching the https enabled checkout are greeted with a rather unfriendly
"there are insecure elements on this page"
prompt - which, one can safely assume, isn't exactly great for business.
If the aforementioned resource is referenced via //example.com/banner.jpg though, the browser takes care of loading it via the proper protocol both on the plain http product/category pages and in the https-enabled checkout flow.
tl;dr: With even the slightest possibility of a mixed http/https environment, just use the double slash/protocol relative URLs to reference resources — assuming that the host serving them supports both http and https.
It will automatically add https or http, depending on how the request was made.
My informatics teacher explained that HTTP can really be used exclusively to transfer unencoded ASCII, and as soon as an image or the like have to be downloaded from the server, FTP is used instead.
Is this true?
No, it isn't. HTTP contains a header and data part, the latter gets interpreted by the receipent according to the CONTENT-TYPE header. HTTP can transfer arbitrary data.
If you want any more specific information about the HTTP protocol, the full RFC (request for comments) document is available here: http://www.w3.org/Protocols/rfc2616/rfc2616.html
An RFC is where the various different parties who have a stake in these protocols are presented the current version and invited to give their opinion. It's the method by which most of the internet has been built :)
In regards to this Haacked blog, I'm hesitant to implement the proposed anti-JSON GET hijacking solutions since
The recommended solutions to mitigating JSON hijacking involve non-REST-full JSON POSTs to GET data
The alternate solution (object wrapping) causes problems with 3rd party controls I don't have source-code access to.
I can't find a community-vetted implementation that implements the Alternative Solution (listed below) on how to compose the security token, or securely deliver it within the webpage. I also won't claim to be enough of an expert to roll my own implementation.
Referrer headers can't be relied upon
Background
This blog describes a CSRF issue regarding JSON Hijacking and recommends using JSON POSTs to GET data. Since using a HTTP POST to GET data isn't very REST-full, I'd looking for a more RESTfull solution that enables REST actions per session, or per page.
Another mitigation technique is to wrap JSON data in an object as described here. I'm afraid this may just delay the issue, until another technique is found.
Alternative Implementation
To me, it seems natural to extend the use ASP.NET MVC's AntiForgeryToken with jQuery HTTP GETs for my JSON.
For example if I GET some sensitive data, according to the Haacked link above, the following code is vulnerable:
$.getJSON('[url]', { [parameters] }, function(json) {
// callback function code
});
I agree that it isn't RESTfull to GET data using the recommended POST workaround. My thought is to send a validation token in the URL. That way the CSRF-style attacker won't know the complete URL. Cached, or not cached, they won't be able to get the data.
Below are two examples of how a JSON GET query could be done. I'm not sure what implementation is most effective, but may guess that the first one is safer from errant proxies caching this data, thus making it vulnerable to an attacker.
http://localhost:54607/Home/AdminBalances/ENCODEDTOKEN-TOKEN-HERE
or
http://localhost:54607/Home/AdminBalances?ENCODEDTOKEN-TOKEN-HERE
... which might as well be MVC3's AntiForgeryToken, or a variant (see swt) thereof. This token would be set as an inline value on whatever URL format is chosen above.
Sample questions that prevent me from rolling my own solution
What URL format (above) would you use to validate the JSON GET (slash, questionmark, etc) Will a proxy respond to http://localhost:54607/Home/AdminBalances with http://localhost:54607/Home/AdminBalances?ENCODEDTOKEN-TOKEN-HERE data?
How would you deliver that encoded token to the webpage? Inline, or as a page variable?
How would you compose the token? Built in AntiforgeryToken, or by some other means?
The AntiForgeryToken uses a cookie. Would a backing cookie be used/needed in this case? HTTP Only? What about SSL in conjunction with HTTP Only?
How would you set your cache headers? Anything special for the Google Web Accelerator (for example)
What are the implications of just making the JSON request SSL?
Should the returned JSON array still be wrapped in an object just for safety's sake?
How will this solution interop with Microsoft's proposed templating and databinding features
The questions above are the reasons I'm not forging ahead and doing this myself. Not to mention there likely more questions I haven't thought of, and yet are a risk.
The Asp.net MVC AntiForgeryToken won't work through HTTP GET, because it relies on cookies which rely on HTTP POST (it uses the "Double Submit Cookies" technique described in the OWASP XSRF Prevention Cheat Sheet). You can also additionally protect the cookies sent to the client by setting the as httponly, so they cannot be spoofed via a script.
In this document you can find various techniques that can be used to prevent XSRF. It seems the you described would fall into the Approach 1. But we have a problem on how to retrieve the session on the server when using Ajax HTTP GET request since the cookies are not sent with the request. So you would also have to add a session identifier to you action's URL (aka. cookieless sessions, which are easier to hijack). So in order to perform an attack the attacker would only need to know the correct URL to perform the GET request.
Perhaps a good solution would be to store the session data using some key from the users SSL certificate (for example the certs thumb-print). This way only the owner of the SSL certificate could access his session. This way you don't need to use cookies and you don't need to send session identifiers via query string parameters.
Anyway, you will need to roll out your own XSRF protection if you don't want to use HTTP POST in Asp.net MVC.
I came to this problem and the solution was not so trivial however there is a fantastic blog to get you started this can be used with get and post ajax.
http://johan.driessen.se/posts/Updated-Anti-XSRF-Validation-for-ASP.NET-MVC-4-RC
If you place the following in the global name space all your post/gets can take advantage having an anti forgery token and you don't have to modify your ajax calls. Create an input element in a common page.
<form id="__AjaxAntiForgeryForm" action="#" method="post">#Html.AntiForgeryToken()</form>
The following javascript will read the anti forgery tokken and add it to the request header.
// Wire up the global jQuery ajaxSend event handler.
$(document).ajaxSend(namespace.ajax.globalSendHandler);
// <summary>
// Global handler for all ajax send events.
// </summary>
namespace.ajax.globalSendHandler = function (event, xhr, ajaxOptions) {
// Add the anti forgery token
xhr.setRequestHeader('__RequestVerificationToken', $("#__AjaxAntiForgeryForm input[name=__RequestVerificationToken]").val());
};
I think it is legitimate to use AntiforgeryToken (AFT) within an ajax http GET request provided that it is embedded in a form that already provides the AFT and associated cookie. The ajax handler can then do the validate on the server just how it would in a normal form post.