深入浅出之Web安全
一、SQL注入
定义:Web应用程序对用户输入数据的合法性没有判断或过滤不严,攻击者可以伪造sql,以此来实现欺骗数据库服务器执行非授权的任意查询,非法获取或篡改数据。
1.1 成因
我们通过一个demo,来帮助大家快速理解:
$username = $_POST['username'];
$password = $_POST['password'];
$sql = "select * from user where username='$username' and password='$password'";
此时参数未做过滤,存在恶意注入风险,此时username真实赋值188,password恶意赋值1’ OR 1='1,即
$sql = "select * from user where username='188' and password='1' OR 1='1'";
可以发现,此时sql就绕过了正常的逻辑判断,攻击者输入真实的账号(如手机号码、撞库的账号)便能轻松完成登录
1.2 应对
1.2.1 参数过滤
针对上述注入,我们发现问题在于单引号导致sql被伪造,常见的做法是对用户提交数据做转义:
$username = addslashes($_POST['username']);
$password = addslashes($_POST['password']);
$sql = "select * from user where username='$username' and password='$password'";
重复上述参数提交,此时获得的是
$sql = "select * from user where username='188' and password='1\' OR 1=\'1'";
这样,我们便完成了简单的防护。其实主流的框架在底层已经帮我们实现了基础过滤,以ThinkPHP3.2接收参数的I()函数为例:
//DEFAULT_FILTER为空
$filters= isset($filter)?$filter:C('DEFAULT_FILTER');
...
if(is_array($filters)){foreach($filters as $filter){if(function_exists($filter)) {$data = is_array($data) ? array_map_recursive($filter,$data) : $filter($data); // 参数过滤} else {$data = filter_var($data,is_int($filter) ? $filter : filter_id($filter));if(false === $data) { return isset($default) ? $default : null;} } }
}
...
is_array($data) && array_walk_recursive($data,'think_filter');
...
//think_filter过滤也很有限
function think_filter(&$value){// 过滤查询特殊字符if(preg_match('/^(EXP|NEQ|GT|EGT|LT|ELT|OR|XOR|LIKE|NOTLIKE|NOT BETWEEN|NOTBETWEEN|BETWEEN|NOTIN|NOT IN|IN)$/i',$value)){$value .= ' ';}
}
PS:永远不要相信用户的输入,主动加以正则验证、长度限制、参数转义,才能有效防护
1.2.2 参数绑定
一次完成的流程包含:
1.获取参数
2.后端接收并转义
3.拼接sql并发送给mysql
4.mysql完成查询返回后端,在后端和mysql通信,也提供了PDO请求方式
<?php
/*通过绑定的 PHP 变量执行一条预处理语句 */
$calories = 150;
$colour = 'red';
$sth = $dbh->prepare('SELECT name, colour, caloriesFROM fruitWHERE calories < ? AND colour = ?');
$sth->bindParam(1, $calories, PDO::PARAM_INT);
$sth->bindParam(2, $colour, PDO::PARAM_STR, 12);
$sth->execute();
?>
进行参数绑定,一方面使得mysql服务器可以做主动过滤(PDO链接时,设定PDO::ATTR_EMULATE_PREPARES => false),另一方面,在同一次访问中,多次类似的sql,mysql只需要解析一次,每次查询只需要发送绑定参数,可节省网络开销
1.2.3 “自爆”
即便我们掌握了注入的原理和应对策略,也只能对当下程式加以防护,但涉及老业务代码,就没那么幸运的被照顾到了,因此,推荐大家应用扫描工具主动扫描(AWVS、APPScan),及时发现并解决隐患。
二、XSS攻击
Cross-Site Scripting(跨站脚本攻击):攻击者通过在目标网站上注入恶意脚本,使之在用户的浏览器上运行。 利用这些恶意脚本,攻击者可获取用户的敏感信息如Cookie、SessionID 等,进而危害数据安全。
XSS在攻击方式上,分为反射型xss和存储型xss,两者最大区别在于反射型xss存储在url内,存储型xss存储在数据库内。
反射型(非持久化):黑客提前设定好攻击URL诱捕用户,点击触发 存储型(持久化):后者利用网站过滤漏洞,将攻击代码注入数据库,访问触发,危害更大
2.1 成因
我们通过实例来快速理解
<input type="text" value="<%= getParameter("keyword") %>">
<button>搜索</button>
<div>您搜索的关键词是:<%= getParameter("keyword") %>
</div>
此时keyword存在注入风险,我们传递非法参数:
https://xxx/search?keyword="><script>alert('XSS');</script>
点击上述链接后,前台会有弹窗提示“XSS”!
解决方案:
- escapeHTML方法对HTML转义
- 链接跳转操作过滤
代码参考:
allowSchemes = ["http", "https"];
valid = isValid(getParameter("redirect_to"), allowSchemes);
if (valid) {<a href="<%= escapeHTML(getParameter("redirect_to"))%>">跳转...</a>
} else {<a href="/404">跳转...</a>
}
2.2 应对
1.参数转义与过滤。通过诸如escapeHTML方法,对传参做过滤。同时可以根据上下文环境,对输入做过滤,比如整数型(年龄)、长度(手机号码)等
2.严格执行CSP安全规范
3.Javascript前端安全规范
XSS除了参数过滤,更多涉及javascript代码安全及前端渲染的知识,这块请大家查询(@美团前端安全系列),非常详尽!
三、CSRF攻击
定义:CSRF(Cross-site request forgery),跨站请求伪造。攻击者通过一些技术手段,欺骗用户的浏览器去访问一个自己登录状态未过期的网站,并执行一些操作(如发邮件,发消息,甚至转账和购买商品等)。
3.1 成因
1、前置:用户再正常网站(Normal WebSite)简称NWeb,完成登录。NWeb站台提供表单请求的转账功能。
www.nweb.com/Pay/transferMoney?targetUser=xxx&money=yyy
点击提交转账信息,则发出请求,完成转账
2、触发:保持上述登录状态,在同一浏览器下,用户被邮件/搜索引擎诱导,打开了恶意网站(Bad WebSite)简称BWeb,上述转账链接,在Bweb站点被用户点击。
www.nweb.com/Pay/transferMoney?targetUser=hacker&money=100
3、结果:用户返回NWeb,则会发现账号资金少了100
不难发现,CSRF攻击与XSS攻击两者极其相似,都是通过漏洞盗取用户信息,进行非法操作。同时,两者的显著区别在于是否需要用户登录状态
3.2 应对
针对上述CSRF漏洞,有两种常规解决方案。
首先是对来源Referer过滤,即判断这个表单请求,是由Bad WebSite发出,我们则给出告警提醒。其次,我们在表单页面加入token令牌标记,在表单请求方法加入token验证,即验签操作。
3.2.1 Referer过滤
只需要在对应的表单提交方法下,加入如下判断
/**
* referer過濾
* $return 1:非法referer;0:正常referer
*/
function isErrorReferer(){//來源判斷$returnValue = 1;$refererUrl = parse_url($_SERVER['HTTP_REFERER']);if (strpos($refererUrl['host'], 'test.com.hk')!==false) {$returnValue = 0;}return $returnValue;
}
当然此方法获取的referer也容易被伪造,因此,推荐下面token令牌方案。
3.2.1 Token令牌
基本思路:
- 生成token存储在session,并输出到当前页面
- 和表单数据一起提交给表单请求接口
- 表单请求接口做token值验证,验证完毕后清空
现在主流的框架,都有提供Token令牌组件,我们以TP3.2为例,为大家做解析: 1、token生成存储在session中,并输出到前端模板
/**
* 系统行为扩展:表单令牌生成
*/
function getToken(){$tokenName= C('TOKEN_NAME',null,'__hash__');$tokenType= C('TOKEN_TYPE',null,'md5');if(!isset($_SESSION[$tokenName])) {$_SESSION[$tokenName]= array();}// 标识当前页面唯一性$tokenKey =md5($_SERVER['REQUEST_URI']);if(isset($_SESSION[$tokenName][$tokenKey])) {// 相同页面不重复生成session$tokenValue = $_SESSION[$tokenName][$tokenKey];}else{$tokenValue = $tokenType(microtime(TRUE));$_SESSION[$tokenName][$tokenKey] =$tokenValue;if(IS_AJAX && C('TOKEN_RESET',null,true))header($tokenName.': '.$tokenKey.'_'.$tokenValue); //ajax需要获得这个header并替换页面中meta中的token值}return array($tokenName,$tokenKey,$tokenValue);
}
2、token令牌与表单一并提交给请求接口
3、表单请求接口,做token令牌验证,验证完毕则清空此次token令牌
function formPostUrl(){//開啟token令牌验证C('TOKEN_ON', true);$model = M(); // 手动进行令牌验证if (!$model->autoCheckToken(I())) {$this->error('您好,請勿重複提交,刷新頁面後再次嘗試,謝謝!'); return false;}//业务代码..
}
function autoCheckToken($data) {// 支持使用token(false) 关闭令牌验证if(isset($this->options['token']) && !$this->options['token']) return true;if(C('TOKEN_ON')){$name = C('TOKEN_NAME', null, '__hash__');if(!isset($data[$name]) || !isset($_SESSION[$name])) { // 令牌数据无效return false;}// 令牌验证list($key,$value)=explode('_',$data[$name]);if($value && $_SESSION[$name][$key] === $value) { // 防止重复提交unset($_SESSION[$name][$key]); // 验证完成销毁sessionreturn true;}// 开启TOKEN重置if(C('TOKEN_RESET')) unset($_SESSION[$name][$key]);return false;}return true;
}
token令牌验证即销毁机制,除了可以防护CSRF跨站伪造请求,还可以判断表单的多次提交,提供额外的风险拦截功能
上述展示的是表单提交,在复杂业务场景中,还包含ajax异步请求数据,从流程上来分析,与表单处理方式是一致的。
四、总结
上述三类安全防护是针对具体的漏洞层面,在其他方面,我们也需要持续加以关注和投入:
1.运维层面。我们也有必要加入WAF(Web Application Firewall)应用防护墙,来提升网站安全性。常见的防护策略包括不限于:高频IP封堵、敏感关键字过滤。
2.业务加固与重构。历史业务逻辑或多或少采用拼接sql,此时如果对参数过滤不严谨,极易出现渗透风险。推荐大家使用工具做模拟注入演练,及早发现并规避问题。
3.安全规范。禁止明文存储密码,书写采用参数绑定语法,工程师电脑定期体检等,对流程加以规范且明确要求,才能降低安全隐患。
4.定期巡检。随着技术日新月异的发展,各种漏洞层出不穷,相应的按时自检必不可少。
互联网安全是老生常谈的课题,但在现今业务优先的开发模式下,对于安全防护,我们做的远远不够,一旦发生安全事故,后果及损失极大。同时,安全防护绝非朝夕之事,需要我们保持警惕,恪守敬畏之心!
参考资料:
XSS攻击模拟与校正# 学习计划安排
我一共划分了六个阶段,但并不是说你得学完全部才能上手工作,对于一些初级岗位,学到第三四个阶段就足矣~
这里我整合并且整理成了一份【282G】的网络安全从零基础入门到进阶资料包,需要的小伙伴可以扫描下方CSDN官方合作二维码免费领取哦,无偿分享!!!
如果你对网络安全入门感兴趣,那么你需要的话可以
点击这里👉网络安全重磅福利:入门&进阶全套282G学习资源包免费分享!
①网络安全学习路线
②上百份渗透测试电子书
③安全攻防357页笔记
④50份安全攻防面试指南
⑤安全红队渗透工具包
⑥HW护网行动经验总结
⑦100个漏洞实战案例
⑧安全大厂内部视频资源
⑨历年CTF夺旗赛题解析