PluginProbe
Fluent Forms – Customizable Contact Forms, Survey, Quiz, & Conversational Form Builder / 6.2.15
Fluent Forms – Customizable Contact Forms, Survey, Quiz, & Conversational Form Builder v6.2.15
6.2.15 6.2.14 6.2.13 6.2.12 6.2.10 6.2.11 6.2.9 6.2.8 6.2.7 6.2.6 6.2.5 6.2.4 6.2.3 6.2.2 3.6.22 3.6.31 3.6.40 3.6.41 3.6.42 3.6.50 3.6.51 3.6.60 3.6.61 3.6.62 3.6.64 All 197 releases
← All changes | app/Modules/Form/HoneyPot.php +64 -16 3.6.42 → 6.2.15 View file →
@@ -1,12 +1,12 @@
1 1 <?php
2 2
3 3 namespace FluentForm\App\Modules\Form;
4 4
5 +use FluentForm\App\Helpers\Helper;
5 6 use FluentForm\Framework\Foundation\Application;
6 7 use FluentForm\Framework\Helpers\ArrayHelper;
7 8
8 -
9 9 class HoneyPot
10 10 {
11 11 private $app;
12 12
@@ -19,29 +19,58 @@
19 19 {
20 20 if (!$this->isEnabled($form->id)) {
21 21 return;
22 22 }
23 +
24 + $fieldName = $this->getFieldName($form->id);
25 + $fieldId = 'ff_' . $form->id . '_item_sf' ;
26 + $labels = ['Newsletter', 'Updates', 'Contact', 'Subscribe', 'Notify'];
27 + $randomLabel = $labels[array_rand($labels)];
23 28 ?>
24 - <span style="display: none !important;"><input type="checkbox" name="<?php echo $this->getFieldName($form->id); ?>" value="1"
25 - style="display:none !important;" tabindex="-1"></span>
29 + <div
30 + style="display: none!important; position: absolute!important; transform: translateX(1000%)!important;"
31 + class="ff-el-group ff-hpsf-container"
32 + >
33 + <div class="ff-el-input--label asterisk-right">
34 + <label for="<?php echo esc_attr($fieldId); ?>" aria-label="<?php echo esc_attr($randomLabel); ?>">
35 + <?php echo esc_html($randomLabel); ?>
36 + </label>
37 + </div>
38 + <div class="ff-el-input--content">
39 + <input type="text"
40 + name="<?php echo esc_attr($fieldName); ?>"
41 + class="ff-el-form-control"
42 + id="<?php echo esc_attr($fieldId); ?>"
43 + />
44 + </div>
45 + </div>
26 46 <?php
27 47 }
28 48
29 49 public function verify($insertData, $requestData, $formId)
30 50 {
51 + // SECURITY (FINDING-25): do NOT skip the check for conversational forms based on the
52 + // client-supplied isFFConversational flag. The conversational renderer now injects the
53 + // honeypot field (empty) into the submission (getConversationalHoneypotInput via
54 + // extra_inputs), so the "present and empty" check passes for legitimate conversational
55 + // submissions and the control can no longer be bypassed with a single flag.
31 56 if (!$this->isEnabled($formId)) {
32 57 return;
33 58 }
34 59
35 - // Now verify
36 - if (ArrayHelper::get($requestData, $this->getFieldName($formId))) {
37 - // It's a bot! Block him
38 - wp_send_json(
39 - array(
40 - 'errors' => 'Sorry! You can not submit this form at this moment!'
41 - ), 422);
60 + $honeyPotName = $this->getFieldName($formId);
61 +
62 + if (
63 + !ArrayHelper::exists($requestData, $honeyPotName) ||
64 + !empty(ArrayHelper::get($requestData, $honeyPotName))
65 + ) {
66 + $message = apply_filters(
67 + 'fluentform/honeypot_spam_message',
68 + __('Sorry! You can not submit this form at this moment!', 'fluentform'),
69 + $formId
70 + );
71 + wp_send_json(['errors' => $message], 422);
42 72 }
43 -
44 73 return;
45 74 }
46 75
47 76 public function isEnabled($formId = false)
@@ -46,14 +75,33 @@
46 75
47 76 public function isEnabled($formId = false)
48 77 {
49 78 $option = get_option('_fluentform_global_form_settings');
50 - $status = ArrayHelper::get($option, 'misc.honeypotStatus') == 'yes';
51 - return apply_filters('fluentform_honeypot_status', $status, $formId);
79 + $status = 'yes' == ArrayHelper::get($option, 'misc.honeypotStatus');
80 + return apply_filters('fluentform/honeypot_status', $status, $formId);
52 81 }
53 82
83 + /**
84 + * SECURITY (FINDING-25): the conversational form is a JS app that never renders the DOM
85 + * honeypot field, so verify() previously had to be skipped for it (via the client-controlled
86 + * isFFConversational flag). Return the honeypot field pre-filled EMPTY so the conversational
87 + * JS carries it in the submission and the "present and empty" check passes for a legitimate
88 + * submission while the control is enforced server-side rather than bypassable by a flag.
89 + *
90 + * @param int $formId
91 + * @return array
92 + */
93 + public function getConversationalHoneypotInput($formId)
94 + {
95 + if (!$this->isEnabled($formId)) {
96 + return [];
97 + }
98 +
99 + return [$this->getFieldName($formId) => ''];
100 + }
101 +
54 102 private function getFieldName($formId)
55 103 {
56 - return apply_filters('fluentform_honeypot_name', 'item__' . $formId . '__fluent_checkme_', $formId);
104 + $honeyPotName = 'item_' . $formId . '__fluent_sf';
105 + return apply_filters('fluentform/honeypot_name', $honeyPotName, $formId);
57 106 }
58 -
59 -}
107 +}