← All changes
|
app/Modules/Payments/PaymentMethods/Stripe/ConnectConfig.php
+26
-4
6.2.4
→
6.2.15
View file →
| @@ -16,18 +16,22 @@ | ||
| 16 | 16 | |
| 17 | 17 | public static function getConnectConfig() |
| 18 | 18 | { |
| 19 | 19 | $configBase = self::$connectBase . 'stripe-connect'; |
| 20 | - $hash = md5(site_url() . wp_generate_uuid4() . time()); | |
| 20 | + // SECURITY (FINDING-24): the fluentforms.com connect proxy sets its own OAuth `state`, so | |
| 21 | + // our nonce can't ride there. Carry it in url_base — the proxy must redirect back to | |
| 22 | + // url_base, so the nonce returns to us intact as ff_connect_nonce for CSRF verification. | |
| 23 | + $hash = wp_create_nonce('ff_stripe_connect'); | |
| 24 | + $urlBase = rawurlencode(admin_url('admin.php?page=fluent_forms_settings&ff_connect_nonce=' . $hash)); | |
| 21 | 25 | |
| 22 | 26 | $liveArgs = [ |
| 23 | - 'url_base' => rawurlencode(admin_url('admin.php?page=fluent_forms_settings')), | |
| 27 | + 'url_base' => $urlBase, | |
| 24 | 28 | 'mode' => 'live', |
| 25 | 29 | 'hash' => $hash |
| 26 | 30 | ]; |
| 27 | 31 | |
| 28 | 32 | $testArgs = [ |
| 29 | - 'url_base' => rawurlencode(admin_url('admin.php?page=fluent_forms_settings')), | |
| 33 | + 'url_base' => $urlBase, | |
| 30 | 34 | 'mode' => 'test', |
| 31 | 35 | 'hash' => $hash |
| 32 | 36 | ]; |
| 33 | 37 | |
| @@ -58,14 +62,32 @@ | ||
| 58 | 62 | } |
| 59 | 63 | |
| 60 | 64 | public static function verifyAuthorizeSuccess($data) |
| 61 | 65 | { |
| 66 | + // SECURITY (FINDING-24): require the settings-manager capability and a valid connect nonce | |
| 67 | + // before exchanging the code. Otherwise a settings manager could be tricked (CSRF) into | |
| 68 | + // loading a callback carrying the attacker's Stripe code, overwriting the site's live | |
| 69 | + // Stripe credentials so all future payments settle into the attacker's account. | |
| 70 | + if (!current_user_can('fluentform_settings_manager')) { | |
| 71 | + return; | |
| 72 | + } | |
| 73 | + // The nonce is carried in url_base (see getConnectConfig) and returns as ff_connect_nonce, | |
| 74 | + // not in the proxy-controlled `state`. | |
| 75 | + // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- this IS the nonce check | |
| 76 | + $connectNonce = isset($_GET['ff_connect_nonce']) ? sanitize_text_field(wp_unslash($_GET['ff_connect_nonce'])) : ''; | |
| 77 | + if (!$connectNonce || !wp_verify_nonce($connectNonce, 'ff_stripe_connect')) { | |
| 78 | + echo '<div class="ff_message ff_message_error">' . esc_html__('Invalid or expired Stripe Connect request. Please start the connection again.', 'fluentform') . '</div>'; | |
| 79 | + return; | |
| 80 | + } | |
| 81 | + | |
| 82 | + // SECURITY (FINDING-24 / PRO-10): enable TLS verification on the exchange that returns the | |
| 83 | + // live Stripe secret key so a network-position attacker cannot read or substitute it. | |
| 62 | 84 | $response = wp_remote_post(self::$connectBase . 'stripe-verify-code', [ |
| 63 | 85 | 'method' => 'POST', |
| 64 | 86 | 'timeout' => 45, |
| 65 | 87 | 'redirection' => 5, |
| 66 | 88 | 'httpversion' => '1.0', |
| 67 | - 'sslverify' => false, | |
| 89 | + 'sslverify' => true, | |
| 68 | 90 | 'blocking' => true, |
| 69 | 91 | 'headers' => array(), |
| 70 | 92 | 'body' => $data, |
| 71 | 93 | 'cookies' => array() |