9

In a REST API interface, should I explicitly check that the client used only the parameters used by the API, and return a HTTP 403 if a parameter the API doesn't know about was included in the request?

A bit of context. I'm working on a API which minifies JavaScript and LESS files. Originally, JavaScript files were minified using Google Closure Compiler. Since Closure Compiler has multiple optimization levels (whitespace only, simple optimizations and advanced optimizations), the API also made it possible for the caller to specify (optionally) the level, so:

POST http://example.com/api/v1/js?level=whitespace

and:

POST http://example.com/api/v1/js?level=advanced

would in most cases give different results.

Recently, I had to add support for ES6. Given the lack of proper support for ES6 by Closure Compiler, I added YUI Compressor. Since this one doesn't have optimization levels, the call is now simply:

POST http://example.com/api/v1/es6

Following POLA, I have an impression that I can't let the callers use the API like this:

POST http://example.com/api/v1/es6?level=advanced

because they would expect a specific result, but get a different one. The solution would be to check for the presence of level parameter in the URI and return a error message indicating that the parameter is not supported.

But I check for this specific parameter, why not checking for lecel (a typo), or optimize (a guess), or anything else?

Therefore, is the API expects parameters a, b and c to be possibly included in the URI, what should be the response if the URI also contains d or e?

4 Answers 4

3

I would argue that your current approach is the one that follows the principle of least astonishment.

RESTfully-speaking, you defined two different resources under v1: js and es6. There’s no reason why these should accept the same query parameters, which aid in the representation of the resource.

And yet, you’re thinking that because all of these are js-minimizers, they would accept the same parameters. And it is actually not a surprise that different minimizers will require different parameters.

Another take at it is that API consumers are very well accustomed to different routes requiring different parameters, they usually don’t have a transparency of changing resources and keeping the same parameters. The exception to this rule might be some authentication parameter or pagination parameter for most APIs, but this is an exception because it deals with cross-cutting concerns that are application-wide responsibilities.

In your case, none of these apply directly. I think your current design is the one that feels more natural and astonishes less.

4

As you already have version for the API (meaning, no backward/forward compatibility concerns), it would be most logical to validate input and on unexpected parameters give 400 (Bad request, very generic), 422 (Unprocessable entity), which some argue is better than 400, see below. Less applicable are 404 (Not found) - because es6 is found, or maybe in very rare cases even 501 (Not implemented).

Using 4xx HTTP code will save your users' time troubleshooting the API access.

See also here (422 suggested as well) or here, which explains why 422 may be more appropriate. See also this question.

Personally, I'd sticked with 400 as well-understood and wide-spectrum HTTP code.

Depending on the use case, some query string parameters may be ignorable, for instance, underscore-prefixed ones, for cases when the only way to prevent caching is changing URL to include "fingerprints".

0
1

level=... seems to be a backwards compatibility issue. In order to not frustrate the current users, I would check for level as it actually did something in previous version, but does not do anything in the current version and give a warning message ("level is deprecated and currently does nothing") - but not stop the processing. I would give the error as part of the JSON response as opposed to the http error. I generally reserve those for errors that prevent processing.

If what you are supporting has the potential to release personal date (healthcare, or credit), then in the case of extra or misspelled variables I would just not return anything. If they are persistent enough, then they will figure it out.

If there is no chance of confidential information to leak out, then give as specific of error/warning as you want. In this case, I would put the warning messages in the JSON response as it would not affect processing to occur.

In either case, you should be checking all of the variables and values being passed in to confirm that there is no cross-site scripting or sql injections or any other security concern.

7
  • I'd not returned 200 on clearly invalid requests (such us applying invalid query string parameter), otherwise good point about leaking information regarding possible options ("enumeration attack"), but applicable only if there truly are parameters available to more trusted users.
    – Roman Susi
    Dec 29, 2017 at 17:11
  • 2
    Get any url out there, put a random query string param and you will find that the URL still works. POLA doesn't fit well here. If we speak about WEB and we are aware of its key points, we realise that the whole architecture fits better into Postel's law. In the line of the Postel law's arguments, ignoring the useless parameters is the easier and simplest solution. If you strive to validate any possible query param you will end up with a witch hunt (spending lot of LoC looking for errors instead of code that provides value to the business). WEB is meant to be flexible. So be flexible.
    – Laiv
    Dec 29, 2017 at 22:40
  • Laiv, yes the web is sypposed to be flexible, and if there are going to be no fines levied against you, then completly ignoring invalid parameters and not looking for potential SQL injections/cross site scripting does save lines of code and headaches. However, if there is a leak of hippa related information, you may be held liable for each violation (in essence each data point). I think the fine was $50 per violation, and so if you are dealing with a small dataset of 100k, on a bad day, you could be fined 5 million. Basically, Dec 29, 2017 at 23:16
  • Leiv (cont), I'll let you have the discussion with rhe judge about the web should be flexible. Dec 29, 2017 at 23:18
  • Well, the CPD could be also hacked by terrorist or pirates causing the very same problem. The judge will ask why my CPD was so vulnerable I think you are crossing subjects. A query param that is ignored because it's not required, has no side effects. There's no attack vector. Moreover, between the client and the code that holds the business, there are several layers capable to deal with such problem. Even a simple HTTP proxy could.
    – Laiv
    Dec 29, 2017 at 23:31
1

If you're willing to spend the time and effort to validate against unused parameters then I'd suggest making such validation optional.

For example, you could accept a strict=true flag (as a parameter or request header) that would result in an error if the client sends an unknown (or unused) parameter. Those who prefer tool-based safety nets (e.g. those preferring a compiler) will probably use it all the time whereas those who have a different preference can choose to limit its use to dev and/or test phases.

Some web frameworks (e.g. Rails) ignore unknown parameters by default. This can help with forward compatibility as your clients can start asking for a feature even before your server supports it. For example, you may choose to enable support for the level parameter later and your clients wouldn't need to be changed.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.