Web应用安全之CSRF

来源:互联网 发布:手机版施工软件 编辑:程序博客网 时间:2024/06/05 00:18

  关键处理

  Web应用中,用户登陆后执行操作中,有一些一旦完成就无法撤销,如信用卡支付,修改密码,发送邮件等,这些被称为“关键处理”。
  关键处理中如果存在安全隐患,就会产生名为Cross-Site Request Forgeries简称CSRF的漏洞。
  

  可能会遭受以下攻击:

  1.使用用户的账号购物
  2.删除用户账号
  3.使用用户的账号发布帖子
  4.更改用户的密码或邮箱地址

  1.输入-执行 模式下的攻击手段

  登陆 -- 密码输入 -- 执行更改密码

  需满足3个条件:
  1.用POST方法请求执行更改密码
  2.保持登录状态
  3.用POST参数中的pwd制定新密码
  
  脚本举例:
  <body onload="document.form[0].submit()">
  <form action="http://xxxx.php" method="POST">
  <input type="hidden" name="pwd" value="cracked"
  </form>
  </body>

  一般攻击流程:
  0.用户登录
  1.攻击者设下圈套
  2.受害人浏览恶意网站而触发圈套
  3.攻击者使用恶意网站中的JavaScipt,使受害人的浏览器向攻击对象网站发送将密码变更为cracked的POST请求
  4.密码被更改

  CSRF和XSS区别

  相同点
  1.浏览恶意网站    ->
  2.恶意HTML        <-
  3.攻击用请求       ->

  CSRF是指恶意使用服务器对步骤3中请求的处理,恶意使用的内容仅限于服务器提供的处理。

  XSS情况下3中的请求包含的脚本则被原封不动的以响应的形式返回,随后该恶意脚本在用户的浏览器中执行。由于攻击者能够在用户的浏览器上执行自己准备的HTML或JavaScript,因此只要是浏览器能做到的事都可以被用作攻击手段。攻击者甚至还能够通过JavaScript恶意使用服务器端的功能。

  2.存在确认页面的CSRF攻击

  输入页面和执行页面之间包含确认页面的情况。
  下面以更改邮箱地址的操作为例。

  确认页面将数据传递给你执行页面的方法大体上有两种。一种使用hidden参数(type属性为hidden的input元素),另一种使用会话变量。

  使用hidden参数传递参数

  输入页面中输入的邮箱地址被以hidden参数的形式嵌入在确认页面中,然后又被传递给了执行页面。

  输入->确认
  POST
  <input type="text" name="mail" value="xxx@xxx">
  确认->执行
  hidden
  <input type="hidden" name="mail" value="xxx@xxx”> 

  此模式下的CSRF攻击手段与没有确认页面时的情况相同,这是因为执行页面性输入(HTTP请求)中取得邮箱地址信息这一点与之前例子一样。所以上面介绍的恶意HTML几乎是被直接用来攻击的。

  使用会话变量传递参数

  输入->确认
  POST
  <input name="mail" value="xxx@xxx">
  确认页面 将邮箱地址保存至会话变量
  $_SESSION['mail']=$_POST['mail']
  执行页面 从会话变量中获取邮箱地址
  $mail=$_SESSION['mail']

  攻击阶段:
  1.向确认页面发送POST请求,使邮箱地址保存到会话变量中
  2.伺机打开执行页面

  实现上述两个阶段共计需要用到两个iframe元素。
  iframe1与恶意网页同时打开,并向确认页面发送含有邮箱地址的POST请求。这样一来邮箱地址就被保存到了会话变量中。
  在恶意网页打开10秒钟后,iframe2打开执行页面并完成CSRF攻击。这时,由于邮箱地址已被设置到会话变量中,因此邮箱地址就被更改为了攻击者所指定的邮箱地址,攻击成功。

  安全隐患的产生原因

  CSRF漏洞之所以能产生,是因为Web应用存在以下特性:
  1.form元素的action属性能够指定任一域名的URL
  2.保存在Cookie中的会话ID会被自动发送给对象网站

  1的问题在于,即使是恶意网站,也能够向攻击目标网站发送请求。而2的问题则在于,即使请求经过了恶意网站,会话ID的Cookie值也照样发送,从而导致攻击请求在认证的状态下被发送。

  在HTTP请求中 Referer字段,CSRF指向的是恶意网站,而正常的不是,只有这点差别。
  但是通常情况下,Web应用中并不会检验Referer值,所以如果开发者没有意识去确认该请求是否由正规用户自愿发送,就无法区分两者,会引入CSRF漏洞。

  对策

  防御CSRF的关键为为确认关键处理的请求确实是由正规用户自愿发送的。因此,作为CSRF的防范策略,需执行以下两点:
  1.筛选出需要防范CSRF攻击的页面
  2.使代码有能力辨认是否是正规用户的自愿请求

  筛选出需要防范CSRF攻击的页面

  例如电商网站,需要防范的是‘购买’和‘更改'界面。

  在开发过程中,应当执行以下流程:
  1.在需求分析阶段制作功能一览表,标记出需要执行CSRF防范策略的功能
  2.在概要设计阶段制作页面跳转图,标记出需要执行CSRF防范策略的页面
  2.在开发阶段实施CSRF防范策略
  

  具体开发方法

  确认是正规用户自愿发送的请求
  判断请求是否为正规用户自愿发送的实现方法,有如下3类:

  1.嵌入机密信息(令牌)

  如果在访问需要防范CSRF的页面时,提供第三方无法得知的机密信息的话,那么即使出现非正规用户自愿发送的请求,应用端也能够通过判断得知请求是否合法。称为令牌(Token)
  例子:

  在执行页面的前一个页面
  <form action="xxx.php" method="POST">
  新密码<input name="pwd" type="password"><br>
  <input type="hidden" name="token" value="<?php
  echo htmlspecialchars(session_id(), ENT_COMPAT, 'UTF-8');?>">     嵌入令牌
  <input type="submit" value="更改密码“ >
  </form>
  
  确认令牌(执行页面)
  session_start()
  if(session_id()!==$_POST['token']){         确认令牌
    die('请从正规页面进行操作');  //显示合适的错误信息
  }
  //下面进行关键处理

  有一种令牌叫做一次性令牌,通常需要密码学级别的伪随机数生成器。
  一次性令牌经常用于需要防范重放攻击(Reply Attack)的情况下。指,在监听得到加密的请求后,将该请求原封不动的再次发送而达到伪装的效果。一次性令牌能有效防御重放攻击。
  
  并不推荐用一次性令牌当做防御CSRF的手段。
  1.CSRF攻击与重放攻击毫不相干,因此并非一定要使用一次性令牌
  2.没有证据说明一次性令牌比使用会话ID作为令牌的方法更安全
  3.使用一次性令牌有时会导致正常的操作也出错
  4.不能保证生成一次性令牌的方法一定安全
  

  2.再次输入密码

  除了用来防范CSRF,再次输入密码也被用于其他目的。
  1.在用户下订单前,再次向用户确认购买意向
  2.能够确认此时在电脑前操作的确实是用户本人
  要求再次输入密码应在执行页面。

  3.检验Referer

  实例
  if(preg_match('#\Ahttp://xxx.php#',@$_SWEVWE['HTTP_REFERER'])!==1){
    die('请从正规页面进行操作‘);
  }
 
  检验Referer的方法也有缺陷。因为如果用户设置为不发送Referer,页面就无法正常显示。通过防火墙或浏览器插件等禁止Referer的用户不在少数。
  另外,手机浏览器中也有不发送Referer的浏览器和能够关闭发送Referer功能的浏览器。

  检验Referer时,必须要使用前方一质检所检验绝对URL,包括域名后的/
  代码量最少,其他两种方法需要在2个页面中进行追加处理,而检验Referer方法只需要在执行关键处理的页面上追加处理即可。

   嵌入令牌再次输入密码确认Referer开发耗时中中小对用户影响无增加了输入密码的麻烦关闭了Referer的用户无法正常使用能否用于手机网站可可不可建议使用的地方最基本的防御策略,所有情况下均可使用需要防范他人伪装或者确认需求很强的页面用于能够限定用户环境的既有应用的CSRF防范策略
  
  




  建议执行完关键处理后,向用户注册的邮箱发送有关处理内容的邮件,因为邮件是未经加密的明文传输,不要再邮件中添加重要信息。

  对策总结

  CSRF漏洞根本性防范策略如下
  1.筛选出需要防范CSRF的页面
  2.确认时正规用户自愿发起的请求
  其中,确认请求确实由用户自愿发起的方法有以下三种。
  1.嵌入机密信息(令牌)
  2.再次输入密码
  3.检验Referer
  另外作为CSRF漏洞的辅助性对策,可以执行以下操作。
  1.执行完关键处理后,向用户注册的邮箱发送通知邮件
0 0