首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >提升网站联系表格的安全性和代码质量

提升网站联系表格的安全性和代码质量
EN

Code Review用户
提问于 2022-02-05 23:00:28
回答 1查看 119关注 0票数 0

我有一个简单的网站联系表格创建于2017年。

该表单是用PHP、PHPMailer、jQuery、HTML和CSS开发的。

我想确保代码符合现代标准和安全。

我还想从PHP切换到AJAX以获得成功和错误消息传递(以避免页面刷新)。但这件事可能超出了我的范围,所以我就不谈这个问题了。

这是一个详细的分类:

(1)表单将站点用户的消息发送给站点管理人员。

(2)结构采用HTML,表示采用CSS。

(3)用户输入通过SMTP使用PHPMailer发送。

(4)为用户提供一个带有字符计数器的textarea框,供用户提交消息。

(5)如果超过字符计数,jQuery脚本将阻止表单被提交。

(6)安装Google reCAPTCHA以减少垃圾邮件。

(7)在客户端使用HTML和标准浏览器函数进行用户输入验证。

(8) PHP函数用于服务器端的用户输入验证和清理。

(9) PHP处理发送给用户的成功和错误消息。

据我所知,这个表格很好用。

我想在这里寻求一些指导:

  • SMTP/PHPMailer设置需要在代码中嵌入用户名和密码。有没有更安全的方法?
  • 对提高本代码的整体质量和效率有何建议?

谢谢。

HTML,CSS & jQuery

代码语言:javascript
运行
复制
// text area character counter
// displays total characters allowed
// displays warning at defined count (currently 150)
// disables submit button when < 0
// max characters that can be input set by maxlength attribute in HTML
(function($) {

    $.fn.charCount = function(submit, options){

        this.submit = submit;

        // default configuration properties
        var defaults = {    
            allowed: 1250,      
            warning: 150,
            css: 'counter',
            counterElement: 'span',
            cssWarning: 'warning',
            cssExceeded: 'exceeded',
            counterText: ''
        }; 
    
        var options = $.extend(defaults, options); 

        function calculate(obj,submit){
        
            submit.attr("disabled", "disabled");

            var count = $(obj).val().length;
            var available = options.allowed - count;
            if(available <= options.warning && available >= 0){
                $(obj).next().addClass(options.cssWarning);
            } else {
                $(obj).next().removeClass(options.cssWarning);
            }
            if(available < 0){
                $(obj).next().addClass(options.cssExceeded);
            } else {
                $(obj).next().removeClass(options.cssExceeded);
                submit.removeAttr("disabled");
            }
            
            $(obj).next().html(options.counterText + available);
        };
        
        this.each(function() {              
            $(this).after('<'+ options.counterElement +' class="' + options.css + '">'+ options.counterText +'');
            
            calculate(this, submit);

            $(this).keyup(function(){calculate(this,submit)});
            $(this).change(function(){calculate(this,submit)});
        });

    };

})(jQuery);

$(document).ready(function(){   
    $("#comments").charCount($("#submit"));
});
代码语言:javascript
运行
复制
#contact-form {
    display: flex;
    flex-direction: column;
    width: 50%;
    font: 1rem/1.5 arial, helvetica, sans-serif;
    margin: 0 auto 1em !important;
}
#contact-form > div {
    display: flex;
    flex-direction: column;
    margin-bottom: 10px;
}
#contact-form > div:not(.send-fail-notice):not(#counter-container) {
    width: 70%;
}

#contact-form > .ad2 { align-self: flex-start; }

/* label formatting */
#contact-form > div > label {
    margin-bottom: 2px;
}

/* asterisk formatting */
#contact-form > div > label > span {
    color: #f00;
    font-size: 1.5em;
    line-height: 1;
}

/* input field formatting */
#contact-form input,
#contact-form textarea {
    border: 1px solid #ccc;
    background: #fcfcfc;
    padding: 2px 5px;
    resize: none;
    font-family: arial, helvetica, sans-serif;    
}
#contact-form input:focus,
#contact-form textarea:focus  {
    border: 1px solid #777;
}

/*  textarea and character counter */
#contact-form > #counter-container { }

#contact-form > #counter-container > .counter {
    font-size: 1.5em;
    color: #ccc;
}
#contact-form > #counter-container .warning {
    color: orange;
}
#contact-form > #counter-container .warning::after {
    content: " approaching limit";
    font-size: 1em;
}
#contact-form > #counter-container .exceeded {
    color: red;
}
#contact-form > #counter-container .exceeded::after {
    content: " form won't submit";
    font-size: 1em;
}

/*  submit button formatting */
#contact-form > button {
    align-self: flex-start;
    padding: 5px 15px;
    cursor: pointer;
    border: 1px solid #ccc;
    background-color: #f1f1f1;
    background-image: linear-gradient(#f1f1f1, #fafafa);
}

#contact-form > button:hover {
    background-image: linear-gradient(#e1e1e1, #eaeaea);
}

/* form errors */
.send-fail-notice {
    flex-direction: row !important;
    align-items: center;
    padding: 15px;    
    background-color: #ffc; 
    border: 2px solid red;    
}

.send-fail-notice > span {
    color: #e13a3e;
    font-weight: bold;
    margin-left: 10px;
}
代码语言:javascript
运行
复制
    Name *
    
  

  
    E-mail *
    
  

  
    Subject
    
  

  
    Message *
    <?php echo $comments ?>
  

  

  Send Message

PHP

代码语言:javascript
运行
复制
// CONTACT FORM PROCESSING SCRIPT

// set default values (prevents undefined variable error)
$send_fail_one = null;
$send_fail_two = null;
$name          = null;
$email         = null;
$subject       = null;
$comments      = null;

// Load PHPMailer (v 6.5.3 02/02/2022)
// Import PHPMailer classes into the global namespace
// These must be at the top of your script, not inside a function
use PHPMailer\PHPMailer\PHPMailer;
use PHPMailer\PHPMailer\SMTP;
use PHPMailer\PHPMailer\Exception;

if ($_SERVER["REQUEST_METHOD"] == "POST") {

// Load PHPMailer
require 'PHPMailer/src/Exception.php';
require 'PHPMailer/src/PHPMailer.php';
require 'PHPMailer/src/SMTP.php';

// Create new PHPMailer instance; passing `true` enables exceptions
$mail = new PHPMailer(true);
$mail->CharSet = "UTF-8";

// SMTP Debugging
//SMTP::DEBUG_OFF = off (for production use)
//SMTP::DEBUG_CLIENT = client messages
//SMTP::DEBUG_SERVER = client and server messages
$mail->SMTPDebug = SMTP::DEBUG_SERVER;  
$mail->Debugoutput = 'html';

// SMTP settings
$mail->isSMTP();  
$mail->Host = 'smtp.gmail.com';
$mail->SMTPAuth = true;
$mail->SMTPSecure = PHPMailer::ENCRYPTION_SMTPS;
$mail->Port = 465;
$mail->Username = 'demo-purposes@yahoo.com'; 
$mail->Password = 'FakePasswordForDemoPurposes';
$mail->setFrom('demo-purposes@yahoo.com');
$mail->addAddress('demo-purposes@yahoo.com');
$mail->isHTML(true);

// Sanitize & Validate Input
// Trim all $_POST values
/* Using FILTER_SANITIZE_SPECIAL_CHARS as opposed to FILTER_SANITIZE_STRING because:
 * (1) FILTER_SANITIZE_SPECIAL_CHARS will disarm code but still display it.
 * (2) FILTER_SANITIZE_STRING removes all code, leaving no trace, and all code input is lost (e.g., anything with brackets is lost).
 * Hence, with (1) we can identify users trying to submit code.
 * Exception: textarea field ('comments') uses FILTER_SANITIZE_STRING because otherwise nl2br (keep line breaks) doesn't work. */
$name = trim(filter_input(INPUT_POST, 'name', FILTER_SANITIZE_SPECIAL_CHARS));
$email = filter_input(INPUT_POST, 'email', FILTER_SANITIZE_EMAIL);
$subject = trim(filter_input(INPUT_POST, 'subject', FILTER_SANITIZE_SPECIAL_CHARS));
$comments = nl2br(filter_input(INPUT_POST, 'comments', FILTER_SANITIZE_STRING));

// Email Body
$message = <<

NAME
$name
E-MAIL
$email
SUBJECT
$subject
MESSAGE
$comments

HTML;

$mail->Subject = 'Message Received =?utf-8?B?4oCT?= Website Contact Form';
$mail->Body = $message;

// verify recaptcha response
$url        =  "https://www.google.com/recaptcha/api/siteverify";
$privatekey =  "xxx";
$response   =  file_get_contents($url."?secret=".$privatekey."&response=".$_POST['g-recaptcha-response']."&remoteip=".$_SERVER['REMOTE_ADDR']);
$data       =  json_decode($response);

// if recaptcha verification is a success...
if(isset($data->success) AND $data->success==true) {
            
    // ... and if phpmailer does not send (for whatever reason, such as a wrong SMTP password)...
    if (!$mail->send()) { 

        // then show this error message:    
        $send_fail_one = <<
                
                ERROR. Message not sent.
Please try again or contact us at bireg at outlook dot com.
              
ERROR;
}   else {
        // ...otherwise delivery is successful and page re-directs to thank you / confirmation page
        header('Location: https://www.yahoo.com');
    }
            
   } else {
       
        // if re-captcha verification fails, show this error message:
        $send_fail_two = <<
                
                ERROR. Message not sent.
Please check the anti-spam box.
              
ERROR;
        }
}
EN

回答 1

Code Review用户

回答已采纳

发布于 2022-02-08 18:59:50

联系人表单不一定是安全风险,但这完全取决于您如何处理提交的数据。基本上,您需要记住两种类型的安全性:

1.服务器

你不把任何东西存储在数据库里,也不自己发电子邮件。这消除了对您的服务器的最大威胁之一。您遗漏了很多代码,所以仍然有可能存储数据,但显然您不希望在这里讨论这个问题。

2.访客

用户使用此联系人表单的风险要大得多。除了他们的评论,他们必须提供他们的名字和电子邮件地址。为什么呢?

当然,任何聪明的用户都不会使用自己的名字和电子邮件地址。任何电子邮件地址都行。那么,为什么要问呢?

You可以使提供名称和电子邮件地址成为可选的。

你也在使用谷歌的隐藏reCAPTCHA,它将大量的用户数据交给谷歌。

读:谷歌reCAPTCHA和GDPR:一个可能的冲突?

如果reCAPTCHA错过了这些信息,谷歌还有第二次机会通过他们的邮件服务器偷看你发送的邮件。你不会给你的访问者留下任何选择,如果他们想要评论的话,他们也可以直接把他们的评论发送到谷歌。

为什么这会是个问题?谷歌将这些数据存储在美国。美国政府也喜欢大数据。他们用它。很简单。爱德华·斯诺登向我们展示了。外国人受到美国法律的保护甚至更少。

也可以阅读:独家:政府秘密命令谷歌确认任何搜查性侵犯受害者姓名、地址或电话号码的人

谷歌( Google )是互联网上没有隐私的主要原因之一,他们与Facebook一起积极努力保持这种状态。他们追求合法的商业利益,但结果是相当有害的。

大多数人,包括我,经常忽视这个明显的问题。我们把注意力集中在所有的技术问题上,但是这个故事有一个完全相反的方面。

票数 1
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://codereview.stackexchange.com/questions/273786

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档