Currently, when captcha's are persisted in a user session, and the user has solved a captcha, and gets to the same page (e.g. contact form), the page will be cached after that. Which results in the captcha not being presented to other untrusted users.

To solve this, I think the code in captcha_form_alter that reads:

  if (!user_access('skip captcha challenges')) {
    // Visitor does not have permission to skip the captcha challenge

    // Do not present captcha if not captcha-persistent and user has already solved a captcha for this form
    if(!variable_get('captcha_persistence', TRUE) && ($_SESSION['captcha'][$form_id]['success'] === TRUE)) {
      return;
    }

    // Get captcha type and module for this form. Return if no captcha was set.
    $result = db_query("SELECT module, type FROM {captcha_points} WHERE form_id = '%s'", $form_id);
    if (!$result) {
      return;
    }
    $captcha_point = db_fetch_object($result);
    if (!$captcha_point->type) {
      return;
    }

Should be changed to something like:

  if (!user_access('skip captcha challenges')) {
    // Visitor does not have permission to skip the captcha challenge

    // Get captcha type and module for this form. Return if no captcha was set.
    $result = db_query("SELECT module, type FROM {captcha_points} WHERE form_id = '%s'", $form_id);
    if (!$result) {
      return;
    }
    $captcha_point = db_fetch_object($result);
    if (!$captcha_point->type) {
      return;
    }

    // Do not present captcha if not captcha-persistent and user has already solved a captcha for this form
    if(!variable_get('captcha_persistence', TRUE) && ($_SESSION['captcha'][$form_id]['success'] === TRUE)) {
      global $conf;
      $conf['cache'] = FALSE;
      return;
    }

I.e., I moved the check for persistent captcha to after the other checks, and made the page non-cacheable if the only reason the captcha is not shown is the fact that the user has already solved a captcha.

CommentFileSizeAuthor
#3 caching_and_persistence.patch2.33 KBsoxofaan

Comments

soxofaan’s picture

I don't see the problem and I think the CAPTCHA module behaves correctly.

I guess this is another case of the "persistent captcha" widget giving an ambiguous message. The expected behavior should be more obvious with the patch from http://drupal.org/node/168717 .

gjxl’s picture

There is no error message. There just is no captcha anymore on forms that should have one.
To reproduce:
1) Enable page caching
2) Set up a general contact form (or any other form that does not by itself invalidate the cache after a submit, ou will nt be able to reproduce this bug with e.g. a comment form).
3) Enable captcha for the contact form for anonymous users (I use reCAPTCHA).
4) Set captcha's to persist (i.e. a user has to only enter a captcha once for the form).
5) As anonymous user, fill and submit the form.
6) As anonymous user, in the same session, reload the form page. The form now gets cached, because, as you can see in the original code, captcha_form_alter is left by a return statement before caching for the form is disabled.
7) Close browser and restart or start a different browser or use a different computer to get a new annymous user session.
8) As anonymous user, go to the form page. It now doesn't show a captcha, because the page is returned from the cache and the cached page doesn't have a captcha.

soxofaan’s picture

Status: Active » Needs review
StatusFileSize
new2.33 KB

Ok, now I understand what you mean.
This is indeed a bug.
Patch in attachment should solve this.

robloach’s picture

Status: Needs review » Patch (to be ported)

I believe this conflicts with this issue and we should move it into the submitted patch there.

soxofaan’s picture

I believe this conflicts with this issue and we should move it into the submitted patch there.

done: http://drupal.org/node/168717#comment-306213

soxofaan’s picture

Status: Patch (to be ported) » Fixed
Anonymous’s picture

Status: Fixed » Closed (fixed)