总公司老被攻击,所以总结一下web安全的事项。
一.把握整站的结构,避免泄露站点敏感目录
1.单入口项目(Single Page Application
– SPA
),隐藏index.php
2.常量定义
3.pathinfo eg:Index.php/m/v/c 变 m/v/c
4.路由:对你的路径简化+保护 eg:index/index/login变login
在安全性上,一个入口点文件也能隐藏后台地址。像这样的地址http://localhost/?act=xxx不会暴露后台绝对路径,甚至可以经常更改,不用改变太多代码。一个入口点文件也可以验证访问者的身份,比如一个网站后台,不是管理员就不允许查看任何页面。在入口点文件中就可以验证身份,如果没有登录,就输出错误页面。
有了入口点文件,我就把所有非入口点文件前面加上了这句话:
<?php if(!defined('WWW_ROOT')) {header("Location:error.php"); exit;} ?>
WWW_ROOT是我在入口点中定义的一个常量,如果用户是通过这个页面的绝对路径访问(http://localhost/register.php),我显示错误页面;只有通过入口点访问(http://localhost/?act=register),才能执行后面的代码。
二.不相信用户传到后台的数据,严格的数据验证,你的用户不全是“好”人。
2.1为了确保程序的安全性,健壮性,数据验证应该包括
(1) 关键数据是否存在。如删除数据id是否存在 通过isset来判断 empty
(2) 数据类型是否正确。如删除数据id是否是整数
(3) 数据长度。如字段是char(10)类型则要strlen判断数据长度
(4) 数据是否有危险字符 敏感字符
if(isset($_GET["num"])){
$num=$_GET["num"];
judgeType($num);
judgeLen($num,7);
}
//判断类型
function judgeType($num){
if(is_array($num)){
echo '这是一个数组';
}else if(is_string($num)){
echo '这是一个字符串';
}else if(is_int($num)){
echo '这是一个整数';
}else if(is_float($num)){
echo '这是一个浮点数';
}
}
//判断长度
function judgeLen($str,$len){
$allLen=mb_strlen($str,'utf8');
if($allLen>$len){
echo "长度过长";
}
}
2.2程序员容易漏掉point或者说需要注意的事项:
(1) 进库数据一定要安全验证,之前参与一个公司内部系统开发的时候,见过直接把$_POST数据传给类函数classFunctionName($_POST),理由竟然是公司内部使用的,不用那么严格。暂且不说逻辑操作与数据操控耦合高低问题,连判断都没判断的操作是致命的。安全验证必须,没任何理由推脱。
(2) 数据长度问题,如数据库建表字段char(25),大多phper考虑到是否为空、数据类型是否正确,却忽略字符长度,忽略还好更多是懒于再去判断长度。(这个更多出现在新手当中)
(3) 以为前端用js判断验证过了,后台不需要判断验证。这也是致命,要知道伪造一个表单就几分钟的事,js判断只是为了减少用户提交次数从而提高用户体验、减少http请求减少服务器压力,在安全情况下不能防“小人”,当然如果合法用户在js验证控制下是完美的,但作为phper我们不能只有js验证而抛弃再一次安全验证。
(4)缺少对表单某些属性比如select、checkbox、radio、button等的验证,这些属性在web页面上开发者已经设置定其值和值域(白名单值),这些属性值在js验证方面一般不会验证,因为合法用户只有选择权没修改权,然后phper就在后端接受数据处理验证数据的时候不会验证这些数据,这是一个惯性思维,安全问题也就有了,小人一个伪表单。
(上述的验证方法)
(5) 表单相应元素name和数据表的字段名一致,如用户表用户名的字段是user_name,然后表单中的用户名输入框也是user_name,这和暴库没什么区别。
(最好前端表单的值和数据库的值不要一致,避免暴露数据库)
(6) 过滤危险字符方面如sql防注入和xss攻击
Sql xss csrf
3、防sql注入
pdo—- 预处理语句 最简单最暴力的防注入的方法
Save(); select() update
写原生的sql语句 query(“”);
3.1简单判断是否有注入漏洞以及原理。
网址:http:www.phpben.com/benwin.php?id=1 运行正常,sql语句如:select * from phpben where id = 1
(1) 网址:http:www.phpben.com/ benwin.php?id=1’ sql语句如:select * from phpben where id = 1’ 然后运行异常 这能说明benwin.php文件没有对id的值进行“’” 过滤和intval()整形转换,当然想知道有没有对其他字符如“%”,“#”等都可以用类似的方法穷举测试
SQL 中的 % 标示通配符, 匹配任何字符, 例如:
select * from TableName where name like 'a%';
SQL 中的 # 表示注释的意思从#开始往后就是不再执行
(2)网址:http:www.phpben.com/ benwin.php?id=1 and 1=1 则sql语句可能是 select * from phpben where id = 1 and 1=1,运行正常且结果和http:www.phpben.com/benwin.php?id=1结果一样,则说明benwin.php可能没有对空格“ ”、和“and”过滤
对于一般的Javascript前台验证,由于无法得知用户的行为,例如关闭了浏览器的javascript引擎,这样通过POST恶意数据到服务器。需要在服务器端进行验证,对每个php脚本验证传递到的数据,防止XSS攻击和SQL注入
3.2常见的mysql注入语句。
(1)不用用户名和密码
//正常语句
$sql ="select * from phpben where user_name='admin' and pwd ='123'";
//在用户名框输入’or 1=’1 然后sql如下
$sql ="select * from phpben where user_name='张三 'or 1='1' and pwd ='' ";
sql ="select * from phpben where user_name='benwin'#' and pwd ='$pwd'"; //#代表注释后面语句的意思
这样不用输入密码。
<?php
if(isset($_POST["user"])){
require "db.php";
print_r($_POST);
$num=$_POST["user"];
echo $num;
echo "<br>";
$sql="select * from user where username = '$num' and pwd=''";
echo $sql;
$stmt = $conn->prepare($sql);
$stmt->execute();
$arr=$stmt->fetchAll(PDO::FETCH_ASSOC);
print_r($arr);
}
?>
<html>
<form method="post">
<input type="text" name="user">
<input type="submit" value="提交">
</form>
</html>
3.3 php代码中使用预处理语句来预防sql注入
$stmt = $conn->prepare("SELECT * FROM auser where user=? and pwd=?");
$stmt->execute(["'ljp'#'","123456"]);
$sql="UPDATE auser SET user=? WHERE uid=?";
$stmt = $conn->prepare($sql);
$stmt->execute(["ljpxxxx",2]);
3.3防注入的一些方法
3.3.1 php可用于防注入的一些函数和注意事项。
(1)addslashes 和stripslashes。
Addslashes给这些 “’”、“””、“\”,“NULL” 添加斜杆“\’”、“\””、“\\”,“\NULL”, stripslashes则相反
3.3.2防注入字符。
防注入则要先知道有哪些注入字符或关键字,常见的mysql注入字符有字符界定符号如“'”、“"”;逻辑关键字如“and”、“or”;mysql注悉字符如“#”等; mysql关键字“select|insert|update|delete|*|union|join|into”
3.3.3防注入代码。
(1)参数是数字直接用intval()函数
$id = addslashes($_POST['id']); //
$id = intval($_POST['id']);
对比容易发现,post过来的数据通过addslashes过滤后的确很多注入已经不起作用,再把类型转换
(2)对于文本参数的过滤
文本参数是指标题、留言、内容等可能有“’”,“’”等内容,过滤时不可能全部转义或代替。
function _str_replace($str )
$str = str_replace(" ","",$str);
$str = str_replace("\n","",$str);
$str = str_replace("\r","",$str);
$str = str_replace("'","",$str);
$str = str_replace('"',"",$str);
$str = str_replace("or","",$str);
$str = str_replace("and","",$str);
$str = str_replace("#","",$str);
$str = str_replace("\\","",$str);
$str = str_replace("null","",$str);
$str = str_replace(">","",$str);
$str = str_replace("<","",$str);
$str = str_replace("=","",$str);
$str = str_replace("char","",$str);
$str = str_replace("order","",$str);
$str = str_replace("select","",$str);
$str = str_replace("create","",$str);
$str = str_replace("delete","",$str);
$str = str_replace("insert","",$str);
$str = str_replace("execute","",$str);
$str = str_replace("update","",$str);
$str = str_replace("count","",$str);
return $str;
ps:
对字段进行过滤
pdo —预处理语句占位 传值
还有一些从列表页操作过来的一般href是”phpben.php?action=delete&id=1”,这时候就注意啦,_str_replace($_GET['action'])会把参数过滤掉,一般不用敏感关键字作为参数,比如delete会写成del,update写成edite,只要不影响可读性即可;
4. XSS攻击
大部分的网站一般都有评论功能或留言功能,或类似可以让用户写东西的地方。
如果后台不经过处理,又把数据返回前端,这就会出问题了。网页解析器会把用户的信息也当成html代码给解析了。
如果用户写的是一些恶意的 js 脚本这是很危险的。专业术语叫:XSS 攻击
- 举个例子:假设后台和前台都没有对需要添加的博客的信息进行处理就添加成功了,此时添加了一张图片地址指向的是危险连接。我们输入如下的代码:
if(isset($_POST["news"])){
require "db.php";
print_r($_POST);
echo "<br>";
$num=$_POST["news"];
$sql="insert into news(title,classify_id,content)values(?,?,?)";
echo $sql;
$stmt = $conn->prepare($sql);
$stmt->execute(["新添加的".time(),1,$num]);
页面就会变成这样的
当用户又把信息读取出来的时候就执行了危险的页面http://www.baidu.com 获取通过人家的网址传播 不良信息 或者盗取当前网站的数据。
如果是其他的恶意攻击,是可以入侵到你的服务器然后获取重要数据等操作
防止xss漏洞的方法:
if (isset($_POST['name'])){
$str = trim($_POST['name']); //清理空格
$str = strip_tags($str); //过滤html标签
echo $str;
}
5. csrf攻击防御
csrf攻击,即cross site request forgery跨站(域名)请求伪造,这里的forgery就是伪造的意思。
5.1简单说明CSRF原理
(1)A登录Site1(如现在网民常上的淘宝、微博、QQ等),产生一些信息,session、cookies等等,且一直保持没退出。
(2)A再登录Site2(如一些危险网站,至于怎么跑到Site2,多数是Site通过些手段,邮件欺骗等),打开site2的浏览器和打开site1的一样,否则无效
(3)Site2站中伪造了Site1的http请求(如修改密码,买东西,转账等),Site1的服务器误以为A在site1的正常操作(因为同浏览器且A还没登出),然后就运行了请求,那么csrf已成功操作。
csrf和xss很相似。xss也能伪造请求,csrf也能制造脚本。
伪造的请求可以很多方面,发邮件、改密码、返回用户信息、交易等等,所以相对与xss攻击来说csrf危害更严重。
登陆之后把登陆之后把用户的id记录到了cookie中,当用户访问到demo1.php时 其中包含了另外一个网站的连接 如果不小心点击了 那么就完成了一次csrf的攻击
在csrf.php中实际包含了 危险的操作 比方说通过cookie中的uId更新信息 或者删除信息 等危险操作
5.2防范方法
对于phper
(1)在表单中增加随机的TOKEN 提交的时候再把token提交到服务器端和session的值进行验证
A、B都是某论坛用户,该论坛允许用户“赞”某篇文章,用户点“赞”其实是访问了这个页面:http://localhost/?act=support&articleid=12。这个时候,B如果把这个URL发送给A,A在不知情的情况下打开了它,等于说给articleid=12的文章赞了一次。
所以该论坛换了种方式,通过POST方式来赞某篇文章。
<form action="http://localhost/?act=support" method="POST">
<input type="hidden" value="12" name="articleid">
<input type="submit" value="赞">
</form>
可以看到一个隐藏的input框里含有该文章的ID,这样就不能通过一个URL让A点击了。但是B可以做一个“极具诱惑力”的页面,其中某个按钮就写成这样一个表单,来诱惑A点击。A一点击,依旧还是赞了这篇文章。
最后,该论坛只好把表单中增加了一个验证码。只有A输入验证码才能点赞。这样,彻底死了B的心。
但是,你见过哪个论坛点“赞”也要输入验证码?
这种方式是所推荐的最好的方式,就是在表单中加入一个随机字符串token(由php生成,并保存在SESSION中),如果用户提交的这个随机字符串和SESSION中保存的字符串一致,才能赞。
在B不知道A的随机字符串时,就不能越权操作了。
也多次使用了TOKEN,不管是GET方式还是POST方式,通常就能抵御99%的CSRF估计了。
<input type="hidden" value="{TOKEN}" name="token">
(5) 如果遇到比较专业点的hacker,例如php中存在抓取页面数据的扩展叫curl 可以原原本本的以本网站的访问情形来获取数据 实现csrf的攻击
登陆时的token也可以获取,session也可以生成
避免通过curl手段攻击的方法
其一:可以通过ajax获取token 获取的时间可以通过计时器来控制一下,这样抓取方 不能立刻就把数据获取到了
其二:统计客户IP 如果访问特别的频繁的话 记录为黑名单等手段
这是一个hacker与程序员攻防的过程,针对攻进行防,针对防进行攻!
6. 严格控制上传文件类型
上传漏洞是很致命的漏洞,只要存在任意文件上传漏洞,就能执行任意代码,拿到webshell。
我在上传这部分,写了一个php类,通过白名单验证,来控制用户上传恶意文件。在客户端,我通过javascript先验证了用户选择的文件的类型,但这只是善意地提醒用户,最终验证部分,还是在服务端。
白名单是必要的,你如果只允许上传图片,就设置成array('jpg','gif','png','bmp'),当用户上传来文件后,取它的文件名的后缀,用in_array验证是否在白名单中。
7. 使用加密算法保存数据库中重要信息
8. 验证码安全性
注意点:
1)验证码验证完之后及时清除cookie或者session中的值
2)在前台img src 验证码的php文件加上随机数 可以保证每次获取的数据都不一样
9.在项目上线之后需要关闭错误提示,开发过程中开启错误提示
找到php.ini修改下面代码即可
Checkmarx 工具用来扫描漏洞
原文链接:https://blog.csdn.net/weixin_42165130/article/details/83306255
原创文章,作者:优速盾-小U,如若转载,请注明出处:https://www.cdnb.net/bbs/archives/17600