在开发网站或者应用程序时,过滤用户输入或者接口提交的php参数是非常重要的。这是因为用户输入的数据可能包含恶意代码,攻击者可以利用这些数据来攻击你的网站或者应用程序。
为了保护你的网站或者应用程序,你需要对用户输入的数据进行过滤。这可以通过使用php内置的函数来实现。例如,你可以使用htmlspecialchars函数来过滤用户输入的html标签,或者使用mysqli_real_escape_string函数来过滤用户输入的sql语句。
另外,你还可以使用正则表达式来过滤用户输入的数据。正则表达式是一种强大的工具,可以用来匹配和替换文本。你可以使用正则表达式来过滤用户输入的电话号码、电子邮件地址、网址等等。
总之,过滤用户输入或者接口提交的php参数是非常重要的。通过使用php内置的函数和正则表达式,你可以有效地保护你的网站或者应用程序,防止攻击者利用用户输入的数据来攻击你的网站或者应用程序,我们注意以下几点:
1、不要信任任何外部数据或输入
在Web应用程序安全性方面,最重要的一点是不要信任任何外部数据。外部数据包括任何不是由程序员在PHP代码中直接输入的数据,如GET变量、表单POST、数据库、配置文件、会话变量或cookie。在确保安全之前,所有来自其他来源的数据都是不可信的。
例如,下面的数据元素可以被认为是安全的,因为它们是在PHP中设置的:
<?php
$myUsername = 'tmyer';
$arrayUsers = array('tmyer', 'tom', 'tommy');
define(”GREETING”, 'hello there' . $myUsername);
?>
然而,下面的数据元素都是有缺陷的:
<?php
$myUsername = $_POST['username']; //tainted!
$arrayUsers = array($myUsername, 'tom', 'tommy'); //tainted!
define(”GREETING”, 'hello there' . $myUsername); //tainted!
?>
为什么第一个变量$myUsername是有缺陷的呢?
因为它直接来自表单POST,用户可以在这个输入域中输入任何字符串,包括用来清除文件或运行以前上传的文件的恶意命令。虽然可以使用客户端(JavaScript)表单验证脚本来避免这种危险,但是任何人都可以将任何表单下载到自己的机器上,修改它,然后重新提交他们需要的任何内容。
解决方案很简单:必须对$_POST['username']运行清理代码。如果不这么做,那么在使用$myUsername的任何其他时候(比如在数组或常量中),就可能污染这些对象。对用户输入进行清理的一个简单方法是使用正则表达式来处理它。
在这个示例中,只希望接受字母。将字符串限制为特定数量的字符,或者要求所有字母都是小写的,这可能也是个好主意。这样可以使用户输入变得更加安全。
2、使用户输入变得安全
<?php
$myUsername = cleanInput($_POST['username']); //clean!
$arrayUsers = array($myUsername, 'tom', 'tommy'); //clean!
define(”GREETING”, 'hello there' . $myUsername); //clean!
function cleanInput($input){
$clean = strtolower($input);
$clean = preg_replace(”/[^a-z]/”, “”, $clean);
$clean = substr($clean,0,12);
return $clean;
}
?>
3、禁用那些会影响安全性的 PHP 设置
除了不能信任用户输入,还应该注意不要信任机器上配置 PHP 的方式。例如,应该禁用 register_globals 设置,因为启用它可能会导致一些粗心的错误,比如使用 $variable 替换同名的 GET 或 POST 字符串。禁用这个设置后,PHP 强制您在正确的名称空间中引用正确的变量。如果要使用来自表单 POST 的变量,应该引用 $_POST['variable'],这样就不会将这个特定变量误会成 cookie、会话或 GET 变量。
如果无法理解代码,就无法保护它
有些开发人员使用奇怪的语法或将语句组织得很紧凑,形成简短但含义模糊的代码。这种方式可能效率高,但如果您无法理解代码正在做什么,就无法决定如何保护它。因此,应该使代码易于理解和保护。
<?php
//obfuscated code
$input = (isset($_POST['username']) ? $_POST['username']:”);
//unobfuscated code
$input = ”;
if (isset($_POST['username'])){
$input = $_POST['username'];
}else{
$input = ”;
}
?>
在第二个代码段中,很明显$input存在缺陷,需要进行清理和处理才能确保安全性。
4、纵深防御”是一种新的保护方法。
本教程将通过示例演示如何保护在线表单,并在处理表单的PHP代码中采取必要的措施。即使使用PHP正则表达式确保GET变量完全是数字,也应该采取措施确保SQL查询使用转义的用户输入。纵深防御不仅是一种好的思想,还可以确保您不会陷入严重的麻烦。
在讨论基本规则之后,我们将研究第一种威胁:SQL注入攻击。在SQL注入攻击中,攻击者通过操纵表单或GET查询字符串,将信息添加到数据库查询中。例如,假设有一个简单的登录数据库,其中每个记录都有一个用户名字段和一个密码字段。为了让用户能够登录,我们需要构建一个简单的登录表单。
<html>
<head>
<title>Login</title>
</head>
<body>
<form action=”verify.php” method=”post”>
<p><label for='user'>Username</label>
<input type='text' name='user' id='user'/>
</p>
<p><label for='pw'>Password</label>
<input type='password' name='pw' id='pw'/>
</p>
<p><input type='submit' value='login'/></p>
</form>
</body>
</html>
该表单允许用户输入用户名和密码,并将输入数据提交给名为 verify.php 的文件进行处理。然而,这段代码存在安全隐患,因为它没有对用户输入进行充分的验证和过滤。为了确保数据的安全性,应该对输入数据进行严格的验证和过滤,以防止恶意攻击和数据泄露。
因此,我们需要对这段代码进行改进,以提高其安全性和可靠性。
<?php
$okay = 0;
$username = $_POST['user'];
$pw = $_POST['pw'];
$sql = “select count(*) as ctr from users where username='”.$username.”' and password='”. $pw.”' limit 1″;
$result = mysql_query($sql);
while ($data = mysql_fetch_object($result)){
if ($data->ctr == 1){
//they're okay to enter the application!
$okay = 1;
}
}
if ($okay){
$_SESSION['loginokay'] = true;
header(”index.php”);
}else{
header(”login.php”);
}
?>
这段代码看起来似乎没有问题,但是世界各地有成百上千的PHP/MySQL站点都在使用这种代码。然而,这段代码存在一个严重的问题,那就是“不能信任用户输入”。因为没有对来自用户的任何信息进行转义,所以这个应用程序很容易受到攻击。具体来说,可能会出现各种类型的SQL注入攻击。
例如,如果用户输入“foo”作为用户名,输入“' or '1'='1”作为密码,那么实际上会将以下字符串传递给PHP,然后将查询传递给MySQL:
<?php
$sql = “select count(*) as ctr from users where username='foo' and password=” or '1′='1′ limit 1″;
?>
这个查询总是返回计数值 1,因此 PHP 会允许进行访问。通过在密码字符串的末尾注入某些恶意 SQL,黑客就能装扮成合法的用户。
解决这个问题的办法是,将 PHP 的内置 mysql_real_escape_string()
函数用作任何用户输入的包装器。这个函数对字符串中的字符进行转义,使字符串不可能传递撇号等特殊字符并让MySQL 根据特殊字符进行操作。清单 7 展示了带转义处理的代码。
5、安全的 PHP 表单处理代码
<?php
$okay = 0;
$username = $_POST['user'];
$pw = $_POST['pw'];
$sql = “select count(*) as ctr from users where username='”.mysql_real_escape_string($username).”' and password='”. mysql_real_escape_string($pw).”' limit 1″;
$result = mysql_query($sql);
while ($data = mysql_fetch_object($result)){
if ($data->ctr == 1){
//they're okay to enter the application!
$okay = 1;
}
}
if ($okay){
$_SESSION['loginokay'] = true;
header(”index.php”);
}else{
header(”login.php”);
}
?>
使用 mysql_real_escape_string()
作为用户输入的包装器,就可以避免用户输入中的任何恶意 SQL 注入。如果用户尝试通过 SQL 注入传递畸形的密码,那么会将以下查询传递给数据库:
select count(*) as ctr from users where username='foo' and password='\' or \'1\'=\'1′ limit 1″
数据库中未发现任何与此类密码匹配的内容。只需简单的步骤,便可以解决 Web 应用程序中存在的一个严重漏洞。我们可以从中得出的经验是,无论何时都要对 SQL 查询中的用户输入进行转义处理。
但是,还有几个安全漏洞需要解决。下一步是预防用户操纵 GET 变量。
在上文中,我们已经避免用户使用畸形密码登录。如果聪明的您能够应用这种方法,对 SQL 查询中的所有用户输入进行转义,以确保更高的安全性。
但是,用户已经成功登录了,并拥有了有效的密码。但这并不意味着用户会按照规则进行操作-他有很多机会会造成损害。例如,该应用程序允许用户查看某些特定的内容,所有链接都像“template.php?pid=33”或“template.php?pid=321”这样。URL 中问号后面的部分称为查询字符串或 GET 查询字符串,因为查询字符串直接放在 URL 中,所以也称为 GET 查询字符串。
在 PHP 中,如果禁用了 register_globals,可以使用“$_GET['pid']”来访问该字符串。
因此,必须采取措施防止用户操纵 GET 变量。
<?php
$pid = $_GET['pid'];
//we create an object of a fictional class Page
$obj = new Page;
$content = $obj->fetchPage($pid);
//and now we have a bunch of PHP that displays the page
?>
这段代码存在哪些问题呢?首先,它默认浏览器传来的 GET 变量 pid 是安全的,这是一个隐含的信任。虽然大多数用户不会构造语义攻击,但如果他们注意到浏览器 URL 中的 pid=33,就可能开始捣乱。他们可以输入任何数字,但如果输入 SQL 命令、文件名(如 /etc/passwd)或其他恶意内容,甚至输入长达 3,000 个字符的数值,都可能导致安全问题。
因此,开发人员应该遵循基本规则,不信任用户输入。
在这种情况下,他们可以使用 PHP 的 is_numeric() 函数来确保只接受数字 PID,代码如下:
6、使用 is_numeric() 来限制 GET 变量
<?php
$pid = $_GET['pid'];
if (is_numeric($pid)){
//we create an object of a fictional class Page
$obj = new Page;
$content = $obj->fetchPage($pid);
//and now we have a bunch of PHP that displays the page
}else{
//didn't pass the is_numeric() test, do something else!
}
?>
这个方法似乎是有效的,但是以下这些输入都能够轻松地通过 is_numeric()
的检查:
100 (有效)
100.1 (不应该有小数位)
+0123.45e6 (科学计数法 —— 不好)
0xff33669f (十六进制 —— 危险!危险!)
那么,有安全意识的 PHP 开发人员应该怎么做呢?多年的经验表明,最好的做法是使用正则表达式来确保整个 GET 变量由数字组成,如下所示:
7、使用正则表达式限制 GET 变量
<?php
$pid = $_GET['pid'];
if (strlen($pid)){
if (!ereg(”^[0-9]+$”,$pid)){
//do something appropriate, like maybe logging them out or sending them back to home page
}
}else{
//empty $pid, so send them back to the home page
}
//we create an object of a fictional class Page, which is now
//moderately protected from evil user input
$obj = new Page;
$content = $obj->fetchPage($pid);
//and now we have a bunch of PHP that displays the page
?>
简单地使用 strlen() 函数来检查变量的长度是否为零,然后再使用一个全数字正则表达式来验证数据元素的有效性,即可解决问题。如果 PID 包含字母、斜线、点号或任何类似于十六进制的内容,那么程序会立即捕捉并将该页面屏蔽,避免对用户活动造成潜在威胁。此外,在仔细研究类似Page类的代码实现过程时,我们会发现安全意识较强的PHP开发人员已经对用户输入的 $pid 进行了转义,并有效地保护了 fetchPage() 方法的执行逻辑,这种做法具有很高的安全性和可行性。
<?php
class Page{
function fetchPage($pid){
$sql = “select pid,title,desc,kw,content,status from page where pid='”.mysql_real_escape_string($pid).”'”;
}
}
?>
您可能会问:“既然已经确认 PID 是数字,为什么还需要进行转义?”这是因为我们无法确定在使用 fetchPage() 方法时会出现多少不同的上下文和情况。因此,我们必须在调用该方法的所有地方进行保护,而方法中的转义则体现了纵深防御的意义。
如果用户尝试输入非常长的数值,比如长达 1000 个字符,试图发起缓冲区溢出攻击,那么会发生什么呢?下一节将更详细地讨论这个问题。但是,我们可以添加另一个检查来确保输入的 PID 具有正确的长度。由于数据库的 pid 字段的最大长度是 5 位,因此我们可以添加以下检查来保证输入的 PID 符合要求。
8、使用正则表达式和长度检查来限制 GET 变量
<?php
$pid = $_GET['pid'];
if (strlen($pid)){
if (!ereg(”^[0-9]+$”,$pid) && strlen($pid) > 5){
//do something appropriate, like maybe logging them out or sending them back to home page
}
} else {
//empty $pid, so send them back to the home page
}
//we create an object of a fictional class Page, which is now
//even more protected from evil user input
$obj = new Page;
$content = $obj->fetchPage($pid);
//and now we have a bunch of PHP that displays the page
?>
在数据库应用程序中,现在已经无法塞进一个5,000位的数值,至少在涉及GET字符串的地方不会出现这种情况。想象一下黑客在试图攻击您的应用程序时,因为无法突破而咬牙切齿的样子吧!此外,由于关闭了错误报告,黑客更难进行侦察。
然而,缓冲区溢出攻击却是一个需要警惕的问题。这种攻击试图利用PHP应用程序(或更准确地说,Apache或底层操作系统)中的内存分配缓冲区发生溢出。虽然您可能使用高级语言如PHP编写Web应用程序,但最终还是需要调用C语言(在Apache的情况下)。与大多数低级语言一样,C语言对于内存分配有严格的规则。因此,必须注意缓冲区溢出攻击的风险,以确保应用程序的安全性。
缓冲区溢出攻击是一种利用大量数据向缓冲区发送的攻击方式,通过使部分数据溢出到相邻的内存缓冲区,从而破坏缓冲区或者重写逻辑,从而造成拒绝服务、破坏数据或者在远程服务器上执行恶意代码的危害。
为了防止缓冲区溢出攻击,必须对所有用户输入的长度进行检查。例如,如果有一个表单元素要求输入用户的名字,那么可以在这个域上添加值为40的maxlength属性,并在后端使用substr()函数进行检查。下面是一个简短的示例,包括表单和PHP代码:
9、检查用户输入的长度
<?php
if ($_POST['submit'] == “go”){
$name = substr($_POST['name'],0,40);
}
?>
<form action=”<?php echo $_SERVER['PHP_SELF'];?>” method=”post”>
<p><label for=”name”>Name</label>
<input type=”text” name=”name” id=”name” size=”20″ maxlength=”40″/></p>
<p><input type=”submit” name=”submit” value=”go”/></p>
</form>
提供 maxlength 属性和后端进行 substr() 检查是为了实现纵深防御。浏览器可以防止用户输入超长字符串,而后端 PHP 检查可以确保没有人远程或在浏览器中操纵表单数据。这种方式类似于前一节中使用 strlen() 检查 GET 变量 pid 的长度。
在这个示例中,忽略长度超过 5 位的任何输入值,但也可以轻松地将值截短到适当的长度。
10、改变输入的 GET 变量的长度
<?php
$pid = $_GET['pid'];
if (strlen($pid)){
if (!ereg(”^[0-9]+$”,$pid)){
//if non numeric $pid, send them back to home page
}
}else{
//empty $pid, so send them back to the home page
}
//we have a numeric pid, but it may be too long, so let's check
if (strlen($pid)>5){
$pid = substr($pid,0,5);
}
//we create an object of a fictional class Page, which is now
//even more protected from evil user input
$obj = new Page;
$content = $obj->fetchPage($pid);
//and now we have a bunch of PHP that displays the page
?>
注意,缓冲区溢出攻击不仅限于长的数字或字母串,还可能包含长的十六进制字符串(如\xA3或\xFF)。请记住,缓冲区溢出攻击的目的是淹没特定的缓冲区,并将恶意代码或指令放入下一个缓冲区中,从而破坏数据或执行恶意代码。为了防止十六进制缓冲区溢出,最简单的方法是限制输入的长度。
如果您正在处理允许在数据库中输入较长条目的表单文本区,那么在客户端很难限制数据的长度。但是,在数据到达PHP之后,可以使用正则表达式清除任何类似于十六进制的字符串,以确保数据的安全性。
11、防止十六进制字符串
<?php
if ($_POST['submit'] == “go”){
$name = substr($_POST['name'],0,40);
//clean out any potential hexadecimal characters
$name = cleanHex($name);
//continue processing….
}
function cleanHex($input){
$clean = preg_replace(”![\][xX]([A-Fa-f0-9]{1,3})!”, “”,$input);
return $clean;
}
?>
<form action=”<?php echo $_SERVER['PHP_SELF'];?>” method=”post”>
<p><label for=”name”>Name</label>
<input type=”text” name=”name” id=”name” size=”20″ maxlength=”40″/></p>
<p><input type=”submit” name=”submit” value=”go”/></p>
</form>
您可能会觉得上述操作有些过于严格了。毕竟,十六进制字符串有其合法的用途,例如输出外语中的字符。因此,您可以自行决定如何部署十六进制正则表达式。一个比较好的策略是,只有在一行中包含过多十六进制字符串,或者字符串的字符数超过特定数量(例如128或255)时,才删除十六进制字符串。
在跨站点脚本(XSS)攻击中,恶意用户往往会在表单中(或通过其他用户输入方式)输入信息,将恶意的客户端标记插入过程或数据库中。例如,假设站点上有一个简单的来客登记簿程序,让访问者能够留下姓名、电子邮件地址和简短的消息。恶意用户可以利用这个机会插入简短消息之外的内容,例如不适当的图片或将用户重定向到另一个站点的JavaScript,或者窃取cookie信息。
幸运的是,PHP提供了strip_tags()函数,可以清除任何包围在HTML标记中的内容。strip_tags()函数还允许提供允许标记的列表,例如<b>或<i>。
还有一类浏览器插件允许用户篡改页面上的头部元素和表单元素。例如,使用Tamper Data(一个Mozilla插件),可以很容易地操纵包含许多隐藏文本字段的简单表单,从而向PHP和MySQL发送指令。
用户在点击表单上的提交按钮之前,可以启动Tamper Data。在提交表单时,他会看到表单数据字段的列表。Tamper Data允许用户篡改这些数据,然后浏览器完成表单提交。
尽管我们已经检查了字符串长度、清除了HTML标记并删除了十六进制字符,但是恶意用户仍然可以添加一些隐藏的文本字段,如下所示:
12、隐藏变量
<?php
if ($_POST['submit'] == “go”){
//strip_tags
$name = strip_tags($_POST['name']);
$name = substr($name,0,40);
//clean out any potential hexadecimal characters
$name = cleanHex($name);
//continue processing….
}
function cleanHex($input){
$clean = preg_replace(”![\][xX]([A-Fa-f0-9]{1,3})!”, “”,$input);
return $clean;
}
?>
<form action=”<?php echo $_SERVER['PHP_SELF'];?>” method=”post”>
<p><label for=”name”>Name</label>
<input type=”text” name=”name” id=”name” size=”20″ maxlength=”40″/></p>
<input type=”hidden” name=”table” value=”users”/>
<input type=”hidden” name=”action” value=”create”/>
<input type=”hidden” name=”status” value=”live\”/>
<p><input type=”submit” name=”submit” value=”go”/></p>
</form>
注意,其中一个隐藏变量暴露了表名为“users”,同时还有一个值为“create”的“action”字段。对于有基本 SQL 经验的人来说,这些命令可能控制着中间件中的一个 SQL 引擎。如果想要进行破坏,只需改变表名或提供另一个选项,比如“delete”。
现在还有一个问题需要解决,那就是远程表单提交。
Web 的优点在于可以分享信息和服务,但缺点也在于此,因为有些人会毫无顾忌地进行恶意行为。以表单为例,任何人都可以访问一个 Web 站点,并使用浏览器上的“File > Save As”建立表单的本地副本。然后,他可以修改“action”参数来指向一个完全限定的 URL(不指向“formHandler.php”,而是指向某个站点),进行任何修改,点击“Submit”,服务器会将这个表单数据作为合法通信流接收。
虽然可以考虑检查“$_SERVER['HTTP_REFERER']”来判断请求是否来自自己的服务器,但这种方法只能挡住大多数恶意用户,无法阻止最高明的黑客。这些人足够聪明,能够篡改头部中的引用者信息,使表单的远程副本看起来像是从您的服务器提交的。
更好的处理远程表单提交的方式是,根据一个唯一的字符串或时间戳生成一个令牌,并将这个令牌放在会话变量和表单中。提交表单后,检查两个令牌是否匹配。如果不匹配,就知道有人试图从表单的远程副本发送数据。
要创建随机的令牌,可以使用 PHP 内置的“md5()”、“uniqid()”和“rand()”函数,如下所示:
13、防御远程表单提交
<?php
session_start();
if ($_POST['submit'] == “go”){
//check token
if ($_POST['token'] == $_SESSION['token']){
//strip_tags
$name = strip_tags($_POST['name']);
$name = substr($name,0,40);
//clean out any potential hexadecimal characters
$name = cleanHex($name);
//continue processing….
}else{
//stop all processing! remote form posting attempt!
}
}
$token = md5(uniqid(rand(), true));
$_SESSION['token']= $token;
function cleanHex($input){
$clean = preg_replace(”![\][xX]([A-Fa-f0-9]{1,3})!”, “”,$input);
return $clean;
}
?>
<form action=”<?php echo $_SERVER['PHP_SELF'];?>” method=”post”>
<p><label for=”name”>Name</label>
<input type=”text” name=”name” id=”name” size=”20″ maxlength=”40″/></p>
<input type=”hidden” name=”token” value=”<?php echo $token;?>”/>
<p><input type=”submit” name=”submit” value=”go”/></p>
</form>
这项技术的有效性在于,PHP 中的会话数据无法在服务器之间迁移。即使有人获取了您的 PHP 源代码并将其转移到自己的服务器上,他们向您的服务器提交信息时,您的服务器只会接收到空的或畸形的会话令牌和原来提供的表单令牌。这两者不匹配,因此远程表单提交将会失败。
本站资源部分来自网友投稿,如有侵犯你的权益请联系管理员或给邮箱发送邮件PubwinSoft@foxmail.com 我们会第一时间进行审核删除。
站内资源为网友个人学习或测试研究使用,未经原版权作者许可,禁止用于任何商业途径!请在下载24小时内删除!
如果遇到评论可下载的文章,评论后刷新页面点击“对应的蓝字按钮”即可跳转到下载页面!
本站资源少部分采用7z压缩,为防止有人压缩软件不支持7z格式,7z解压,建议下载7-zip,zip、rar解压,建议下载WinRAR。
温馨提示:本站部分付费下载资源收取的费用为资源收集整理费用,并非资源费用,不对下载的资源提供任何技术支持及售后服务。