Let's assume there is a website with an API that supports the following REST call in which authenticated user Alice can send registered user Bob a message to his cell phone which he registered on our site (hypothetically speaking, for the sake of this example):

curl --header "Authorization: JWT $someTokenForAuthz" \
     --header "Content-Type: application/json" \
     --request POST \
     --data '{"phone":"+43 123 456","msg":"some text"}'

Let's assume that we classify the phone number as sensitive (PII) data and let's assume, that the API returns the following response in case a phone number is submitted, which was not registered at the site:

{"error": {"code":404,"message":"Phone number not found"}}

Imagine Eve writing a script that iterates through the cell phone numbers +43 000 001 to +43 999 999 (ignoring real world phone number limitations). With the error code and after 1 000 000 iterations of her script, Eve has enumerated all numbers which are registered at the site and can e.g. target site users in a more specific way.

Is it a security issue to return an 404 HTTP error code when sensitive data like a cell phone number was not found in our system? What would be a better way in terms of error handling (as a backup strategy in case request limits/detection mechanisms that already in place might fail) to prevent such sensitive data discovery? A more general 401 - not authorized error or something completely different?

  • 1
    You could return a more general error message, maybe a 400 Bad Request. This is sortof a weird example though because users will probably become frustrated if the site rejects their messages without telling them why so you need to weigh the security vs the usability here. And ultimately an attacker will know if the message succeeded, and since wrong number is pretty much the only thing that could cause an error, I'm not sure you're hiding anything. – Mike Ounsworth Sep 11 '18 at 11:14
  • 1
    You mention "authenticated user Alice" - how hard is it to become an authenticated user? I presume there should be a Cookie: or Authorization: header in this request. There may be more abuses you're not thinking about, e.g. if our attacker wants to harass a specific phone number with threatening messages. – Riking Sep 11 '18 at 16:30
  • Thanks for the input, @Riking, but for the sake of this scenario, let's just say that registration issues and all your other concerns do not apply to this question (of course they would apply in a real world scenario!). – SeeYouInDisneyland Sep 11 '18 at 20:54

So the vulnerability is that returning an error code allows enumeration of the registered phone numbers. If allowing the registered numbers to be disclosed is bad, then this is a security issue.

A more general 401 - not authorized error

No, you've just changed the text - you haven't changed the behaviour.

There are lots of things you might do to make the solution more secure - but we have no basis for knowing which are appropriate to your fictitious model, e.g.

  • always report success
  • don't use phone numbers - use a surrogate identifier (with much higher entropy) and require the client to maintain their lookup tables
  • require authenticated access and revoke that access based on failure rates
  • seed the data with honeypots and revoke clients access when it attempts to use one
  • limit the rate at which a client can make requests
  • charge the client for each POST
  • require recipients to opt-in to receive messages from a given client - return the same error for a missing number as one which has not granted permission
  • ...

    assuming that request limits/detection mechanisms are already in place

So you are saying that you have protection mechanisms in place, but they don't protect against enumeration? Then your question is an oxymoron.

  • The assumption regarding rate limiting was for the case that said limit is by-passed in one way or another. I'll edit the question to clarify. Also, could you please expand on the "always report success"? I feel that this might lead to more issues down the road as @mike-ounsworth mentioned in his comment. From your suggestions, I really like the surrogate IDs which seems quite natural and least intrusive. – SeeYouInDisneyland Sep 11 '18 at 12:49

Your frontend could tell the user only status messages referring to the frontend. Request received? If so, tell. If the validation fails, inform them. Nothing else. If the backend cannot deliver the message for any reason, the frontend should not be informed.

Returning only something like {"status": "success", "message": "Received"} is enough. Eve don't need to know if the number exists or not. If Eve submits an invalid number (invalid, not unregistered), you could throw {"status": "error", "message": "Invalid number"} so she can fix the typo and try again.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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