From patchwork Fri Sep 6 19:28:04 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Lukas Fleischer X-Patchwork-Id: 1213 Return-Path: Delivered-To: patchwork@archlinux.org Received: from apollo.archlinux.org (localhost [127.0.0.1]) by apollo.archlinux.org (Postfix) with ESMTP id DE4EE130B0494 for ; Fri, 6 Sep 2019 19:26:34 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on apollo X-Spam-Level: X-Spam-Status: No, score=-2.9 required=5.0 tests=DKIMWL_WL_HIGH=-0.001, DKIM_SIGNED=0.1,DKIM_VALID=-0.1,DKIM_VALID_AU=-0.1, LOCAL_FAKEBUSINESS=0.5,MAILING_LIST_MULTI=-1,RCVD_IN_DNSWL_MED=-2.3, SPF_HELO_NONE=0.001,T_DMARC_POLICY_NONE=0.01,WEIRD_QUOTING=0.001 autolearn=unavailable autolearn_force=no version=3.4.2 X-Spam-BL-Results: [127.0.9.2] [127.0.0.11] Received: from orion.archlinux.org (orion.archlinux.org [88.198.91.70]) by apollo.archlinux.org (Postfix) with ESMTPS for ; Fri, 6 Sep 2019 19:26:34 +0000 (UTC) Received: from orion.archlinux.org (localhost [127.0.0.1]) by orion.archlinux.org (Postfix) with ESMTP id 237C8153099863; Fri, 6 Sep 2019 19:26:33 +0000 (UTC) Received: from luna.archlinux.org (luna.archlinux.org [5.9.250.164]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange ECDHE (P-384) server-signature RSA-PSS (4096 bits)) (No client certificate requested) by orion.archlinux.org (Postfix) with ESMTPS; Fri, 6 Sep 2019 19:26:33 +0000 (UTC) Received: from luna.archlinux.org (luna.archlinux.org [127.0.0.1]) by luna.archlinux.org (Postfix) with ESMTP id 1169A2BD3A; Fri, 6 Sep 2019 19:26:33 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=archlinux.org; s=luna2; t=1567797993; bh=SWAqebgeYVBuASz0Tkbp4DmGFrKEJQetJBZdgryjrb4=; h=From:To:Subject:Date:List-Id:List-Unsubscribe:List-Archive: List-Post:List-Help:List-Subscribe; b=ZOxL6AXZt7kpe3akPENN7senD4WUD3d9w2N3aZNNyxY29weZFkxbjJRS4M8FD/+ba frl+uGT52mGXLqhZFapInBB2gKTlcR5nHMQCAax2htD52d4bEH/WbhEPMcpoUjqZVI YnhZkNVbeNHgbvCJT5TFNmjmJ/h8FqqMY475pl+s4hfaTG4KxnGvmcMrQ0dQl4pNLn pxZY9yuL0O0ltiyvuT2uFLTniXZWgC3UFUteZgdMLnQ4AM/lplPEXy3HnZiw/s4SzE DGhVsFVB2JQ9bfbst2XK99HtjDbJxdY4PdAih4AOugGuuhuVtB4dkMuwc05eTfwm4Z +n26s8kHclss+Fgqv78f0IS8S1tj0RZMXyMUAVWgMvuWxcUPT7wb1ELVHTCuu+ork8 SBWSelrq/IEFgd3glhqpIwo2avGnDyMIzdfSWGjryryJ+qbQuBLM47hsazykixi2FT l7c/8ZVBU+Bji9YgWnuiSuOpsyTsCdZu3BnHQv0wsobAo3AMfSVN4MmPwAjQTzl31m gYHBvSVoCEl6Q6Zq1tctIaKFgIQ526xG4bzoWsIL+929xmyANUVgCaVuA3j92p+qxj xOH2zVAonhpa5WLZubMqTVZPNqKQ3c8rq9cHhQWuhP7xAR1v+09/R9qMMPvBUmnfd2 HeJo5VFD53n/HsKPJGjzWJHs= Received: from luna.archlinux.org (luna.archlinux.org [127.0.0.1]) by luna.archlinux.org (Postfix) with ESMTP id 5BDE72B35D for ; Fri, 6 Sep 2019 19:26:30 +0000 (UTC) Received: from orion.archlinux.org (orion.archlinux.org [88.198.91.70]) by luna.archlinux.org (Postfix) with ESMTPS for ; Fri, 6 Sep 2019 19:26:30 +0000 (UTC) Received: from orion.archlinux.org (localhost [127.0.0.1]) by orion.archlinux.org (Postfix) with ESMTP id 5D3E3153099861 for ; Fri, 6 Sep 2019 19:26:29 +0000 (UTC) Received: from localhost (wn-campus-nat-129-97-124-59.dynamic.uwaterloo.ca [129.97.124.59]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange ECDHE (P-384) server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) (Authenticated sender: lfleischer) by orion.archlinux.org (Postfix) with ESMTPSA id F22B5153099860 for ; Fri, 6 Sep 2019 19:26:28 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=archlinux.org; s=orion; t=1567797989; bh=SWAqebgeYVBuASz0Tkbp4DmGFrKEJQetJBZdgryjrb4=; h=From:To:Subject:Date; b=BiQkcIP9FiOqweuyMhxnvuWpYz3faDWOTUPiWfZNCsLoCdQS+76Kw83Sle1HEAbdl GoJjInI7F7GMFTQR4WjzYz/J8qH6H7FvkUBierSrT0Dnw+z3pfI35VstRa6b/VdtRd Oj5t/iMQEOlrO90iLUEOvXxBUwxM9Aivl8cY4OdYjkX9RILbDUjKLMmQBMsXMMQu8R P1DxBDKzsZ2joU/5XTfnGx8sI7gch2Pm3M6RXUpKh3ogIWL8s4MQCNurmL8WQlfeOF y28d9yQUCLozXDipW94tjin1pSro/j/BhLwBkiw2v0Cca/jOFb79ncrBg4ZswMWDnq ZxgIjVado/oVG+StOtcnjfSgTIOkvMrAqG5xjhn+r8Dyr2sZSIrP0srNhsXKKaN6as BaYLhuimNMGgV3NKoxbdagGcnz+N1hyzcbe4XasqQ3I3Y5ZZ0GEhNq20FI0RY3YaV1 DHZQgWvntcOSDI+GRp+IkFaqzYz/Mkxkl4A3KQgT43pLP1bdeqRLvP7WKvYLp95dzD TkDirAST8yKLO5KquzcFvmbINtBymo0FD2Xke4o/nAUFv+L/rqsU5uy/8viItvTdYR BsvuAlH4Mq1ZljlKYTqlBiS7qa04z2NIz1F/37PKqKcDYLNiNSUlOL8V1CE33kfMAP 0Tq3Jx7zv+ZnrUo6lGDCdM9g= From: Lukas Fleischer To: aur-dev@archlinux.org Subject: [PATCH] Add a simple CAPTCHA to the sign up form Date: Fri, 6 Sep 2019 15:28:04 -0400 Message-Id: <20190906192804.64231-1-lfleischer@archlinux.org> X-Mailer: git-send-email 2.23.0 MIME-Version: 1.0 X-BeenThere: aur-dev@archlinux.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: "Arch User Repository \(AUR\) Development" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: aur-dev-bounces@archlinux.org Sender: "aur-dev" Add a CAPTCHA to protect against automated account creation. The CAPTCHA changes whenever three new accounts are registered. Signed-off-by: Lukas Fleischer --- This is a first attempt to stop the recent wave of spammers. Other counter-measures will be implemented if it is not effective. web/html/register.php | 14 +++++- web/lib/acctfuncs.inc.php | 74 +++++++++++++++++++++++++++++- web/template/account_edit_form.php | 11 +++++ 3 files changed, 95 insertions(+), 4 deletions(-) diff --git a/web/html/register.php b/web/html/register.php index 368999a..a426482 100644 --- a/web/html/register.php +++ b/web/html/register.php @@ -36,7 +36,12 @@ if (in_request("Action") == "NewAccount") { 0, in_request("CN"), in_request("UN"), - in_request("ON")); + in_request("ON"), + 0, + "", + in_request("captcha_salt"), + in_request("captcha"), + ); print $message; @@ -59,7 +64,12 @@ if (in_request("Action") == "NewAccount") { 0, in_request("CN"), in_request("UN"), - in_request("ON")); + in_request("ON"), + 0, + "", + in_request("captcha_salt"), + in_request("captcha") + ); } } else { print '

' . __("Use this form to create an account.") . '

'; diff --git a/web/lib/acctfuncs.inc.php b/web/lib/acctfuncs.inc.php index dc44484..b0513c6 100644 --- a/web/lib/acctfuncs.inc.php +++ b/web/lib/acctfuncs.inc.php @@ -62,17 +62,25 @@ function html_format_pgp_fingerprint($fingerprint) { * @param string $ON Whether to notify of ownership changes * @param string $UID The user ID of the displayed user * @param string $N The username as present in the database + * @param string $captcha_salt The salt used for the CAPTCHA. + * @param string $captcha The CAPTCHA answer. * * @return void */ function display_account_form($A,$U="",$T="",$S="",$E="",$H="",$P="",$C="",$R="", - $L="",$TZ="",$HP="",$I="",$K="",$PK="",$J="",$CN="",$UN="",$ON="",$UID=0,$N="") { + $L="",$TZ="",$HP="",$I="",$K="",$PK="",$J="",$CN="",$UN="",$ON="",$UID=0,$N="",$captcha_salt="",$captcha="") { global $SUPPORTED_LANGS; if ($TZ == "") { $TZ = config_get("options", "default_timezone"); } + if ($captcha_salt != get_captcha_salt()) { + $captcha_salt = get_captcha_salt(); + $captcha = ""; + } + $captcha_challenge = get_captcha_challenge($captcha_salt); + include("account_edit_form.php"); return; } @@ -103,11 +111,13 @@ function display_account_form($A,$U="",$T="",$S="",$E="",$H="",$P="",$C="",$R="" * @param string $ON Whether to notify of ownership changes * @param string $UID The user ID of the modified account * @param string $N The username as present in the database + * @param string $captcha_salt The salt used for the CAPTCHA. + * @param string $captcha The CAPTCHA answer. * * @return array Boolean indicating success and message to be printed */ function process_account_form($TYPE,$A,$U="",$T="",$S="",$E="",$H="",$P="",$C="", - $R="",$L="",$TZ="",$HP="",$I="",$K="",$PK="",$J="",$CN="",$UN="",$ON="",$UID=0,$N="") { + $R="",$L="",$TZ="",$HP="",$I="",$K="",$PK="",$J="",$CN="",$UN="",$ON="",$UID=0,$N="",$captcha_salt="",$captcha="") { global $SUPPORTED_LANGS; $error = ''; @@ -269,6 +279,18 @@ function process_account_form($TYPE,$A,$U="",$T="",$S="",$E="",$H="",$P="",$C="" } } + if (!$error && $TYPE == "new" && empty($captcha)) { + $error = __("The CAPTCHA is missing."); + } + + if (!$error && $TYPE == "new" && $captcha_salt != get_captcha_salt()) { + $error = __("This CAPTCHA has expired. Please try again."); + } + + if (!$error && $TYPE == "new" && $captcha != get_captcha_answer($captcha_salt)) { + $error = __("The entered CAPTCHA answer is invalid."); + } + if ($error) { $message = "
  • ".$error."
\n"; return array(false, $message); @@ -1445,3 +1467,51 @@ function account_comments_count($uid) { $result = $dbh->query($q); return $result->fetchColumn(); } + +/* + * Compute the CAPTCHA salt. The salt changes based on the number of registered + * users. This ensures that new users always use a different salt. + * + * @return string The current salt. + */ +function get_captcha_salt() { + $dbh = DB::connect(); + $q = "SELECT count(*) FROM Users"; + $result = $dbh->query($q); + $user_count = $result->fetchColumn(); + return 'aurweb-' . floor($user_count / 3); +} + +/* + * Return the CAPTCHA challenge for a given salt. + * + * @param string $salt The salt to be used for the CAPTCHA computation. + * + * @return string The challenge as a string. + */ +function get_captcha_challenge($salt) { + $token = substr(md5($salt), 0, 3); + return "pacman -V|sed -r 's#[0-9]+#" . $token . "#g'|md5sum|cut -c1-6"; +} + +/* + * Compute CAPTCHA answer for a given salt. + * + * @param string $salt The salt to be used for the CAPTCHA computation. + * + * @return string The correct answer as a string. + */ +function get_captcha_answer($salt) { + $token = substr(md5($salt), 0, 3); + $text = << + +
+ +

+ + () + +

+
+ +