Skip to content

Verify reCAPTCHA tokens over cURL instead of file_get_contents (magento/magento2#41428) - #347

Open
lbajsarowicz wants to merge 1 commit into
magento:developfrom
lbajsarowicz:fix/recaptcha-curl-request-method
Open

lbajsarowicz wants to merge 1 commit into
magento:developfrom
lbajsarowicz:fix/recaptcha-curl-request-method

Conversation

@lbajsarowicz

Copy link
Copy Markdown

Description (*)

Magento\ReCaptchaValidation\Model\ReCaptcha is created by Validator::isValid() with only the secret, so ReCaptcha\ReCaptcha::__construct() falls back to RequestMethod\Post. That class verifies the token with file_get_contents() on https://www.google.com/recaptcha/api/siteverify. On servers running with allow_url_fopen=0 the call fails, the library returns connection-failed, and every reCAPTCHA-protected form rejects every submission.

This PR injects ReCaptcha\RequestMethod\CurlPost (shipped by phpfui/recaptcha, no required constructor arguments) through the module's di.xml. cURL works regardless of allow_url_fopen, and ext-curl is already required by magento/framework; the module now declares it in its own composer.json as well.

Because one validator serves storefront, admin, REST and GraphQL, the change covers every reCAPTCHA entry point.

An integration test asserts that ReCaptchaFactory produces an instance that uses CurlPost.

Fixed Issues (if relevant)

  1. reCAPTCHA validation fails when allow_url_fopen is disabled magento2#41428: reCAPTCHA validation fails when allow_url_fopen is disabled

Manual testing scenarios (*)

  1. Set allow_url_fopen = Off for PHP-FPM.
  2. Configure reCAPTCHA v3 Invisible keys and enable it for "Create New Customer Account".
  3. Without this change: submitting the registration form fails reCAPTCHA validation, and the log shows file_get_contents(): https:// wrapper is disabled in the server configuration by allow_url_fopen=0.
  4. With this change: the form is accepted with a valid token, and rejected with a validation error when the token is missing or invalid.

I also checked it outside a full installation: I parsed this module's di.xml with Magento\Framework\ObjectManager\Config\Mapper\Dom, built Magento\ReCaptchaValidation\Model\ReCaptcha through the ObjectManager, and called verify() under php -d allow_url_fopen=0. Without the di.xml entry it used Post and returned connection-failed. With it, CurlPost reached Google, which returned invalid-input-response for the dummy token.

Questions or comments

Post is bounded by default_socket_timeout, while CurlPost uses cURL defaults with no total timeout. If a bounded timeout is wanted, it can be added in a follow-up through a custom ReCaptcha\RequestMethod\Curl wrapper.

Contribution checklist (*)

  • Author has signed the Adobe CLA
  • Pull request has a meaningful description of its purpose
  • All commits are accompanied by meaningful commit messages
  • All new or changed code is covered with unit/integration tests (if applicable)
  • All automated tests passed successfully (all builds are green)

Magento\ReCaptchaValidation\Model\ReCaptcha was created without a request
method, so the library fell back to RequestMethod\Post, which calls
file_get_contents() on the siteverify URL. On servers with
allow_url_fopen=0 every verification failed with connection-failed and
reCAPTCHA-protected forms rejected all submissions.

Inject ReCaptcha\RequestMethod\CurlPost through di.xml. ext-curl is already
required by magento/framework; it is now declared by the module too.
@lbajsarowicz

Copy link
Copy Markdown
Author

@magento run all tests

@lbajsarowicz

Copy link
Copy Markdown
Author

@alzota tracked in magento/magento2#41428 (internal AC-19076). Happy to adjust anything if the team prefers a different approach, for example a bounded cURL timeout.

@bluefairydevelopment

Copy link
Copy Markdown

Tested on Magento Open Source 2.4.9 (magento/module-re-captcha-validation 1.1.5, phpfui/recaptcha 2.0.1, PHP 8.5), calling Magento\ReCaptchaValidation\Model\ReCaptcha the way ReCaptchaFactory builds it today and the way this PR's di.xml builds it, with a dummy secret and token against the real siteverify endpoint:

allow_url_fopen today (no request method → Post) with this PR (CurlPost)
0 connection-failed, plus the "https:// wrapper is disabled" warning from magento/magento2#41428 invalid-input-response (Google reached and answered)
1 invalid-input-response invalid-input-response

So with allow_url_fopen=0 every verification currently fails before reaching Google, and CurlPost restores the same round trip as allow_url_fopen=1. With it enabled, the behaviour is unchanged. I did not run the integration test in this PR. The ext-curl requirement is already met by magento/framework.

Confirming the fix works as described. It would be good to see this reviewed, since it affects every reCAPTCHA-protected form on hardened hosting.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants