Jquery .Net MVC-Can';不要阻止我的Ajax.begin被黑客攻击

Jquery .Net MVC-Can';不要阻止我的Ajax.begin被黑客攻击,jquery,ajax,asp.net-mvc,forms,Jquery,Ajax,Asp.net Mvc,Forms,我已经在我的.NETMVCWeb应用程序中构建了一个基于Ajax的表单,但我无法阻止被黑客攻击并被用来向我发送垃圾邮件 @using (Ajax.BeginForm("ContactSend", "Home", null, new AjaxOptions { OnBegin = "Contact.submitOnBegin", OnSuccess = "Contact.submitOnSuccess" }, new

我已经在我的.NETMVCWeb应用程序中构建了一个基于Ajax的表单,但我无法阻止被黑客攻击并被用来向我发送垃圾邮件

@using (Ajax.BeginForm("ContactSend", "Home", null, new AjaxOptions { OnBegin = "Contact.submitOnBegin", OnSuccess = "Contact.submitOnSuccess" }, new { id = "contact-form" }))
            {
                @Html.AntiForgeryToken()

                <input id="contact-cta" type="hidden" name="cta" value="@ViewBag.CTA" />

                <label class="form-label" for="nome">@Resources.Contact_Form_Name <span class="mandatory">*</span></label>
                <div class="form-input-ctn">
                    <input id="contact-name" type="text" name="name">
                    <div class="mandatory-error">@Resources.Contact_Form_Mandatory</div>
                </div>
                <label class="form-label" for="email">@Resources.Contact_Form_Email <span class="mandatory">*</span></label>
                <div class="form-input-ctn">
                    <input id="contact-email" type="text" name="email">
                    <div class="mandatory-error">@Resources.Contact_Form_Mandatory</div>
                    <div class="invalid-error">@Resources.Contact_Form_Invalid</div>
                </div>
                <label class="form-label" for="phone">@Resources.Contact_Form_Phone <span class="mandatory">*</span></label>
                <div class="form-input-ctn">
                    <input id="contact-phone" type="text" name="phone">
                    <div class="mandatory-error">@Resources.Contact_Form_Mandatory</div>
                    <div class="invalid-error">@Resources.Contact_Form_Invalid</div>
                </div>
                if (!string.IsNullOrEmpty(ViewBag.Subject))
                {
                    <label class="form-label" for="subject">@Resources.Contact_Form_Subject</label>
                    <div class="form-input-ctn">
                        <input id="contact-subject" type="text" name="subject" value="@ViewBag.Subject">
                        <div class="mandatory-error">@Resources.Contact_Form_Mandatory</div>
                    </div>
                }
                <label class="form-label" for="message">@Resources.Contact_Form_Message <span class="mandatory">*</span></label>
                <div class="form-input-ctn">
                    <textarea id="contact-message" class="form-textarea" name="message">@ViewBag.Message</textarea>
                    <div class="mandatory-error message-mandatory-error">@Resources.Contact_Form_Mandatory</div>
                </div>
                <label class="form-label"><span class="mandatory">*</span> @Resources.Contact_Form_Mandatory</label>
                <div class="form-input-ctn">
                    <div id="contact-recaptcha-mandatory-error" class="recaptcha-mandatory">@Resources.Contact_Form_Mandatory</div>
                    <div id="contact-recaptcha" class="g-recaptcha" data-callback="reCaptchaOnValidCallback"></div>
                </div>
                <br />
                <input id="contact-submit-btn" class="form-submit" type="submit" value="@Resources.Contact_Form_Send_Button" data-sending-message="@Resources.Contact_Form_Sending_Button">
            }
在isFormValid函数中,我对每个输入执行所有测试:

var _isFormValid = function () {

    // Reset
    isFocusOn = false;
    isFormValid = true;

    // Name
    if ($contactName.val() == "") {
        _showErrorMessage($contactName, contactErrorMandatoryCls);
    }
 
    // Email
    if ($contactEmail.val() == "") {
        _showErrorMessage($contactEmail, contactErrorMandatoryCls);
    }
    else if (!_isEmailValid()) {
        _showErrorMessage($contactEmail, contactErrorInvalidCls);
    }

    // Phone
    if ($contactPhone.val() == "") {
        _showErrorMessage($contactPhone, contactErrorMandatoryCls);
    }
    else if (!_isPhoneValid()) {
        _showErrorMessage($contactPhone, contactErrorInvalidCls);
    }

    // Message
    if ($contactMessage.val() == "") {
        _showErrorMessage($contactMessage, contactErrorMandatoryCls);
    }

    // reCaptcha
    var reCaptchaResponse = grecaptcha.getResponse();

    if (reCaptchaResponse.length == 0) {
        isFormValid = false;
        $("#contact-recaptcha-mandatory-error").addClass(contactErrorRecaptchaMandatoryCls);
    }
};
var _reCaptchaRender = function () {
    grecaptcha.render('contact-recaptcha', {
        'sitekey': 'XXX'
    });
};
var _reCaptchaValid = function () {
    $contactRecaptchaMandatoryError.removeClass(contactErrorRecaptchaMandatoryCls);
};

var _showErrorMessage = function (el, msg) {
    el.addClass(contactErrorMandatoryCls);
    el.parent().find("." + msg).fadeIn();

    if (!isFocusOn) {
        el.focus();
        isFocusOn = true;
    }
    isFormValid = false;
};
更奇怪的是,他们能够用reCaptcha对表单进行黑客攻击,还可以发送主题中的空值

在Contact.SubmitOnSuccess中,如果一切正常,我将进行提交:

var _submitOnSuccess = function (ajaxResult) {

    sentResultOk = ajaxResult.Success;

    $sentModal.load("/home/contactsent?cta=" + $contactCTA.val(), function () {
        if (sentResultOk == true) {
            $("#" + sentModalOkId).show();
        }
        else {
            $("#" + sentModalErrorId).show();
        }

        $sentModal.fadeIn(function () {
            $contactForm[0].reset();
            grecaptcha.reset();
            $submitBtn.removeClass("submitting");
            $submitBtn.prop('disabled', false);
            $submitBtn.val("Enviar");
        });
    });
我无法停止被黑客攻击,并被用来向我发送垃圾邮件

问题的核心反映在对该问题的评论中:

该表单在有效之前不会进入服务器端,从我在谷歌文档中看到的文档来看,我确信我只能从客户端进行验证

发生的情况是,您依赖于客户端告诉服务器一切都是有效的。所以任何黑客都可以。。。告诉服务器一切都是有效的

永远不要含蓄地相信来自客户的东西。始终验证

对于reCaptcha,Google会返回带有令牌的客户端代码,而您会这样做。请记住,此令牌的验证是在与处理表单相同的服务器端操作中完成的。毕竟,如果您首先让客户端将令牌发送到服务器并获得有效/无效响应,然后将表单发送到服务器,那么您就回到了与以前相同的位置。。。客户端只需将表单发送到服务器并声明它是有效的

在不深入示例的情况下,总体流程应该是:

  • 用户执行reCaptcha时,您的客户端代码将从Google获得一个令牌
  • 客户端代码在发布到服务器之前验证表单。(这不是一个安全步骤,这只是针对UX,因此用户不必等待服务器响应进行验证。)
  • 用户将表单发布到服务器。这包括所有表单数据和客户端代码从Google收到的reCaptcha令牌
  • 服务器端代码验证表单。这与上面的第2步基本相同,只是重复检查它,因为您不能假设数据是有效的
  • 服务器端代码使用Google验证reCaptcha令牌
  • 如果一切正常,请处理表单并继续应用程序流

  • 任何失败的步骤,你都会以你认为合适的方式处理这个错误。在大多数情况下,您只需返回一些错误响应给客户端,或者重定向到错误页面,或者返回AJAX错误并在客户端代码中优雅地处理它。您不需要假设任何错误都是由于黑客企图造成的。只是显示一个友好的错误,仅此而已。只要攻击者无法获得进一步的信息,错误说明对他们来说并不重要。

    在服务器端代码中,在哪里验证reCaptcha结果?我在这里只看到客户端代码。如果你依赖客户端告诉你它是否有效,那么这就解释了为什么它被黑客攻击。黑客只是告诉你它是有效的。你必须验证他们是否真的解决了验证码,而不仅仅是告诉你他们解决了验证码。客户端不需要执行JavaScript,甚至不需要在web浏览器中与之交互。他们可以向您的服务器发送他们喜欢的任何请求。验证该请求取决于服务器端代码。永远不要信任来自客户端的任何东西。基本上,当用户将表单提交到服务器时,该表单应该包含reCaptcha响应令牌。在服务器端代码中,您将验证表单(如果无效,则返回一个错误),然后使用Google验证令牌(如果无效,则返回一个错误),然后如果所有内容都有效,则处理表单。可能,也可能不是。如何处理任何给定的错误取决于您。也许客户端验证有一个bug,也许reCaptcha暂时存在连接问题,等等。您不需要假设用户正在做一些恶意的事情,只要适当地处理验证即可。因此,如果他们没有做恶意的事情,他们会看到一个有用的错误。如果他们做了一些恶意的事情,他们所看到的只是一个有用的错误。非常感谢@David!
    var _submitOnSuccess = function (ajaxResult) {
    
        sentResultOk = ajaxResult.Success;
    
        $sentModal.load("/home/contactsent?cta=" + $contactCTA.val(), function () {
            if (sentResultOk == true) {
                $("#" + sentModalOkId).show();
            }
            else {
                $("#" + sentModalErrorId).show();
            }
    
            $sentModal.fadeIn(function () {
                $contactForm[0].reset();
                grecaptcha.reset();
                $submitBtn.removeClass("submitting");
                $submitBtn.prop('disabled', false);
                $submitBtn.val("Enviar");
            });
        });