.Net MVC - 无法阻止我的 Ajax.BeginForm 被黑客入侵

Posted

技术标签:

【中文标题】.Net MVC - 无法阻止我的 Ajax.BeginForm 被黑客入侵【英文标题】:.Net MVC - Can't Stop my Ajax.BeginForm to be hacked 【发布时间】:2021-03-18 17:33:08 【问题描述】:

我已经在我的 .Net MVC Web 应用程序中构建了一个基于 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">
            

我还加入了 Google reCaptcha,但没有任何改变。

在我的 Contact.submitOnBegin jQuery 代码中,我进行了所有验证以避免空白值和无效值:

var _submitOnBegin = function () 

    _isFormValid();

    if (isFormValid) 
        $submitBtn.prop('disabled', true);

        var sendingMessage = $submitBtn.data("sending-message");
        $submitBtn.addClass("submitting");
        $submitBtn.val(sendingMessage);
     else 
        return false;
    
;

在 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 结果?我在这里只看到客户端代码。 如果您依靠客户端来告诉您它是否有效,那么这就解释了它被黑客入侵的原因。黑客只是告诉你它是有效的。你必须verify the user's response with Google 来验证他们确实解决了验证码,而不仅仅是告诉你他们已经解决了。 客户端不需要执行 javascript,甚至不需要在 Web 浏览器中与之交互。他们可以向您的服务器发送他们喜欢的任何请求。由您的 服务器端 代码来验证该请求。永远不要相信来自客户的任何东西。 基本上当用户向服务器提交表单时,该表单应该包含 reCaptcha 响应令牌。在服务器端代码中,您将验证表单(如果无效则返回错误),然后使用 Google 验证令牌(如果无效则返回错误),然后如果一切都有效,则处理表单。 也许,也许不是。如何处理任何给定的错误取决于您。也许客户端验证有一个错误,也许 reCaptcha 暂时存在连接问题等。您不需要假设用户正在做一些恶意的事情,只需适当地处理验证即可。因此,如果他们没有做恶意的事情,他们会看到一个有用的错误。如果他们正在做一些恶意的事情,他们看到的所有都是一个有用的错误。 【参考方案1】:

我无法停止被黑客入侵并被用来向我发送垃圾邮件

问题的核心体现在对问题的评论中:

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

发生的事情是您依赖客户端告诉服务器一切都是有效的。所以任何黑客都可以简单地......告诉服务器一切都是有效的。

永远不要暗中相信来自客户的东西。始终验证。

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

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

    用户执行 reCaptcha,您的客户端代码从 Google 获取令牌。 客户端代码在发布到服务器之前验证表单。 (这不是安全步骤,这仅适用于 UX,因此用户不必等待服务器响应进行验证。) 用户将表​​单发布到服务器。这包括所有表单数据您的客户端代码从 Google 收到的 reCaptcha 令牌。 服务器端代码验证表单。这与上述第 2 步的验证基本相同,只是再次检查它,因为您不能假设数据是有效的。 服务器端代码使用 Google 验证 reCaptcha 令牌。 如果一切顺利,请处理表单并继续申请流程。

任何失败的步骤,您都可以按照您认为合适的方式处理该错误。在大多数情况下,您只需将一些错误响应返回给客户端,要么通过重定向到错误页面,要么通过返回 AJAX 错误并在客户端代码中优雅地处理它。您无需假设任何错误是由于黑客攻击造成的。只是显示一个友好的错误,仅此而已。只要攻击者无法继续前进,错误内容对他们来说并不重要。

【讨论】:

以上是关于.Net MVC - 无法阻止我的 Ajax.BeginForm 被黑客入侵的主要内容,如果未能解决你的问题,请参考以下文章

SmtpClient.SendAsync 阻止我的 ASP.NET MVC 请求

如何通过更改 ASP.NET MVC 中的 Url 来阻止对控制器的访问?

从.net mvc api控制器下载角度应用程序中的文件时被CORS策略错误阻止

ASP.NET MVC 阻止当前请求的视图页面缓存OutputCache

在 ASP.NET 核心 MVC 项目上启用 CORS

CORS 不工作 ASP.Net MVC5