这些安全功能足够吗?

3

我正在尝试保护我的网站,以免受到SQL注入或XSS攻击。

这是我的代码:

//here's the form (abbreviated)
<form>
<label for="first_name" class="styled">First Name:</label>
<input type="text" id="first_name" name="first_name" value="<?php if (!empty($first_name)) echo $first_name; ?>" /><br />

//submit button etc
</form>


if (isset($_POST['submit'])) {

 //gets rid of extra whitesapce and escapes
 $first_name = mysqli_real_escape_string($dbc, trim($_POST['first_name']));

 //check if $first_name is a string
 if(!is_string($first_name)
 { 
 echo "not string"; 
 }

 //then insert into the database. 
 .......

mysqli_real_escape_string:我知道这个函数会转义像\n \r这样的特殊字符,那么当数据输入到dbc时,所有被转义的字符旁边是否都有'\'?

  • 这个脚本足以防止大多数sql注入吗?只进行转义并检查数据是否为字符串。对于整数值(例如用户输入价格),我只用:is_numeric()

  • 我应该如何使用htmlspecialchars?我应该只在回显和显示用户数据时使用它吗?还是在插入数据到数据库时也要使用它?

  • 何时应该使用strip_tagshtmlspecialchars

所以针对这些函数:

if (isset($_POST['submit'])) {

 //gets rid of extra whitesapce and escapes
 $first_name = mysqli_real_escape_string($dbc, trim($_POST['first_name']));

 //check if $first_name is a string
 if(!is_string($first_name)
 { 
 echo "not string"; 
 }

 //gets rid of any <,>,&
 htmlspecialchars($first_name);

 //strips any tags with the first name
 strip_tags($first_name)

 //then insert into the database. 
 .......

我应该使用哪些函数来防止 SQL 注入,哪些函数来防止 XSS 攻击?

什么情况下用户可以对我进行 XSS 攻击?当存在表单时吗?


我建议进行适当的表单验证,而不仅仅是简单地清除用户提供的数据。 - Davor Lucic
什么是正确的表单验证? - ggfan
当我谈论正确的表单验证时,我主要想到的是一些 Web 框架中使用编程语言内置的 html 表单抽象。也就是创建一个表示表单的类,它将知道它有哪些字段以及如何验证它们、返回清理后的数据、打印出 html 等等。在您的示例中,您可以使用正则表达式('\w+' 可能)验证 $first_name,如果验证通过,则可以确信字符串中没有任何不安全的字符,例如反斜杠等,否则会引发错误。 - Davor Lucic
4个回答

2
检查数据是否为字符串是无用的:字符串正是您用于注入的内容。
real_escape_string 是一种合理但并不保证完全避免 SQL 注入的方法,因为转义程序有可能出现漏洞,不能正确地转义某些内容(实际上,以前曾经出现过此类漏洞)。正确的做法是使用参数化查询 - 这将数据与查询结构分离,使注入变得不可能。如果您绝对无法使用参数化查询,则 real_escape_string(在打开连接时使用 set_charset)是您能够做到的最好的方法。
您会想要在用户可以触及的任何内容上使用htmlspecialchars,并且您希望在显示页面时立即使用它。如果您希望用户格式化帖子或其他任何内容,则应为他们提供类似于BBCode的格式语言(并在运行htmlspecialchars之后转换BBCode)。如果您需要存储纯HTML,则不应使用htmlspecialchars,但您需要确保只有可信赖的人才能在那里写入。例如,如果您正在编写博客,则在博客文章本身中允许纯HTML可能是可以的,因为只有博客编辑可以在那里写东西。但是,在评论中不应允许它,因为每个人都可以在那里写东西,这将使像{{link1:跨站点脚本}}这样的事情变得太容易了。

1

对于 SQL 注入,mysql_real_escape_string 应该可以解决问题。(为了确保安全,您可以使用预处理语句)

对于 XSS,htmlspecialchars 应该可以解决问题。但是 strip_tags 可能不够安全,因为有人可能巧妙地伪装他们的 JavaScript。


所以任何用户可以输入数据的地方,我都应该使用htmlspecialchars,如果我将数据插入dbc中,我应该使用mysql_real_escape_string和prepared statements? - ggfan
1
是的。(real_escape_string或prepared statements)你不应该同时使用两者。 - Mitch Dempsey

1
无论何时您在HTML中嵌入用户提供的信息,都应该使用htmlspecialchars。无论何时您在SQL中嵌入用户提供的信息,都应该使用mysql_real_escape_string。遵循这些规则,您就应该没问题了。
但请注意,更好的数据库安全解决方案是使用准备好/参数化查询(请参见此处此处),因为这些将为您处理转义,消除您忘记的可能性。
另外,请不要忘记检查魔术引号

1
如果您要打印HTML,应该先使用HTML Purifier进行清理。将其视为strip_tags()的高级(且可定制)版本。
对于插入到数据库中,我使用prepared statements。这是绝对可靠的。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接