我有一个html表单,接受用户输入的大小约1000的文本,并提交到一个php页面,它将存储在mysql数据库中。我使用PDO与预准备语句来防止SQL注入。但是要清理用户输入的文本,需要做的最好的努力是什么?
我想阻止任何脚本注入,xss攻击等。
答案 0 :(得分:7)
安全是一个有趣的概念,吸引了很多人。不幸的是,这是一个复杂的主题,甚至专业人士也错了。我在Google(CSRF),Facebook(更多CSRF),几家主要在线零售商(主要是SQL注入/ XSS)以及成千上万的小型企业和个人网站中都发现了安全漏洞。
这些是我的建议:
1)使用参数化查询
参数化查询强制将传递给查询的值视为单独的数据,以便DBMS不能将输入值解析为SQL代码。很多人会建议您使用mysql_real_escape_string()
来逃避字符串,但与普遍认为的相反,不是SQL注入的全能解决方案。以此查询为例:
SELECT * FROM users WHERE userID = $_GET['userid']
如果$_GET['userid']
设置为1 OR 1=1
,则没有特殊字符,也不会对其进行过滤。这会导致返回所有行。或者,更糟糕的是,如果它被设置为1 OR is_admin = 1
?
参数化查询可防止发生此类注入。
2)验证您的输入
参数化查询很棒,但有时候意外的值可能会导致代码出现问题。确保您确认它们在范围内,并且不允许当前用户更改他们无法做到的事情。
例如,您可能有一个密码更改表单,该表单将POST请求发送到更改其密码的脚本。如果您将其用户ID作为隐藏变量放在表单中,他们可以更改它。发送id=123
而不是id=321
可能意味着他们更改了其他人的密码。确保在类型,范围和访问方面正确验证了一切。
3)使用htmlspecialchars转义显示的用户输入
假设您的用户输入他们的“关于我”,如下所示:
</div><script>document.alert('hello!');</script><div>
这样做的问题是您的输出将包含用户输入的标记。尝试用黑名单自己过滤这个只是一个坏主意。使用htmlspecialchars
过滤掉字符串,以便将HTML标记转换为HTML实体。
4)不要使用$ _REQUEST
跨站点请求伪造(CSRF)攻击的工作原理是让用户单击链接或访问表示在其登录的站点上执行操作的脚本的URL。$_REQUEST
变量是组合$_GET
,$_POST
和$_COOKIE
,这意味着您无法区分在POST请求中发送的变量(即通过input
标记中的变量您的表单)或作为GET一部分在您的网址中设置的变量(例如page.php?id=1
)。
假设用户想要向某人发送私人消息。他们可能会向sendmessage.php
发送POST请求,其中to
,subject
和message
为参数。现在让我们假设某人发送了一个GET请求:
sendmessage.php?to=someone&subject=SPAM&message=VIAGRA!
如果您使用$_POST
,则不会看到任何这些参数,因为它们是在$_GET
中设置的。您的代码将看不到$_POST['to']
或任何其他变量,因此它不会发送消息。但是,如果您使用$_REQUEST
,则$_GET
和$_POST
会卡在一起,因此攻击者可以将这些参数设置为网址的一部分。当用户访问该URL时,他们无意中发送了该消息。真正令人担忧的部分是用户无需做任何事情。如果攻击者创建了恶意页面,则它可能包含指向URL的iframe
。例如:
<iframe src="http://yoursite.com/sendmessage.php?to=someone&subject=SPAM&message=VIAGRA!">
</iframe>
这导致用户在没有意识到他们做任何事情的情况下向他们发送消息。因此,您应该避免$_REQUEST
并改为使用$_POST
和$_GET
。
5)将您给予的所有内容视为可疑(甚至恶意)
您不知道用户发送给您的是什么。这可能是合法的。这可能是一次袭击。永远不要相信用户发送给您的任何信息。转换为正确的类型,验证输入,使用白名单在必要时进行过滤(避免黑名单)。这包括通过$_GET
,$_POST
,$_COOKIE
和$_FILES
发送的任何内容。
如果您遵循这些准则,那么您在安全方面的合理地位。
答案 1 :(得分:4)
您需要区分两种类型的攻击:SQL注入和XSS。通过使用预准备语句或数据库库的引用函数可以避免SQL注入。在插入数据库之前,您可以使用之前的引用函数。
可以通过引用htmlspecialchars的所有特殊字符来避免XSS。 从数据库中读取并将原始输入存储在数据库中后,将输出视为好的样式。这样,当您在不需要HTML转义的其他上下文中使用输入时(文本电子邮件,JSON编码的字符串),您仍然可以从用户那里获得原始输入。
另见this answer类似问题。
答案 2 :(得分:1)
为了安全起见,您需要做两件简单的事情: