Commit 2873d817 authored by Jakob P's avatar Jakob P
Browse files

Resolve #3266305 "Captcha request replay"

parent e994d019
Loading
Loading
Loading
Loading
Loading
+1 −0
Changes for captcha.inc: 1 added line, 0 removed lines.
Original line number Diff line number Diff line
@@ -118,6 +118,7 @@ function _captcha_update_captcha_session($captcha_sid, $solution) {
    ->fields([
      'timestamp' => \Drupal::time()->getRequestTime(),
      'solution' => $solution,
      'status' => CaptchaConstants::CAPTCHA_STATUS_UNSOLVED,
    ])
    ->execute();
}
+11 −7
Changes for captcha.module: 11 added lines, 7 removed lines.
Original line number Diff line number Diff line
@@ -442,16 +442,19 @@ function _captcha_get_posted_captcha_info(array $element, FormStateInterface $fo
          ->select('captcha_sessions', 'cs')
          ->fields('cs', ['token'])
          ->condition('csid', $posted_captcha_sid)
          // Only for unsolved sessions to prevent replay:
          ->condition('status', CaptchaConstants::CAPTCHA_STATUS_UNSOLVED)
          ->execute()
          ->fetchField();

        // If we do have a CAPTCHA token mismatch then log it.
        try {
          if (($expected_captcha_token !== $posted_captcha_token) && empty($input['captcha_cacheable'])) {
            throw new \UnexpectedValueException('CAPTCHA session reuse attack detected.');
          }
        }
        catch (\Exception $e) {
        // A solved or unknown session returns FALSE from the query above, and
        // a POST that drops the captcha_token field sends NULL. Treat any
        // difference from the posted token, including these, as a reuse
        // attempt. Comparing against FALSE explicitly keeps this independent of
        // how the database layer represents a NULL token column.
        if ($expected_captcha_token === FALSE || $expected_captcha_token !== $posted_captcha_token) {
          // The captcha_cacheable flag only suppresses the log message.
          if (empty($input['captcha_cacheable'])) {
            \Drupal::logger('captcha')->debug(
              'CAPTCHA session reuse attack detected on %form_id. Posted CAPTCHA token: %posted_captcha_token. Expected captcha token: %expected_captcha_token',
              [
@@ -460,6 +463,7 @@ function _captcha_get_posted_captcha_info(array $element, FormStateInterface $fo
                '%posted_captcha_token' => var_export($posted_captcha_token, TRUE),
              ]
            );
          }
          // Invalidate the CAPTCHA session.
          $posted_captcha_sid = NULL;
        }