camaraproject / Commonalities

Repository to describe, develop, document and test the common guidelines and assets for CAMARA APIs
Apache License 2.0
10 stars 25 forks source link

API misuse #259

Open AxelNennker opened 1 month ago

AxelNennker commented 1 month ago

Problem description @HuubAppelboom raised an issue in today's SimSwap... - meeting

@HuubAppelboom raised a good point about potential use of SIM swap to perform a numberVerification

If the parameter phoneNumber is present and the phoneNumber is also in the access token, then SimSwap might also accidentally implementing NumberVerification because if the values do not match the result of the API request is different to when the values match.

This problem exists for APIs where identifying information is available in several places.

This leads to several topics worth considering:

Expected behavior API Design Guideline should make API designers aware of this problem and provide guidance on how to handle this.

e.g. add guidance e.g. to the API Design Guidelines' Security section like the following sentence If identifying information is both available in a request parameter and in the access token then the resource server MUST ignore the request parameter. No error should be returned if information from the access token and information from request parameters are inconsistent or contradict each other, because the error message is doing the leaking of information.

ICM could also or additionally put some text into info.description?! @jpengar

Aditional Context

regarding device object: https://github.com/camaraproject/DeviceLocation/issues/201

jpengar commented 1 month ago

This issue is trickier than it looks. IMHO, this would only apply if the access token was obtained using Auth Code, where the phone number is validated with network-based authentication. In the case of CIBA, the phone number is provided by a backend as login_hint.

On the other hand, if the API request provides a phone_number, it must be validated against the access token to ensure that the client is allowed to access the requested resource, i.e., the client can only access the authenticated phone number associated with the access token.

I understand the proposed guideline text as potential solution, but it could also be misleading for the API client that (for example) if I request the location of phone number B with the access token associated with phone number A, I will not get an error, but a success response and the actual location obtained is the one corresponding to phone number A.

I think this needs further discussion in the WG...

patrice-conil commented 1 month ago

Hi @jpengar, I agree with You it's trickier than it looks.

This issue is trickier than it looks. IMHO, this would only apply if the access token was obtained using Auth Code, where the phone number is validated with network-based authentication. In the case of CIBA, the phone number is provided by a backend as login_hint.

On the other hand, if the API request provides a phone_number, it must be validated against the access token to ensure that the client is allowed to access the requested resource, i.e., the client can only access the authenticated phone number associated with the access token.

I understand the proposed guideline text as potential solution, but it could also be misleading for the API client that (for example) if I request the location of phone number B with the access token associated with phone number A, I will not get an error, but a success response and the actual location obtained is the one corresponding to phone number A.

I think this needs further discussion in the WG...

  • So far CAMARA only recommends not to send the device object in the API request when using 3-legged access tokens, should CAMARA make it mandatory? In case of SIM swap it was decided to follow the same Commonalities recommendation for device object but with the phoneNumber field (Extracting phoneNumber from the 3-legg access token SimSwap#117).

This is probably the best option in my opinion. Because we need to avoid having conflicting sources of information and it seems to be the best way to ensure that personal information is not disclosed.

  • Should the API document instead, as suggested, that the phone number is ignored in the request when using 3-legged access tokens? Is it a good experience from the API client perspective to not get an error and get the information of a phone number different from the one requested?

I think this would be source of confusion. If we have info twice we must check they match and return an error if not.

sfnuser commented 1 month ago

If the parameter phoneNumber is present and the phoneNumber is also in the access token, then SimSwap might also accidentally implementing NumberVerification because if the values do not match the result of the API request is different to when the values match.

What would be the use case where SimSwap API access requires a 3-legged access token? Why would a fraudulent user ever allow 3-legged token to proceed?

This problem exists for APIs where identifying information is available in several places.

This leads to several topics worth considering:

  • APIs are not "atomic"
  • Privacy considerations because an API (e.g. SimSwap) is leaking information
  • Legal considerations because API access was granted for one "purpose" which might might match or might not match the "emulated" API access
  • Business implications because clients who bought one API (e.g. SimSwap) do not need to buy the emulated API (e.g. NumberVerification)

Should we consider DEVICE_IDENTIFIERS_MISMATCH case as well? With one identifier known, can a API consumer verify other identifier? image

AxelNennker commented 1 month ago

@jpengar regarding:

This issue is trickier than it looks. IMHO, this would only apply if the access token was obtained using Auth Code, where the phone number is validated with network-based authentication. In the case of CIBA, the phone number is provided by a backend as login_hint.

The access token is associated with the device/phone_number on which the browser run, that was used to open the link from the SMS.

I think this applies to CIBA.

eric-murray commented 1 month ago

Actually, this is quite straightforward

For CIBA, there is no issue, as both the MSISDN provided in the login_hint field of the /bc-authorize request and any phoneNumber in the service API call are provided by the client. If they provide different numbers, then they deserve to receive an error, which only confirms that they themselves provided different numbers.

And, as I pointed out here, CIBA also effectively allows device IP/port to MSISDN lookup, so there is no reason to use the authorisation code flow if the network supports such an IP to MSISDN mapping capability.

Only if the network is relying on header enrichment to identify the device must the authorisation code flow be used. In Vodafone's case, this will only be for Number Verification, where verifying the MSISDN provided by the client against the true MSISDN is exactly the use case anyway. I can't see us using authorisation code flow for any other API.

AxelNennker commented 1 month ago

This issue is about clients buying SimSwap API but using it for NumberVerification.

If SimSwap is cheaper than NumberVerifcation then clients might buy SimSwap but use it for NumberVerification. Or if they bought SimSwap but also need NumberVerification, then they might think they skip buying NumberVerfication because SimSwap does verify the number.

The user might have opted-out of NumberVerification but the client is using SimSwap to verify numbers which the user might not have opted-out from.

eric-murray commented 1 month ago

@AxelNennker

But this is inherent to CIBA that supports login_hint="ipport:..." and the use of ID tokens, is it not?

I, as a cheapskate API consumer, request my first access token using login_hint="tel:+1234567890" (the MSISDN the customer tells me) and subsequent access tokens using login_hint="ipport:XX.XX.XX.XX:YYYY". By matching the sub claims of the ID tokens, I can then tell whenever device with MSISDN +1234567890 returns to my application. I don't need to make any service API call at all, I just need to find an API that the end user has opted in to (or not opted out from) and use one of its scopes to request a token.

Or, if I did not know the MSISDN itself but am only interested to know it is the same user returning, I could use CIBA with ipport (or Number Verification) when the end user first visits to obtain a sub for that end user, and then on subsequent device connections use CIBA with ipport for any API with end user consent to confirm whether or not that same end user has returned.

AxelNennker commented 1 month ago

CIBA was designed for use case where the consumption device and the authentication device are different. https://openid.net/specs/openid-client-initiated-backchannel-authentication-core-1_0.html#rfc.section.6

CIBA was not designed for onboarding a user to a mobile app on the user's smartphone - For that the client's mobile app should use OIDC authorization code flow. CIBA was not designed for onboarding a user using a webbrowser on a mobile phone - For that the client's webserver should start OIDC authorization code flow in the mobile webbrowser.

CIBA should not be used if consumption device and authentication device are same. CIBA should not be used if consumption device and authentication device are both under the user's control. (For some definition of control)

The assumptions the client and the telco make about CIBA might not be true or the same.

CIBA and OIDC support login_hint to hint to the authorization server which "account" the user might use to authenticate and give consent. The user is free to use a different account.

CIBA with login_hint=tel:+... shows that the authentication request reached someone at that number. The assumption that the authentication device has the phone number from login_hint might be true or not. The assumption that the consumption device has the phone number from login_hint might be true or not.

I always interpreted the NumberVerification documentation that the number is verified when the API request is made, not when the access token is created. (I removed the link to the NV documentation because NV documentation is now in the yaml file and the linked-to document is stale and probably deprecated. 22.08.2024)

CIBA asserts that someone had control over the authentication device at one point in time.

HuubAppelboom commented 1 month ago

@AxelNennker @eric-murray For API's like KYC Match, SIM Swap and DeviceIdentifier a 3-legged flow is mandatory because we are processing personal information in these. As a result the access token is the access token is phone number specific, and the phone number is already determined by either the login_hint (in case of CIBA) or by retrieving it from the network (in case of front end-flow). There is not point to ask for the phone number again in the resource call (with the exception of Number Verify ofcourse), also because this will lead to either an unintended number verification (in case you start comparing the number provided with the number associated with the access token), or it will lead to confusion with the developer, or it will lead to loss of revenue.

I think there are 3 options:

  1. we should either remove the phone numbers from all the resource calls in case only 3 legged flows are permitted
  2. we should make the phone number always an optional parameter (to be used only for client credential flows) and always return an error in case the phone number is presented in the resource call with a 3 legged flow (CIBA and Front End Flow)
  3. in case the client presents the phone number in the resource call, in case of front end flow, return whether the number matches (just like with Number Verification) , and charge the API consumer additonal charges. In case of CIBA flow, you provide an error in case there is a mismatch between login_hint and the number presented in the resource call.

My preference is option 1, this is the simplest, if you ask me. Option 2 has more flexibility in it, in case parties want to use a (faster) client credential flow.

Would like to hear your thought on this.

AxelNennker commented 1 month ago

@HuubAppelboom from the general issue back to the specific: What do you think about this proposal? https://github.com/camaraproject/SimSwap/issues/117#issuecomment-2247792629 which seem to cover your option 2 and 3

eric-murray commented 1 month ago

@HuubAppelboom

and the phone number is already determined by either the login_hint (in case of CIBA)

In the case of CIBA, the phone number is specified by the API consumer, independent of any end user device. If the API consumer then specifies a different phone number in the API service call itself, then any error is just telling them that they specified two different end user phone numbers. I don't see the issue here, as no device has ever confirmed its phone number.

I can see the issue with authorisation code flow but, for APIs such as SIM Swap, using authorisation code flow doesn't really make sense for the use case. Current implementations use CIBA. This will be true for many APIs.

@AxelNennker How does the proposed solution for SIM Swap fix the issues with CIBA and use of login_hint="ipport:..."?

jpengar commented 1 month ago

@eric-murray I think that assuming only the use of CIBA flow for 3-legged scenarios is something we shouldn't do (there's not even consensus about it CC @sfnuser @AxelNennker ) and IMHO it's not consistent with existing CAMARA definitions in ICM. It has its own discussion thread in https://github.com/camaraproject/IdentityAndConsentManagement/issues/176 as you mention. So I would not consider it a solution to the original problem reported here.

From Huub's comment, I see option 2 as the one that better fits exiting ICM definitions giving the flexibility to consume and API in 3-legged and 2 legged mode as needed.

we should make the phone number always an optional parameter (to be used only for client credential flows) and always return an error in case the phone number is presented in the resource call with a 3 legged flow (CIBA and Front End Flow)

We should make sure that there are no other corner cases not considered so far if option 2 is chosen. And it would be necessary to define what would be the error returned to the API client when phone_number/device is used in the API call with a three-legged flow.

HuubAppelboom commented 1 month ago

@HuubAppelboom from the general issue back to the specific: What do you think about this proposal? camaraproject/SimSwap#117 (comment) which seem to cover your option 2 and 3

@AxelNennker The problem with this proposal is that once you provide errors like the 403 - INVALID_TOKEN_CONTEXT error, you are effectively doing the same thing as a in a Number Verification call.

Note that my option 2 is different in the sense that as soon as you see two sources of phone number information, you will always return an error code (and not only when there is a mismatch).

Option 3 is also different, because here you make it more explicit that a Number Verification is included, by provding an explict answer on the phone number in the request (just like how you respond with Number Verification).

MarkCornall commented 1 month ago

A valid point and a way of getting a free number verification. Although we are trying to be helpful surely the use of a more generic error rather than an invalid token indication would mean that you could then not rely on the result from any of these APIs and would need to call number verify for a real answer. I can see any of the other APIs as being more premium to number verify.

AxelNennker commented 1 month ago

For some definition of "premium"... I expect that number verification is an attractive API for high-volume services that have billions of users, while sim-swap is an Account Take Over Protection or Risk Management API which is probably rarer.

Hard to say whether billions times small fee greater or less than millions time high fee.

AxelNennker commented 1 month ago

I think all APIs that have a device object or phoneNumber as a parameter should be aware that the API could be used to validate that information.

HuubAppelboom commented 1 month ago

@AxelNennker @MarkCornall There will be API's at a lower price point than Number Verify and at a higher price point. Either way you can have a revenue leak.

But what is more relevant I think is that you may have a privacy leak which the MNO or the API Consumer is not aware of.
Under GDPR, you will need to be transparent about what gets verified, and having a "hidden" verification in a protocol is not a good idea. Also, asking for personal information in a resource call when it is not needed is not a good idea, you should always try to minimize this.

jpengar commented 1 month ago

A valid point and a way of getting a free number verification. Although we are trying to be helpful surely the use of a more generic error rather than an invalid token indication would mean that you could then not rely on the result from any of these APIs and would need to call number verify for a real answer. I can see any of the other APIs as being more premium to number verify.

The issue is not solely the error message returned. The primary use case for Number Verification is to confirm a number "positively," under the assumption that the number is already known. It is not intended for discovering numbers through trial and error. When using the Sim Swap API or similar services as an alternative, the objective is to obtain a 200 status code to verify the number.

As long as CAMARA asserts that a 200 API response indicates successful validation of the number against the provided token, we are inherently disclosing this verification.

If an error occurs, it may be unclear whether it is due to a mismatch of the phone number or another issue. However, it can already be inferred that the number has not been verified.

MarkCornall commented 1 month ago

Are we also open to someone calling the authorisation flow and getting the information that they need but not finally calling the actual API?

AxelNennker commented 1 month ago

Are we also open to someone calling the authorisation flow and getting the information that they need but not finally calling the actual API?

That seems to be a question for Camara business people. if e.g. the client pays a monthly fee for being registered and there is a maximum of created access-tokens per month, then we might not care much.

eric-murray commented 1 month ago

If it is agreed that this type of information leak is to be avoided, then I think the decision for Commonalities is whether providing a 3-legged access token and a device object in the service API call is always and error or never an error. It is only because we currently only give an error when the device identifiers do not match that we have an information leak.

So the options would be:

As an API implementor, I slightly favour the second option (as, in fact, that is what Vodafone already do). But I understand that the API consumer may not be aware they are using a 3-legged token (maybe the developer got it from some library call) and could be misled by the response when they provided a device object that identifies a different device to the token.

So my preference is therefore that providing a 3-legged token and a device object should always be an error.

As to which error, I'd say a 422 still applies, but with a more generic code - maybe 422 UNNECESSARY_DEVICE_IDENTIFIER.

HuubAppelboom commented 6 days ago

@eric-murray

As to which error, I'd say a 422 still applies, but with a more generic code - maybe 422 UNNECESSARY_DEVICE_IDENTIFIER.

Aan alternative error code may be 400 - INVALID_ARGUMENT - Client specified an invalid argument, request body or query param

This already exsists, and it covers it (the phone number should not be in the request)

eric-murray commented 6 days ago

@HuubAppelboom

As to which error, I'd say a 422 still applies, but with a more generic code - maybe 422 UNNECESSARY_DEVICE_IDENTIFIER.

Aan alternative error code may be 400 - INVALID_ARGUMENT - Client specified an invalid argument, request body or query param

My instinct is to try to restrict 400 errors to clear violations of the API OAS definition (for example, pattern violations, or not including required parameters). The 400 error is a strong hint to the API consumer to read the API definition in more detail.

In this case, the Device object must remain optional in case a 2-legged token is provided, and if providing a (correctly formatted) optional parameter results in an error, I think more explanation is required. The reason for the error may not be obvious to the developer, particularly when the provided phone number does match that associated with the token, and certainly wouldn't be picked up by any additional OAS validation.

Now maybe this additional error documentation could be in the error message, but I think giving the error its own code would make it simpler for the developer to search for the correct documentation to explain their error.