掌握XSS与CSFR,我也可以是个黑客!
- 2019 年 10 月 6 日
- 筆記

今天呀,我想当一名黑客,去黑别人的网站!我有两三技能,独乐不如众乐乐,今天我也把这个几个攻击手段教给你,咱们一起搞事情去。
首先我们来了解一下攻击手段,也是比较常见的两种攻击手段了:
- CSRF
- XSS
CSRF
全称:Cross-site request forgery,跨站请求伪造。原理是:通过伪装成受信任用户的请求来攻击受信任的网站。
如何伪装?如何才算攻击?
生活中其实我们不缺这种例子,比如说我们经常接收到一些来历不明的垃圾短信,短信内容里面有个url链接,有些人手贱点开了链接,然后就发现钱不见了!!
我们从技术角度来复原一下这个过程,首先设定一些基础:
- 垃圾短信里的链接(垃圾网):http://www.lajiwang.com/pianqian
- 存了钱的网站(存钱网):http://www.cunqianwang.com/
然后用户动作是:点开了垃圾网的链接,但是存钱网里账户的钱不见了。既然是自己账户的钱不见了,所以这里其实有个前提:用户已经登录了存钱网!所以准确来说用户的动作是这样的:点开了垃圾网的链接,但是之前登录过的存钱网里账户的钱不见了!
两个网站毫无关联,为啥会造成这个让人意想不到的后果呢?
其实呀,垃圾网的人为了达到攻击的目的,偷偷在网页上嵌入了存钱网的链接,所以打开垃圾网时候顺便也触发了存钱网的转账的链接,整体逻辑如下:
- 1、用户登录成功存钱网,于是浏览器中产生了网站cookie
- 2、用户在没有退出存钱网的情况下,访问了垃圾网
- 3、垃圾网要求访问存钱网的转账url,转账url带上存钱网的cookie去访问服务器
- 4、存钱网服务器验证转账url确认是用户在转账,转账成功!
说到这里,你发现漏洞在哪里没有?大家都知道cookie代表用户身份,每次发起请求,请求头里都会附上用户的cookie信息,既然cookie是存在浏览器的,我偷不到你的cookie,那么我就让你在不知道到的情况下让你自己去操作。
举个例子:假如一家银行转账操作的URL地址如下:
http://www.cunqianwang.com/zhuanzhang?account=A&for=B&amount=500
那么,一个垃圾网中可以放置如下代码
<img src="http://www.cunqianwang.com/zhuanzhang?account=A&for=B&amount=500">
好了,原理和攻击手段我们都懂了,那么我们来说说几种常见的预防手段:
1、检查referer字段
HTTP头中有一个Referer字段,这个字段是用来标明请求来源于哪一个网址。当网站A去访问网站B的资源时候,链接上的请求头上就会有Referer字段。注意是在不同域名下才有。
我随意打开hao123.com的首页,一些图片不是放在hao123.com域名下的,所以会在header中带上Referer字段表示请求源是hao123.com。

那么服务器可以通过判断Referer字段来判断请求的来源。所以在垃圾网站里访问存钱网,Referer的值就是垃圾网的域名,就能判断是不是合法的操作啦。
java代码里获取Referer字段值代码是:
String referer = request.getHeader("Referer");
这种方法简单易行,但也有其局限性。http协议无法保证来访的浏览器的具体实现,可以通过篡改Referer字段的方式来进行攻击,所以就要看你用的浏览器高级不高级了,如果你用的浏览刚好是骗子开发的浏览器,嘿嘿~~
2、Token 验证
既然我们要判定用户行为的合法性,那么我就给用户颁发一个合法token,除了带上cookie,还得带上token才行,token在前一个步骤中获取。
逻辑如下:
- 服务器发送给客户端一个token;
- 客户端提交的表单中带着这个token。
- 如果这个 token 不合法,那么服务器拒绝这个请求。
3、添加图片验证码、短信验证等
重要步骤添加验证码认证后才能操作。脑补,略略略略~
学会攻击
好了,作为一名出色的黑客,必须要知道自己攻击手段的漏洞在哪,怎么防御,绝不做无用功!既然预防手段我知道了,那么接下来就是我展现真正技术的时候了。
嘿嘿,很多公司在一开始的时候为了节约成本,选择用开源项目作为基础,然后再二次开发。虽说开发快,但其实未必安全,一些开源项目如果没有做csrf的预防,那么漏洞就一直存在。
经过我多天的研究,终于发现了某个商城用的是开源项目二次开发的,没有csrf预防。商城的积分可以直接赠送给别人,我立马搞了个网页,嵌入网站赠送积分的链接。
于是有了我和我朋友的对白。
- 我:小明呀,你的A商城还有多少积分呀?
- 小明:2000多吧?
- 我:这么多?我不信!你登录让我看看!
- 小明去登录A网站给我看积分,果然2000多。
- 我:小明呀,我开发了个网站,我发给你看看能不能打开
- 小明打开网站,小明的积分到我账户了~
当黑客感觉真好,小明,你是个好人~
XSS
全程:Cross Site Scripting,中文:跨域脚本攻击。原理:不需要你做任何的登录认证,通过合法的操作(比如在url中输入、在评论框中输入),向你的页面注入脚本(可能是js、hmtl代码块等),类似于SQL注入。
通俗点讲就是:恶意攻击者往Web页面里插入恶意html代码,当用户浏览该页之时,嵌入其中Web里面的html代码会被执行,从而达到恶意用户的特殊目的。
讲再细点其实就是:利用输入内容来闭合对应的html标签,从而执行输入内容的脚本。
攻击形态
xss有两种形态(网友总结):
- 1、反射型
发出请求时,XSS代码出现在url中,作为输入提交到服务器端,服务器端解析后响应,XSS代码随响应内容一起传回给浏览器,最后浏览器解析执行XSS代码。这个过程像一次反射,所以叫反射型XSS。
- 2、存储型
存储型XSS和反射型XSS的差别在于,提交的代码会存储在服务器端(数据库、内存、文件系统等),下次请求时目标页面时不用再提交XSS代码。
攻击手段
不管是什么类型,你get到关键点没有?关键点以及技术难点其实在于如何往页面中嵌入恶意的代码。
下面我们来写个例子模拟一下:首先我页面写了个form表单:
- index.ftl
<form action="/submit" method="post"> 名称:<input name="name" value="${name}"> <input type="submit"> </form>
controller中有个基本跳转,还有form表单的提交:
- com.example.IndexController#index
@GetMapping("") public String index(HttpServletRequest request) { request.setAttribute("name", "公众号:java思维导图"); return "index"; } @PostMapping("/submit") public String submit(HttpServletRequest request) { String name = request.getParameter("name"); System.out.println("name---------->" + name); // 假装只有名字为“求关注”才能通过 if(!name.equals("求关注")) { request.setAttribute("name", name); } return "index"; }
初始效果如下:

ok,基本逻辑也写好了,一个简单的表单提交,提交之后如果数据不对,或格式不对就会返回表单页面,同时回显表单数据。
加入我想嵌入脚本如下:
<script>alert(1);</script>
那么我该怎么样才能往这个页面上嵌入代码呢?我打开F12,研究一下

要是这个这个脚本能提到input的外面,value能提前结束就好了。嘿嘿,突然想到,既然我改不了原来的,那么我就创造一个。
于是我改了一下输入的值成:
"><script>alert(1);</script>
这">不就跑到前面了嘛,哈哈哈,天才,我赶紧试试。谷歌浏览器测试结果如下:

脚本的确跑到外面了,但是alert(1)怎么不见了呀,我赶紧调试一下:

不是后端在搞事情,那么真相就只有一个,谷歌浏览器在搞事情,谷歌果然强大,还能辨别我的脚本并和谐掉。
我换个Edge浏览器再试试:

哇,果然Edge你最帅,我想要的你都给我~ F12看下:

没毛病,原声原味的alert(1);
好了上面我们已经弄懂了xss的嵌入脚本的方式,我们输入是合法的,只是内容有点取巧,这就是xss的攻击手段。
除了这个input标签,其实还有很多标签比较常用,比如title、a、img、script等。
上面这个一般都是反射性的xss攻击,我们再来看看一个存储类型的title的例子。
在很多博客中,我们都可以发布文章,我们需要写文章标题,文章内容等,文章标题一般我们还会放在我们的head的title中,用于标签展示当前浏览文章标题。

加入说,我们的页面是这样展示的:
- title.ftl
<!DOCTYPE html> <html> <head> <title>${title}</title> </head> <body> 这是内容 - ${content} </body> </html>
而controller中传过来的内容如下:
- IndexController
@GetMapping("/title") public String title(HttpServletRequest request) { request.setAttribute("title", "</title><script>alert('公众号java思维导图');</script>"); request.setAttribute("content", "内容是关注公众号:java思维导图"); return "title"; }
最后我们的得到的页面展示这样子:加载时候先执行弹窗:alert("公众号java思维导图");然后再加载内容。

因为一般我们文章标题内容都是保存到数据库的,所以每次渲染都会执行脚本,所以是个存储型xss攻击。
解决方法
好了,看了我们的例子项目,我们已经意识到了xss攻击的可怕性,一单发布文章都可以写脚本,那么所有的用户打开这篇文章都会被执行脚本,影响可就大了。那么有什么好的解决方法吗?
这里给大家介绍几个解决方法。我们先来看renren-fast项目是怎么解决这个问题的:
- renren-fast
#识别攻击脚本、并删掉对应可执行脚本的标签 HTMLFilter #全局过滤器,包装request XssFilter #包装request,重写request的几个重要方法,比如getParameter等 XssHttpServletRequestWrapper
所以renren-fast项目的设计逻辑是加入一个全局过滤器,然后通过包装请求的request,重写request的getParameter、getHeader、getInputStream等方法,在这些方法里面都进行一遍过滤,从而去掉所有的攻击脚本。看看重要代码:
- io.renren.common.xss.XssFilter
public class XssFilter implements Filter { public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { XssHttpServletRequestWrapper xssRequest = new XssHttpServletRequestWrapper( (HttpServletRequest) request); chain.doFilter(xssRequest, response); } ... }
- io.renren.common.xss.XssHttpServletRequestWrapper
public class XssHttpServletRequestWrapper extends HttpServletRequestWrapper { @Override public String getParameter(String name) { String value = super.getParameter(xssEncode(name)); if (StringUtils.isNotBlank(value)) { value = xssEncode(value); } return value; } ... }
可以看到上面的xssEncode就是进行过滤脚本的方法;xssEncode方法代码如下:
private String xssEncode(String input) { return htmlFilter.filter(input); }
ok,相信你已经弄明白了。
我们来看看另一个博客项目mblog的解决方法:
- mblog
#通用控制器 BaseController #自定义编辑器 StringEscapeEditor
mblog项目其实是通过注册所有controller的自定义编辑器,在提交表单时候对所有字段都进行一层get和set,在set的过程中对输入内容进行一番检查,如果有脚本就进行替换等操作。
详细代码如下:
- BaseController
@InitBinder public void initBinder(ServletRequestDataBinder binder) { /** * 防止XSS攻击 */ binder.registerCustomEditor(String.class, new StringEscapeEditor(true, false)); ... }
@InitBinder用于表单到方法的数据绑定的,这里绑定了一个自定义编辑器StringEscapeEditor。
- StringEscapeEditor

可以看到setAsText中就是对脚本进行过滤等操作的。
这两种方法都学会了吗?其实逻辑都是对脚本进行过滤替换删除等操作。
学会攻击
好了,又到了黑客show time,某个知名博客平台没防御xss攻击,这时候我发布了一篇文章,title中包含了脚本
<script>alert("刘亦菲,我爱你");</script>
于是,全世界都知道我的表白,我们最后开心得在一起了。

真是浪漫有爱,又爱做白日梦的黑客,鼓掌,鲜花~
结束语
文中涉及到的项目:
- renren-fast:https://gitee.com/renrenio/renren-fast.git
- mblog:https://gitee.com/mtons/mblog.git
好啦,今天的文章先到这里了。
如果你喜欢我的文章,欢迎关注我的公众号:java思维导图,给我点个在看或者转发一下,万分感谢哈!