我有一个简单的问题。我不太擅长编程,但这样安全吗?
目前我正在使用函数来获取用户名,头像等。
看起来像这样:
try {
$conn = new PDO("mysql:host=". $mysql_host .";dbname=" . $mysql_db ."", $mysql_username, $mysql_password);
// set the PDO error mode to exception
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$conn->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
}
catch(PDOException $e)
{
echo "Connection failed: " . $e->getMessage();
}
config.php ^^
function getUsername($userid) {
require "config/config.php";
$stmt = $conn->prepare("SELECT username FROM accounts WHERE id = ? LIMIT 1");
$stmt->execute([$userid]);
$name = $stmt->fetch();
return $name["username"];
}
function getProfilePicture($userid) {
require "config/config.php";
$stmt = $conn->prepare("SELECT profilepicture FROM accounts WHERE id = ? LIMIT 1");
$stmt->execute([$userid]);
$image = $stmt->fetch();
return $image["profilepicture"];
}
这是正确的,更重要的是,这样安全吗?
答案 0 :(得分:1)
看起来假设你的配置文件是正确的,它会起作用。因为它是一个准备好的声明,就安全性而言看起来很好。
他们只传递身份证。添加一些安全性可以做的一件事是确保传入的$ userid是正确的类型。 (我假设一个int)。
例如,如果您希望有一个整数ID,并且您得到的字符串可能是phishy(可能是SQL注入),但是如果您可以确认它是一个int(如果不是则可能会抛出错误)然后你可以确定你得到了你想要的东西。
您可以使用:
is_int($userid);
确保它是一个int
http://php.net/manual/en/function.is-int.php
的is_int()的更多详细信息希望这有帮助。
答案 1 :(得分:1)
这是安全的(至少这部分代码,我不知道@icecub指出的数据库连接部分),但有些事情你应该注意:
require
config.php
一次prepare
语句一次,然后在函数上调用它,每次都可以减慢脚本速度:
查询只需要解析(或准备)一次,但可以使用相同或不同的参数执行多次。准备好查询后,数据库将分析,编译和优化其执行查询的计划。 - PHP Docs
is_int
来验证用户的ID(如果您使用ID作为数字)答案 2 :(得分:1)
是的,SQL注入是安全的。
其他一些答案是将主题转移到XSS保护中,但是您显示的代码不会回显任何内容,它只是从数据库中获取并从函数返回值。当你从函数中返回时,我建议不要使用预转义值,因为你不确定是否要调用该函数以将结果回显给HTML响应。
没有必要使用is_int()
,因为当您在数字上下文中使用参数时,MySQL会自动转换为整数。非数字字符串被解释为零。换句话说,以下谓词给出了相同的结果。
WHERE id = 0
WHERE id = '0'
WHERE id = 'banana'
我建议不要在每个函数中连接数据库。 MySQL的连接代码相当快(特别是与其他一些RDBMS相比),但为每个 SQL查询建立新连接仍然很浪费。而是连接到数据库一次并将连接传递给函数。
当您连接到数据库时,您捕获异常并回显错误,但随后您的代码将继续,就像连接成功一样。相反,如果出现问题,您应该让脚本死掉。此外,不要向用户输出系统错误消息,因为他们无法对该信息执行任何操作,并且可能会显示有关您的代码的过多信息。记录错误以进行自己的故障排除,但输出更通用的内容。
您也可以考虑为您的连接定义一个函数,并为您的用户定义一个类。这是一个例子,虽然我还没有测试过:
function dbConnect() {
try {
$conn = new PDO("mysql:host=". $mysql_host .";dbname=" . $mysql_db ."", $mysql_username, $mysql_password);
// set the PDO error mode to exception
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$conn->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
}
catch(PDOException $e)
{
error_log("PDO connection failed: " . $e->getMessage());
die("Application failure, please contact administrator");
}
}
class User {
protected $row;
public function __construct($userid) {
global $conn;
if (!isset($conn)) {
$conn = dbConnect();
}
$stmt = $conn->prepare("SELECT username, profilepicture FROM accounts WHERE id = ? LIMIT 1");
$stmt->execute([$userid]);
$this->row = $stmt->fetch(PDO::FETCH_ASSOC);
}
function getUsername() {
return $this->row["username"]
}
function getProfilePicture() {
return $this->row["profilepicture"]
}
}
用法:
$user = new User(123);
$username = $user->getUsername();
$profilePicture = $user->getProfilePicture();