/** * Renders the captcha image * * @return string empty string (the image is sent here) */ public function render() { // Avoid Brute Force Attacks: if (!$this->word->getAttempts()) { $this->word->setAttempts(1); } else { $this->word->setAttempts($this->word->getAttempts() + 1); // if more than ($this->settings['maxAttempts']) refreshes, block further refreshes // can be negated by connecting with new session id // could get round this by storing num attempts in database against IP // could get round that by connecting with different IP (eg, using proxy servers) // in short, there's little point trying to avoid brute forcing // the best way to protect against BF attacks is to ensure the dictionary is not // accessible via the web or use random string option if ($this->word->getAttempts() > $this->settings['maxAttempts']) { $this->word->setWordHash(''); $this->word->setWordCypher(array()); $this->word->setHashFunction(''); // Get an instance of the word repository $objectManager = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance('TYPO3\\CMS\\Extbase\\Object\\ObjectManager'); $wordRepository = $objectManager->get('SJBR\\SrFreecap\\Domain\\Repository\\WordRepository'); // Reset the word $wordRepository->setWord($this->word); $string = \TYPO3\CMS\Extbase\Utility\LocalizationUtility::translate('max_attempts', $this->extensionName); $font = 5; $width = imagefontwidth($font) * strlen($string); $height = imagefontheight($font); $image = ImageCreate($width + 2, $height + 20); $background = ImageColorAllocate($image, 255, 255, 255); ImageColorTransparent($image, $background); $red = ImageColorAllocate($image, 255, 0, 0); ImageString($image, $font, 1, 10, $string, $red); \SJBR\SrFreecap\Utility\ImageContentUtility::sendImage($image, $this->settings['imageFormat']); ImageDestroy($image); // Return an empty string return ''; } } // Get random word $word = \SJBR\SrFreecap\Utility\RandomContentUtility::getRandomWord($this->settings['useWordsList'], $this->settings['wordsListLocation'], $this->settings['generateNumbers'], $this->settings['maxWordLength']); // Save hash of word for comparison // using hash so that if there's an insecurity elsewhere (eg on the form processor), // an attacker could only get the hash // also, shared servers usually give all users access to the session files // echo `ls /tmp`; and echo `more /tmp/someone_elses_session_file`; usually work // so even if your site is 100% secure, someone else's site on your server might not be // hence, even if attackers can read the session file, they can't get the freeCap word // (though most hashes are easy to brute force for simple strings) $this->word->setWordHash(md5($word)); // We use a simple encrypt to prevent the session from being exposed if ($this->settings['accessibleOutput']) { $this->word->setWordCypher(\SJBR\SrFreecap\Utility\EncryptionUtility::encrypt($word)); } // Build the image $image = $this->buildImage($word, $this->settings['imageWidth'], $this->settings['imageHeight'], $this->settings['backgroundType']); // Send the image \SJBR\SrFreecap\Utility\ImageContentUtility::sendImage($image, $this->settings['imageFormat']); // Cleanup ImageDestroy($image); // Return an empty string return ''; }
/** * Merge captcha image with background * * @param int $width: width of the image in pixels * @param int $height: width of the image in pixels * @param string $captchaImage: a GD image identifier * @param string $backgroundImage: a GD image identifier * @param string $backgroundType (see constants) * @param int $mergeType: 0 - Background over captcha, 1 - Captcha over background (see constants) * @param int $backgroundFadePercentage: fading factor for background * @return string GD image identifier of merged image */ public static function mergeCaptchaWithBackground($width, $height, $captchaImage, $backgroundImage, $backgroundType, $mergeType) { if ($backgroundType != self::BACKGROUND_TYPE_TRANSPARENT) { // How faded should the background be? (100=totally gone, 0=bright as the day) // to test how much protection the bg noise gives, take a screenshot of the freeCap image // and take it into a photo editor. play with contrast and brightness. // If you can remove most of the background, then it's not a good enough percentage switch ($backgroundType) { case self::BACKGROUND_TYPE_WHITE_WITH_GRID: case self::BACKGROUND_TYPE_WHITE_WITH_SQUIGGLES: $backgroundFadePercentage = 65; break; case self::BACKGROUND_TYPE_MORPHED_IMAGE_BLOCKS: $backgroundFadePercentage = 50; break; } // Slightly randomize the background fade $backgroundFadePercentage += RandomContentUtility::getRandomNumberInRange(-2, 2); // Fade background if ($backgroundType != self::BACKGROUND_TYPE_MORPHED_IMAGE_BLOCKS) { $tempImage = ImageCreateTrueColor($width, $height); $white = ImageColorAllocate($tempImage, 255, 255, 255); ImageFill($tempImage, 0, 0, $white); ImageCopyMerge($backgroundImage, $tempImage, 0, 0, 0, 0, $width, $height, $backgroundFadePercentage); ImageDestroy($tempImage); $colorFadePercentage = 50; } else { $colorFadePercentage = $backgroundFadePercentage; } // Merge background image with CAPTCHA image to create smooth background if ($mergeType == self::MERGE_CAPTCHA_OVER_BACKGROUND) { // Might want to not blur if using this method, otherwise leaves white-ish border around each letter ImageCopyMerge($backgroundImage, $captchaImage, 0, 0, 0, 0, $width, $height, 100); ImageCopy($captchaImage, $backgroundImage, 0, 0, 0, 0, $width, $height); } else { // Background over captcha ImageCopyMerge($captchaImage, $backgroundImage, 0, 0, 0, 0, $width, $height, $colorFadePercentage); } } return $captchaImage; }