我有一个 php 文件,它在开始时从使用 $_GET 发送的内容中分配一些变量。
然后它执行一些 mysql 查询,处理输出,然后回显一些文本和变量。
我在代码中设置的唯一保护是mysql_real_escape_string
在 GET 上。
这足以防止攻击吗?
还有什么可以做的?
我有一个 php 文件,它在开始时从使用 $_GET 发送的内容中分配一些变量。
然后它执行一些 mysql 查询,处理输出,然后回显一些文本和变量。
我在代码中设置的唯一保护是mysql_real_escape_string
在 GET 上。
这足以防止攻击吗?
还有什么可以做的?
好吧,你mysql_real_escape_string
大错特错了。
但这不是你的错——它是 PHP 社会中最邪恶的错觉之一。甚至官方手册页都错了。
此功能与保护任何东西无关,尤其是 GET 变量
该函数只是对字符串分隔符进行转义,使字符串分隔符无法打断字符串。因此,两个最重要的后果:
mysql_real_escape_string()
,无论它们的来源或来源或可能的危险性如何因此,为了保护您的 SQL 查询,您必须遵循整套规则,而不仅仅是欺骗“使用 mysql_real_escape_string 清理您的数据”。
您可以从我之前关于类似主题的回答中了解如何保护您的 SQL:在 PHP 中,当向数据库提交字符串时,我应该使用 htmlspecialchars() 还是使用正则表达式来处理非法字符?
更新
一个场景以说明为什么 mysql_real_escape_string 不是灵丹妙药
使用 url
http://www.example.com/news.php?offset=99999+UNION+SELECT+password+FROM+users+--
一个代码
$offset = mysql_real_escape_string($_GET['offset']);
$sql = "SELECT title FROM news LIMIT $offset,20";
如果不是像小鲍比桌那样华丽,但也会造成同样的灾难性后果。
mysql_real_escape_string
当您在MySQL 字符串声明中使用返回值时,只会保护您免受 SQL 注入,例如:
'SELECT foo FROM bar WHERE quux="'.mysql_real_escape_string($val).'"'
ASC
如果您在任何其他上下文中使用它(使用/指定排序顺序DESC
、行限制、表/行名称等),它不会保护您。在这种情况下,您需要分别验证/过滤/清理该值。
如果用户数据也可以是您即将输出的查询结果的一部分,请使用它htmlspecialchars
来替换任何 HTML 特殊字符。
不,有很多攻击你可能没有保护。一个例子是 CSRF。这是一个很大的领域,所以我建议在 Owasp 网站上阅读这些内容:
使用它绝对是不够的。如果只考虑 sql 注入,甚至还不够。当您仅考虑对字符串进行 sql 注入时就足够了,但是一旦您有一个整数(比如一个 id)就会出错:
http://example.com/foo.php?id=10
穿过去:
$q = "SELECT * FROM foo where id = " + mysql_real_escape_string($_GET['id'])
这导致de SQL查询:
SELECT * FROM foo where id = 10
这很容易被利用,例如:
http://example.com/foo.php?id=10%3B%20DROP%20TABLE%20foo
穿过去:
$q = "SELECT * FROM foo where id = " + mysql_real_escape_string($_GET['id'])
这导致de SQL查询:
SELECT * FROM foo where id = 10;DROP TABLE foo
我希望这能说明为什么它还不够。
你应该如何解决这个问题?定义允许的输入,并检查输入是否确实是这种形式,例如:
if(preg.match("^[0-9]+$",$_GET['id']){
// your code here
}else{
// invalid id, throw error
}
但是为了安全起见(关于 SQL 注入),最好的方法是使用准备好的语句: http: //php.net/manual/en/pdo.prepared-statements.php
如果 get 变量具有使用 isset() 和 empty() 函数的值,你有