我应该mysql_real_escape_string我从用户那里获得的所有cookie以避免mysql注入php吗?
当用户访问我的网站时,我的脚本会检查2个cookie,这些cookie存储用户ID +部分密码,以自动登录。
可以通过cookie编辑器来编辑cookie的内容,所以我想可以向书面cookie中添加一些恶意内容吗?
我应该在所有cookie调用中添加" mysql_real_escape_string"(或者其他内容),还是有某种内置过程不允许这种情况发生?
解决方案
我们应该使用mysql_real_escape_string可能有害的任何东西。永远不要相信用户可以更改的任何类型的输入。
我同意你的看法。可以修改Cookie并发送恶意数据。
我相信,在使用Cookie之前,最好先过滤掉从Cookie中获得的值。根据经验,我会过滤可能被篡改的任何其他输入。
我只在将变量插入SQL语句之前使用mysql_real_escape_string。如果我们已经对某些变量进行了转义,我们将感到困惑,然后再次对它们进行转义。这是我们在新手博客Web应用程序中看到的经典错误:
When someone writes an apostrophe it keeps on adding slashes ruining the blog\\\\'s pages.
变量的值本身并不危险:只有当我们将其放入字符串或者类似内容中时,我们才开始迷失在危险的环境中。
当然,绝对不要信任来自客户端的任何信息。
mysql_real_escape_string太过过去了...这些天,我们应该真正使用参数绑定。
我将通过提及来详细说明,我指的是准备好的语句,并提供指向文章的链接,该文章证明有时mysl_real_escape_string不够用:http://www.webappsec.org/projects/articles/091007.txt
我建议使用htmlentities($ input,ENT_QUOTES)代替mysql_real_escape_string,因为这还将防止实际HTML代码的任何意外输出。当然,我们可以使用mysql_real_escape_string和htmlentities,但是为什么呢?
我们真正需要做的是首先不发送这些可入侵的cookie值。相反,为什么不对用户名和密码以及(秘密)盐进行哈希处理,然后将其设置为cookie值呢? IE。:
define('COOKIE_SALT', 'secretblahblahlkdsfklj'); $cookie_value = sha1($username.$password.COOKIE_SALT);
然后,我们知道cookie值始终是40个字符的十六进制字符串,并且可以将用户发回的值与数据库中的值进行比较,以确定它们是否有效:
if ($user_cookie_value == sha1($username_from_db.$password_drom_db.COOKIE_SALT)) { # valid } else { #not valid }
mysql_real_escape_string对数据库产生了额外的影响,顺便说一句(很多人没有意识到它需要数据库连接并查询MySQL)。
如果我们无法更改应用程序并坚持使用可破解的Cookie值,那么做自己想要做的最好的方法就是使用带有绑定参数的预备语句。
mysql_real_escape_string的目的不是要防止注入攻击,而是要确保数据准确地存储在数据库中。因此,无论其来源如何,都应在进入数据库的ANY字符串上调用它。
但是,我们还应该使用参数化查询(通过mysqli或者PDO)来保护自己免受SQL注入。否则,我们可能冒着像小鲍比·泰勒斯(Bobby Tables)的学校那样的结局的风险。
Yegor,我们可以在创建/更新用户帐户时存储哈希,然后在每次启动登录时对发布到服务器的数据进行哈希处理,并与该用户名在数据库中存储的数据进行比较。
(在我的头顶上,在松散的php中将其视为伪代码):
$usernameFromPostDbsafe = LimitToAlphaNumUnderscore($usernameFromPost); $result = Query("SELECT hash FROM userTable WHERE username='$usernameFromPostDbsafe' LIMIT 1;"); $hashFromDb = $result['hash']; if( (sha1($usernameFromPost.$passwordFromPost.SALT)) == $hashFromDb ){ //Auth Success }else{ //Auth Failure }
成功通过身份验证后,我们可以将哈希存储在$ _SESSION或者缓存的已认证身份用户名/哈希的数据库表中。然后将哈希发送回浏览器(例如在cookie中),以便随后的页面加载将哈希发送回服务器,以便与所选会话存储中保存的哈希进行比较。
准备好的语句和参数绑定始终是一个好方法。
PEAR :: MDB2支持预备语句,例如:
$db = MDB2::factory( $dsn ); $types = array( 'integer', 'text' ); $sth = $db->prepare( "INSERT INTO table (ID,Text) (?,?)", $types ); if( PEAR::isError( $sth ) ) die( $sth->getMessage() ); $data = array( 5, 'some text' ); $result = $sth->execute( $data ); $sth->free(); if( PEAR::isError( $result ) ) die( $result->getMessage() );
这将只允许适当的数据和预设数量的变量进入数据库。
当然,我们应该在验证数据之前先进行数据验证,但是准备语句是应该完成的最终验证。