Secure verify endpoint on providers
We need to secure the verify endpoint on providers so that we can rate limit it and realistically implement charges different pricing tiers.
Background
Captcha Providers run an API that delivers our service. There are various endpoints:
https://github.com/prosopo/captcha/blob/60c44b46240edae78319bc6af1a2b5b5b1cdffa2/packages/types/src/provider/api.ts#L18-L27
Clients are billed based on how many requests they make to verify endpoints:
- 0 - 100k Free
- 100k - 1M $9 per month
- 1M+ - custom
To make a request to an endpoint, a client must pass their dapp (site key - which is actually the public key of a keypair).
Clients' obtain their site key from us when they sign up to our website. We email them their site key as part of our email trigger server. However, we don't currently provide access to the private key.
Precursor
Access to the private key must also be provided - a precursor to merging this issue.
Problem
Currently, there is no check in the verify endpoints to verify that the calling dapp (site key) is actually owned by the caller.
Image Captcha verification body
dapp is passed but there is no check to see if the caller owns the dapp (site key) account.
https://github.com/prosopo/captcha/blob/60c44b46240edae78319bc6af1a2b5b5b1cdffa2/packages/types/src/provider/api.ts#L97-L103
parsed.dapp is not used in this verify function:
https://github.com/prosopo/captcha/blob/60c44b46240edae78319bc6af1a2b5b5b1cdffa2/packages/provider/src/api/captcha.ts#L137-L140
PoW captcha verification body
dapp is passed but there is no check to see if the caller owns the dapp (site key) account.
https://github.com/prosopo/captcha/blob/60c44b46240edae78319bc6af1a2b5b5b1cdffa2/packages/types/src/provider/api.ts#L146-L149
dapp is not used in this verify function:
https://github.com/prosopo/captcha/blob/60c44b46240edae78319bc6af1a2b5b5b1cdffa2/packages/provider/src/api/captcha.ts#L248
Considerations
Frontend Verify Calls
There is currently a verify API call made from the frontend of procaptcha when a user has cached @prosopo/procaptcha local storage, indicating that they previously completed a captcha.
https://github.com/prosopo/captcha/blob/60c44b46240edae78319bc6af1a2b5b5b1cdffa2/packages/procaptcha/src/modules/Manager.ts#L184-L196
These calls would need to be switched to use a different, unsecured endpoint as we obviously can't give the frontend access to the dapp private key.
API Verify Endpoint
Calls are made from an AWS lambda on behalf of dapps. Dapp signatures would also need to be forwarded on from this lambda to the providers. Or, signature verification could occur within the lambda to avoid making any extra unnecessary calls should the signature be invalid.
Required Changes
Require that dapps calling the verify endpoints sign a message to show that they own their site key. This needs to occur in the following places:
Where to add signature
Add dapp signature parameter here: https://github.com/prosopo/captcha/blob/60c44b46240edae78319bc6af1a2b5b5b1cdffa2/packages/api/src/api/ProviderApi.ts#L76-L82
Add dapp signature parameter here: https://github.com/prosopo/captcha/blob/60c44b46240edae78319bc6af1a2b5b5b1cdffa2/packages/api/src/api/ProviderApi.ts#L103-L108
How to compute a signature
Here is an example of how signing is achieved in the frontend using the user's account:
https://github.com/prosopo/captcha/blob/60c44b46240edae78319bc6af1a2b5b5b1cdffa2/packages/procaptcha/src/modules/ProsopoCaptchaApi.ts#L136-L141
We need to provide similar functionality wherever the verify endpoints are called.
What message to sign
TODO - this needs to be something that is fairly recent so that the same signature cannot be used again and again. The block number might be a good candidate.