【问题标题】:Are the variables in this code properly escaped?此代码中的变量是否正确转义?
【发布时间】:2015-09-23 11:06:17
【问题描述】:

我认为我已经正确地逃脱了一切,但我想知道我是否做对了。我记得在某处读到我们不应该过滤输入,只过滤输出。就我而言,这是否意味着我不应该在任何地方使用函数sanitize?并坚持prepare statementshtmlscpecialchars

<?php
    #Connection to the database
    function dbcon (){
        try{
            $db = new PDO('mysql:dbname=php_test;host=localhost','root','mysql');
        }
        catch (PDOException $e){
            echo $e->getMessage();
            exit();
        }
        return $db;
    }

    #Sanitize the input for preventing hacking attempts
    function sanitize($data) {
        $data = trim($data);
        $data = stripslashes($data);
        $data = htmlspecialchars($data);
        return $data;
    }

    #Get the list of countries from the DB
    function getCountries() {
        $db = dbcon();
        $query = "SELECT country FROM countries";
        $stmt = $db->prepare($query);
        $stmt->execute();
        $countries = "";
        while ($row = $stmt->fetch()) {
            $countries .= '<option value= "'.$row['country'].'">'.$row['country'].'</option>';
        }
        return $countries;
    }


    $name = $email = $password = $password2 = $country = "";
    $validForm = True;

    #If it's a submission, validate the form
    if ($_SERVER["REQUEST_METHOD"] == "POST") {
        $db = dbcon();

        #Name validation
        $name = sanitize($_POST["name"]);
        if ((strlen($name) < 2) || (strlen($name) > 50)) {
            echo "<span style=\"color: #FF0000;\"> Name must have between 2 and 50 characters </span> <br>";
            $name = "";
            $validForm = False;
        }

        #Email validation
        $email = sanitize($_POST["email"]);
        if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
            echo "<span style=\"color: #FF0000;\"> Check the format of the email </span> <br>";
            $email = "";
            $validForm = False;
        }
        else { #If it's a valid email, check whether or not it's already registered
            $query = "SELECT email FROM users;";
            $stmt = $db->prepare($query);
            $stmt->execute();
            $found = False;
            while (($row = $stmt->fetch()) and (!$found)) {
                if ($row["email"] == $email) {
                    $found = True;
                }
            }
            if ($found) {
                echo "<span style=\"color: #FF0000;\"> This email is already registered </span> <br>";
                $email = "";
                $validForm = False;
            }
        }

        #Password validation
        $password = sanitize($_POST["pass1"]);
        if ((strlen($password) < 6) || (strlen($password) > 20)) {
            echo "<span style=\"color: #FF0000;\"> Password must have between 6 and 20 characters </span> <br>";   
            $validForm = False;
        }
        else { #If it's a valid password, check whether or not both passwords match
            $password2 = sanitize($_POST["pass2"]);
            if ($password != $password2) {
                echo "<span style=\"color: #FF0000;\"> Passwords don't match </span> <br>";
                $validForm = False;
            }
            #If passwords match, hash the password
            else {
                $password = password_hash($password, PASSWORD_DEFAULT);
            }
        }

        #We don't need to validate country because it's retrieved from the DB, but we sanitize it just in case a hacker modified the POST using a proxy
        $country = sanitize($_POST["country"]);

        #All checks done, insert into DB and move to success.php
        if ($validForm) {
            $query = "INSERT INTO users VALUES(:name, :email, :password, :country);";
            $stmt = $db->prepare($query);
            $stmt->bindParam(':name', $name);
            $stmt->bindParam(':email', $email);
            $stmt->bindParam(':password', $password);
            $stmt->bindParam(':country', $country);
            $stmt->execute();
            header("Location: success.php");
        }
    }
?>
<html>
    <head>
    </head>
    <body>
        <!-- Submitting to this very file -->
        <form action="<?php echo htmlspecialchars($_SERVER["PHP_SELF"]);?>" method="post">
            <table>
                <tr> <!-- Name -->
                    <td><label for="name">Name:</label></td>
                    <td><input type="text" name="name" value="<?php echo htmlspecialchars($name); ?>" required /></td> 
                    <td><span style="color: #FF0000;">*</span></td> 
                    <td>Between 2 and 50 characters</td>
                </tr>
                <tr> <!-- Email -->
                    <td><label for="email">Email:</label></td>
                    <td><input type="text" name="email" value="<?php echo htmlspecialchars($email); ?>" required/></td> 
                    <td><span style="color: #FF0000;">*</span></td>
                    <td>Must be a valid address</td>
                </tr>
                <tr> <!-- Password -->
                    <td><label for="pass1">Password:</label></td>
                    <td><input type="password" name="pass1" required/></td> 
                    <td><span style="color: #FF0000;">*</span> </td>
                    <td>Between 6 and 20 characters</td>
                </tr>
                <tr> <!-- Confirm password -->
                    <td><label for="pass2">Confirm password:</label></td>
                    <td><input type="password" name="pass2" required/></td>
                    <td><span style="color: #FF0000;">*</span></td>
                    <td>Must be the same as the password</td>
                </tr>
                <tr> <!-- Country -->
                    <td><label for="country">Country:</label></td>
                    <td><select name="country"> <?php echo getCountries(); ?></select></td>
                    <td><span style="color: #FF0000;">*</span></td> 
                </tr>
                <tr>
                    <td><input type="submit"></td>
                </tr>
            </table>
        </form>
    </body>
</html>

【问题讨论】:

  • 为密码设置最大长度通常是不好的做法
  • @Crecket 是的,我知道,但这是具有此类必要条件的测试的一部分
  • @yzT 好吧,只是确保 ;) 顺便说一句,阿卜杜拉已经给出了正确的答案。 Prepare() 和 BindParam() 负责 sql 注入
  • @Crecket 根据他的回答,我可以摆脱sanitize 功能。但是htmlspecialchars呢?

标签: php html mysql code-injection


【解决方案1】:

全部由PDO::prepare完成

调用 PDO::prepare() 和 PDOStatement::execute() 以获取将使用不同参数值多次发出的语句,通过允许驱动程序协商查询计划的客户端和/或服务器端缓存以及元信息,并通过消除手动引用参数的需要来帮助防止 SQL 注入攻击。

还有另一个替代品

PDO::quote

PDO::quote() 在输入字符串周围放置引号(如果需要)并转义输入字符串中的特殊字符,使用适合底层驱动程序的引用样式。

了解XSS注入Read this Answer too

【讨论】:

  • 根据您的回答,我知道我可以摆脱sanitize 功能,但我仍然必须在表单回显中使用htmlspecialchars,对吗?
  • @yzT htmlspecialchars 把
【解决方案2】:

我在清理用户输入的数据时经常使用的一件事是使用 strip_tags()... 特别是如果要在某个时候回显内容...您不想使用表单轻松注入脚本。 尝试在其中一个文本元素中输入&lt;script&gt;alert("hello");&lt;/scirpt&gt; 并提交...

【讨论】:

  • 使用 strip_tags() 还不错。它本身还不够,但它肯定会阻止人们将
  • @Crecket 我并没有说这还不错,如果我已经在使用htmlspecialchars 就没有必要了
  • 我更喜欢使用 strip_tags、stripslashes 和 mysql_real_escape_string 而不是 htmlspecialchars 来处理我从表单收到的并将存储在数据库中的内容,因为我可能想以其他方式使用内容而不是 html所以我想尽可能保持“文本”。从数据库或表单向屏幕发送任何内容时,我总是使用它。
猜你喜欢
  • 2020-02-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-11-23
  • 1970-01-01
  • 2011-08-29
  • 2019-04-19
  • 2012-01-16
相关资源
最近更新 更多