前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >掌握XSS与CSFR,我也可以是个黑客!

掌握XSS与CSFR,我也可以是个黑客!

作者头像
JAVA葵花宝典
发布2019-10-08 17:12:16
6610
发布2019-10-08 17:12:16
举报
文章被收录于专栏:JAVA葵花宝典

今天呀,我想当一名黑客,去黑别人的网站!我有两三技能,独乐不如众乐乐,今天我也把这个几个攻击手段教给你,咱们一起搞事情去。

首先我们来了解一下攻击手段,也是比较常见的两种攻击手段了:

  • 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地址如下:

代码语言:javascript
复制
http://www.cunqianwang.com/zhuanzhang?account=A&for=B&amount=500

那么,一个垃圾网中可以放置如下代码

代码语言:javascript
复制
<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字段值代码是:

代码语言:javascript
复制
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
代码语言:javascript
复制
<form action="/submit" method="post">
    名称:<input name="name" value="${name}">
    <input type="submit">
</form>

controller中有个基本跳转,还有form表单的提交:

  • com.example.IndexController#index
代码语言:javascript
复制
@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,基本逻辑也写好了,一个简单的表单提交,提交之后如果数据不对,或格式不对就会返回表单页面,同时回显表单数据。

加入我想嵌入脚本如下:

代码语言:javascript
复制
<script>alert(1);</script>

那么我该怎么样才能往这个页面上嵌入代码呢?我打开F12,研究一下

要是这个这个脚本能提到input的外面,value能提前结束就好了。嘿嘿,突然想到,既然我改不了原来的,那么我就创造一个。

于是我改了一下输入的值成:

代码语言:javascript
复制
"><script>alert(1);</script>

这">不就跑到前面了嘛,哈哈哈,天才,我赶紧试试。谷歌浏览器测试结果如下:

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

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

我换个Edge浏览器再试试:

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

没毛病,原声原味的alert(1);

好了上面我们已经弄懂了xss的嵌入脚本的方式,我们输入是合法的,只是内容有点取巧,这就是xss的攻击手段。

除了这个input标签,其实还有很多标签比较常用,比如title、a、img、script等。

上面这个一般都是反射性的xss攻击,我们再来看看一个存储类型的title的例子。

在很多博客中,我们都可以发布文章,我们需要写文章标题,文章内容等,文章标题一般我们还会放在我们的head的title中,用于标签展示当前浏览文章标题。

加入说,我们的页面是这样展示的:

  • title.ftl
代码语言:javascript
复制
<!DOCTYPE html>
<html>
<head>
    <title>${title}</title>
</head>
<body>
    这是内容 - ${content}
</body>
</html>

而controller中传过来的内容如下:

  • IndexController
代码语言:javascript
复制
@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
代码语言:javascript
复制
#识别攻击脚本、并删掉对应可执行脚本的标签
HTMLFilter
#全局过滤器,包装request
XssFilter
#包装request,重写request的几个重要方法,比如getParameter等
XssHttpServletRequestWrapper

所以renren-fast项目的设计逻辑是加入一个全局过滤器,然后通过包装请求的request,重写request的getParameter、getHeader、getInputStream等方法,在这些方法里面都进行一遍过滤,从而去掉所有的攻击脚本。看看重要代码:

  • io.renren.common.xss.XssFilter
代码语言:javascript
复制
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
代码语言:javascript
复制
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方法代码如下:

代码语言:javascript
复制
private String xssEncode(String input) {
    return htmlFilter.filter(input);
}

ok,相信你已经弄明白了。

我们来看看另一个博客项目mblog的解决方法:

  • mblog
代码语言:javascript
复制
#通用控制器
BaseController

#自定义编辑器
StringEscapeEditor

mblog项目其实是通过注册所有controller的自定义编辑器,在提交表单时候对所有字段都进行一层get和set,在set的过程中对输入内容进行一番检查,如果有脚本就进行替换等操作。

详细代码如下:

  • BaseController
代码语言:javascript
复制
@InitBinder
public void initBinder(ServletRequestDataBinder binder) {

    /**
     * 防止XSS攻击
     */
    binder.registerCustomEditor(String.class, new StringEscapeEditor(true, false));

    ...
}

@InitBinder用于表单到方法的数据绑定的,这里绑定了一个自定义编辑器StringEscapeEditor。

  • StringEscapeEditor

可以看到setAsText中就是对脚本进行过滤等操作的。

这两种方法都学会了吗?其实逻辑都是对脚本进行过滤替换删除等操作。

学会攻击

好了,又到了黑客show time,某个知名博客平台没防御xss攻击,这时候我发布了一篇文章,title中包含了脚本

代码语言:javascript
复制
<script>alert("刘亦菲,我爱你");</script>

于是,全世界都知道我的表白,我们最后开心得在一起了。

真是浪漫有爱,又爱做白日梦的黑客,鼓掌,鲜花~

结束语

文中涉及到的项目:

  • renren-fast:https://gitee.com/renrenio/renren-fast.git
  • mblog:https://gitee.com/mtons/mblog.git

好啦,今天的文章先到这里了。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2019-09-29,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 JAVA葵花宝典 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1、检查referer字段
  • 2、Token 验证
  • 3、添加图片验证码、短信验证等
  • 学会攻击
  • 攻击形态
  • 攻击手段
  • 解决方法
  • 学会攻击
相关产品与服务
云服务器
云服务器(Cloud Virtual Machine,CVM)提供安全可靠的弹性计算服务。 您可以实时扩展或缩减计算资源,适应变化的业务需求,并只需按实际使用的资源计费。使用 CVM 可以极大降低您的软硬件采购成本,简化 IT 运维工作。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档