如果插入用户输入而不修改SQL查询,则应用程序容易受到SQL注入的攻击,如下例所示:
$unsafe_variable = $_POST['user_input'];
mysql_query("INSERT INTO `table` (`column`) VALUES ('$unsafe_variable')");
Run Code Online (Sandbox Code Playgroud)
这是因为用户可以输入类似的内容value'); DROP TABLE table;--,查询变为:
INSERT INTO `table` (`column`) VALUES('value'); DROP TABLE table;--')
Run Code Online (Sandbox Code Playgroud)
可以采取哪些措施来防止这种情况发生?
赏金更新:马克已经得到了很好的答案.改编:=进入:,下面.但是,除了DBIx之外,我还在寻找类似的方案.我只对与任何东西兼容感兴趣.
我需要建议我在参数化SQL语句中为"扩展"占位符选择的语法.因为构建一些构造(IN子句)让我烦恼,我决定使用一些自动扩展为普通的语法快捷方式?占位符.
我喜欢他们.但我想打包它以便分发,并且问我自己是否容易理解.
基本上我的新占位符是??和:?(枚举参数)和:&和:,(:|以及::(对于命名占位符)具有以下用例:
-> db(" SELECT * FROM all WHERE id IN (??) ", [$a, $b, $c, $d, $e])
Run Code Online (Sandbox Code Playgroud)
该??扩展到?,?,?,?,?,...依赖于的$ args数到我的分贝()FUNC.这个很清楚,它的语法已经标准化了.Perls DBIx :: Simple也使用它.所以我很确定这是一个可以接受的想法.
-> db(" SELECT :? FROM any WHERE id>0 ", ["title", "frog", "id"]);
// Note: not actually parameterized attr, needs cleanup regex
Run Code Online (Sandbox Code Playgroud)
承认它.我只喜欢笑脸.基本上这个:?占位符将关联$ args扩展为普通列名.它实际上抛弃了任何$ args值.它实际上对于INSERT和??有时是有用的,有时对于IN子句也是有用的.但是在这里我已经想知道这种新语法是否合理,或者只是用词不当,因为它混合了:和?字符.但不知何故,它似乎很好地匹配语法方案.
-> db(" UPDATE some SET :, WHERE :& AND (:|) …Run Code Online (Sandbox Code Playgroud) 我总是做简单的连接mysql_connect,mysql_pconnect:
$db = mysql_pconnect('*host*', '*user*', '*pass*');
if (!$db) {
echo("<strong>Error:</strong> Could not connect to the database!");
exit;
}
mysql_select_db('*database*');
Run Code Online (Sandbox Code Playgroud)
虽然使用这个我一直使用的简单的方法,使查询之前逃脱的任何数据,不管是INSERT,SELECT,UPDATE或者DELETE通过使用mysql_real_escape_string
$name = $_POST['name'];
$name = mysql_real_escape_string($name);
$sql = mysql_query("SELECT * FROM `users` WHERE (`name` = '$name')") or die(mysql_error());
Run Code Online (Sandbox Code Playgroud)
现在我明白这在某种程度上是安全的!
它逃脱了危险的人物; 但是,它仍然容易受到其他可能包含安全字符的攻击,但可能对显示数据或在某些情况下恶意修改或删除数据有害.
所以,我搜索了一下,发现了PDO,MySQLi和准备好的语句.是的,我可能会迟到,但我已经阅读了很多很多教程(tizag,W3C,博客,谷歌搜索),没有一个人提到这些.看起来很奇怪为什么,因为只是逃避用户输入真的不安全而且至少可以说是不好的做法.是的,我知道你可以使用Regex解决它,但是,我很确定这还不够吗?
据我所知,当用户输入给出变量时,使用PDO /预处理语句是一种更安全的方式来存储和检索数据库中的数据.唯一的麻烦是,切换(特别是在我的方式/先前编码的习惯非常困难之后)有点困难.
现在我明白使用PDO连接到我的数据库我会使用
$hostname = '*host*';
$username = '*user*';
$password = '*pass*';
$database = '*database*'
$dbh = new PDO("mysql:host=$hostname;dbname=$database", $username, $password);
if ($dbh) {
echo …Run Code Online (Sandbox Code Playgroud) 我刚刚开始准备语句的工作,我的第几个例子摸索出伟大的,但现在我运行到一个SQL语法,我不明白.我有一个执行INSERT的函数,带有一个关联数组的参数,其中数组的键是字段,数组的值是要插入的值.例如:
$arr = array("field1" => "value1",
"field2" => "value2");
$this->insert("table", $arr);
Run Code Online (Sandbox Code Playgroud)
会执行:
INSERT INTO table ('field1', 'field2') VALUES ('value1', 'value2')
Run Code Online (Sandbox Code Playgroud)
但是,在尝试执行此操作时,我收到以下错误:
PDOException:SQLSTATE [42000]:语法错误或访问冲突:1064 SQL语法中有错误; 检查与MySQL服务器版本对应的手册,以便在''post_title','post_body'附近使用正确的语法.)VALUES('Testing!','1 2 3!')'在第1行
这是我的功能:
/**
* insert()
*
* Performs an insert query
*
* @param string $table The table to be inserted into
* @param array $fields An associative array of the fields to be inserted
* and their respective values
* @return void
*
*/
function insert($table, $fields) {
if (empty($table) || empty($fields)) { …Run Code Online (Sandbox Code Playgroud)