Restrict access to specific endpoint unless certain header value given - nginx

As I explained in title I want to restrict access unless the header is satisfied. In the given link, it is explained how to restrict a specific path access, however I couldn't find anything about how to add conditions to this restriction from my researches. Any idea about this problem?

Instead of deny/allow directives you can check any HTTP header value via $http_<name> variable and use return 403 to forbid access. For example, lets call our header X-Secret-Token:
location /some/path {
if ($http_x_secret_token != 'my-super-secret-password') {
return 403; # HTTP 403 Forbidden, the same code as generated by 'deny' directive
}
...
}
If you need some complex checks, you can use several chained map blocks (see the example).

From the research I've made it seems like the token approach presented here before seems to be the only suitable solution, a similar question has been asked here.

Related

How do I access individual headers from a API request response?

I'm currently creating a test suite for a new API, at the moment I've sent a POST request and it's responding as expected. However, I'm now performing further validation such as checking the status code and also wish to check the Location Header. Problem being, through trial and error I've been unable to access to location header value from the response. Below is some cut down code:
${POST_REQUEST} Replace String ${CLAIM_AVAILABLE_BASE_URL} PLAN_NAME ${VALID_PLAN}
${file_data}= Get Binary File Data/Json/API/GETNaviNetClaimID/valid_aries_claim_local_only.json
${POST_RESPONSE} Post Request APIService ${POST_REQUEST} data=${file_data}
Should Be Equal As Strings ${POST_RESPONSE.status_code} ${HTTP STATUSCODE OK}
I can access the header object using:
${POST_RESPONSE.headers}
But so far I've been unable to pull out just the location header value. Can anyone offer any assistance? I'm using the Requests Library
Seems possible using the below, just replace location with the key you're looking for.
${location_header}= Get From Dictionary ${POST_RESPONSE.headers} location
I don't like this solution though so welcome to anything better!

how to match # character in a url in nginx through location directive

How do I match a # character in a url using location directive? I understand that we can use regex(PCRE), but their docs say that :
The location directive only tries to match from the first / after the hostname, to just before the first ? or #. (Within that range, it matches the unescaped url.)"
In short, How to match "example.com/#123456" using
location ~ [someregex] {
return 200 "matched";
}
or with any other alternative
Simple answer, you can't actually, because that part is never sent to the server to begin with, the only way to process this is to use Javascript, using location.hash
You can't because the ID hash isn't actually sent to the server, you might want to use GET variables like example.com?p=1234 if you intend to direct to a certain page or use location.hash if you wish to direct to a location on the page (which is its intended use)
Good luck!

What response code is appropriate for this situation?

I'm developing a webgame. As part of the game, you start out with a limited set of features, and you unlock more of them as you play.
For instance, you unlock /fields as part of step 3 in the tutorial. But what if you just navigate to /fields in the address bar?
I'm trying to work out what would be the best status code to respond with.
403 seems ideal since the user is forbidden from accessing the page until they unlock it.
404 also makes sense since the page technically "doesn't exist" until it is unlocked and also prevents users from being able to tell the difference between a page that doesn't exist and one that they just haven't unlocked yet.
But in both cases I've had some users report issues with the browser cacheing the 403/404 result and not letting them access the page even after unlocking it unless they purge the cache entirely.
I'm wondering if I should keep using 403 or 404, or should I use an unused 4XX code such as 442 with a custom statusText, or even jokingly send HTTP/1.1 418 I'm A Teapot in response to a user poking around where they shouldn't be.
I need a good, solid reason why one option should be used over the others.
tl;dr 409 Conflict would be an idea, but perhaps you have problems with caching. In this case a cache-buster to force a reload will work.
Long explanation
Perhaps a 409 Conflict status code would make sense:
10.4.10 409 Conflict
The request could not be completed due to a conflict with the current state of the resource. This code is only allowed in situations where it is expected that the user might be able to resolve the conflict and resubmit the request. The response body SHOULD include enough information for the user to recognize the source of the conflict. Ideally, the response entity would include enough information for the user or user agent to fix the problem; however, that might not be possible and is not required.
Conflicts are most likely to occur in response to a PUT request. For example, if versioning were being used and the entity being PUT included changes to a resource which conflict with those made by an earlier (third-party) request, the server might use the 409 response to indicate that it can't complete the request. In this case, the response entity would likely contain a list of the differences between the two versions in a format defined by the response Content-Type.
It would make sense, because the resource is only available after the user did the tutorial. Before that the resource is in an «invalid» state. And the user is able to resolve this conflict by completing the tutorial.
Later I investigated the case a little more and I discovered that the devil is in the detail. Let's read the specification for 403 Forbidden and 404 Not Found.
10.4.4 403 Forbidden
The server understood the request, but is refusing to fulfill it. Authorization will not help and the request SHOULD NOT be repeated. If the request method was not HEAD and the server wishes to make public why the request has not been fulfilled, it SHOULD describe the reason for the refusal in the entity. This status code is commonly used when the server does not wish to reveal exactly why the request has been refused, or when no other response is applicable.
Important is the specification that «the request SHOULD NOT be repeated». A browser which never re-requests a 403 page might do the right thing. However, let's continue with 404:
10.4.5 404 Not Found
The server has not found anything matching the Request-URI. No indication is given of whether the condition is temporary or permanent.
[omitted]
Now we have a problem! Why would your 404 pages be cached if the specification allows them to be temporary?
Perhaps in your setup you have caching configured not correctly for your 403 and 404 pages. If this is so, please consult this answer on StackOverflow. It gives a detailed answer about caching 4xx pages.
If you don't want to mess with caching headers, use a so-called cache-buster and pass the system time like this (assuming PHP as your web language):
<a href="/fields?<?php echo time(); ?>">
This produces URLs like /fields?1361948122, increasing every second. It's a variant of the solution proposed by Markus A.
I assume the querystring 1361948122 is ignored by your resource. If it is not, pass the cache-buster in a querystring parameter instead, for example t=1361948122 and make sure that the parameter t is not evaluated by your resource.
In terms of the intended purpose of the HTTP error codes, I would definitely go with 403 Forbidden, because the page does exist (404 is out), but the user is forbidden to access it for now (and this restriction is not due to a resource conflict, like concurrent modification, but due to the user's account status, i.e. 409 is out as well in my opinion). Another sensible option based on it's intended purpose could have been 401, but as nalply already noted in his comment, this code triggers some, if not all, browsers to display a login dialog, as it implies that using the standard web-authentication mechanism can resolve the issue. So, it would definitely not be an option for you here.
Two things seem a little "misfitting" in the description of 403, so let me address them:
Authorization will not help ...: This only talks about the authorization mechanism inside the HTTP protocol and is meant to distinguish 403 from 401. This statement does not apply to any form of custom authorization or session state management.
... the request SHOULD NOT be repeated ...: A request must always be seen in the session context, so if the session context of the user changes (he unlocks a feature) and then he retries accessing the same resource, that is a different request, i.e. there is no violation of this suggestion.
Of course, you could also define your own error code, but since it probably won't be reserved in any official way, there is no guarantee that some browser manufacturer isn't going to intentionally or accidentally use exactly that code to trigger a specific (debugging) action. It's unlikely, but not disallowed.
418 could be OK, too, though. :)
Of course, if you would like to specifically obscure the potential availability of features, you could also decide to use 404 as that is the only way to not give a nosy user any hints.
Now, to your caching issue:
Neither one of these status codes (403, 404, 409, 418) should trigger the browser to cache the page against your will more than any other. The problem is that many browser simply try to cache everything like crazy to be extra snappy. Opera is the worst here in my opinion. I've been pulling my hair out many times over these things. It SHOULD be possible to work it all out with the correct header settings, but I've had situations where either the browser or the server or some intermediate proxy decided to ignore them and break my page anyways.
The only sure-fire way that I have found so far that absolutely positively guarantees a reload is to add a dummy request parameter like /fields?t=29873, where 29873 is a number that is unique for every request you make within any possibly relevant time scales. On the server, of course, you can then simply ignore this parameter. Note that it is not enough to simply start at 1 when your user first opens your page and then count up for following requests, as browsers might keep the cache around across page-reloads.
I do my web-development in Java (both server and client-side using GWT) and I use this code to generate the dummy "numbers":
private static final char[] base64chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_.".toCharArray();
private static int tagIndex = 0;
/**
* Generates a unique 6-character tag string that is guaranteed to not repeat
* for about 400 days, if this function is, on average, not called more often
* than twice every millisecond.
*
* #return the tag string
*/
public static String nowTag() {
int tag = (int) ((System.currentTimeMillis() >>> 5)); // adjust
char[] result = new char[6];
result[5] = base64chars[(tagIndex++) & 63];
result[4] = base64chars[tag & 63];
tag >>>= 6;
result[3] = base64chars[tag & 63];
tag >>>= 6;
result[2] = base64chars[tag & 63];
tag >>>= 6;
result[1] = base64chars[tag & 63];
tag >>>= 6;
result[0] = base64chars[tag & 63];
return new String(result);
}
It uses the system's clock in combination with a counter to be able to provide up to about two guaranteed unique values every ms. You might not need this speed, so you can feel free to change the >>> 5 that I marked with "adjust" to fit your needs. If you increase it by 1, your rate goes down by a factor of two and your uniqueness time-span doubles. So, for example, if you put >>> 8 instead, you can generate about 1 value every 4 ms and the values should not repeat for 3200 days. Of course, this guarantee that the values will not repeat will go away if the user messes with the system clock. But since these values are not generated sequentially, it is still very unlikely that you will hit the same number twice. The code generates a 6-character text-string (base64) rather than a decimal number to keep the URLs as short as possible.
Hope this helps. :)
I feel there is no need to throw an error code, in spite you just display a message like
You have to be Level XX to access this page or something funny like Come back when you grow-up
with code 200-OK itself, so there will be no cache problem and objective is also achieved.

Can the Location header be used for multiple resource locations in a 201 Created response?

What is the correct verb and response to accept a batch PUT create and then return multiple locations? The Location header only appears to support one single Uri.
I assumed originally I could use PUT for a batch create and return an string array with a list of Uris, but in looking at the specification, that doesn't appear to be supported, but it isn't entirely clear either.
Are multiple Location headers permissible as an alternative?
Any advice?
No, you can have only one Location header field (and yes, it is clear from the spec).
That being said, PUT is for creating/updating a single resource. It seems that you're using it for something it is not designed for...
PUT can only create one resource, because according to the specification:
The PUT method requests that the state of the target resource be created or replaced with the state defined by the representation enclosed in the request message payload.
(https://www.rfc-editor.org/rfc/rfc7231#section-4.3.4)
However, it is possible for a request with a different verb (such as POST) to create multiple resources and return a 201 Created status. According to the specification:
The primary resource created by the request is identified by either a Location header field in the response or, if no Location field is received, by the effective request URI.
The 201 response payload typically describes and links to the resource(s) created.
(https://www.rfc-editor.org/rfc/rfc7231#section-6.3.2)
So it is OK to return the URIs of multiple created resources in a 201 response to, e.g., a POST request, but the Location header may only contain one URI.
RFC 5988 introduces Link HTTP Header. It can be used for this purpose.

If POST to an URL and how can I tell the client to look at a fragment of the response?

I would like to POST an entity as follows
POST /example.org/MyEntity/100
Based on the passed entity, the server would like to draw the users attention to a particular part of the response using a fragment identifier. e.g.
/example.org/MyEntity/100#InterestingPart
How do I return this new URL to the client. I am assuming I could do some form of redirect using a 3XX response code, but I actually do not want the client to do another request because the only difference between the two URLs is the fragment. At the moment it seems that a 307 return code would be the most appropriate because according to the spec you should not automatically redirect a POST.
Is there are better way?
Update: My client is not limited to the constraints of a web browser. I am just looking at this from the perspective of HTTP.
Update2: Based on my reading of RFC2616, I can see nothing stopping me from returning a 200 and a Location header that contains the fragment identifier. Anyone know of a reason why I cannot do that?
I think the only sensible solution is to have action URL have static fragment identifier, like <form method="post" action="/action#anchored"> and then put an anchor wherever you want user to look at while generating page.
But, to answer the Update2: no, there's no reason to avoid it.
My inclination is to return 201 - and have the location header point to the URI you want the client to GET.
I didn't look, but IIRC nothing dictates that the location header points to the resource created, so it should be spec legal.
You should normally redirect every POST to avoid problems with refreshing the page and the use of the back button. This is known as the PRG (POST Redirect Get) pattern:
http://blog.httpwatch.com/2007/10/03/60-of-web-users-can%E2%80%99t-be-wrong-%E2%80%93-don%E2%80%99t-break-the-back-button/
Although, this does incur the cost of another round trip to the server it makes your web application much more user friendly.
You could then add the fragment onto the redirected URL.
There's an example of PRG with a fragment on this page:
http://www.httpwatch.com/httpgallery/redirection/
POSTing to the URI:
http://example.org/MyEntity/100
implies to me that a MyEntity resource called "100" already exists. If that's the case, why not use PUT instead? Is this an update or a create operation?
An alternative might be:
POST http://example.org/MyEntities
Now your service has a choice to make from at least two possibilities:
Return 201 Created. Set the Location header to be the URI you want the client to use (e.g.: http://example.org/MyEntities/100#InterestingPart). Add the representation of the new resource to the body.
Return 204 No Content. Same as above, but no body. This option requires a subsequent GET to fetch the representation, which sounds like what you're trying to avoid.
Neither approach requires redirection and both can return as specific a URI as you desire.
I am curious though, why is the #InterestingPart significant? Why not just return the entire representation and its URI http://example.org/MyEntities/100 in the Location header - and let clients decide for themselves what's interesting or not? If the answers have something to do with only a small part of the resource being of interest (or being modified) during a request, how feasible would it be to break MyResource into a main resource and one or more subordinate resources? For example:
/MyResources/100/CoolThings
/MyResources/100/CoolThings/42
/MyResources/100/InterestingThings
/MyResources/100/InterestingThings/109

Resources