密码找回逻辑漏洞—Web安全深度剖析(5)

发表于:2015-5-13 10:16

字体: | 上一篇 | 下一篇 | 我要投稿

 作者:张炳帅    来源:51Testing软件测试网原创

  (51Testing软件测试网获电子工业出版社和作者授权连载本书部分章节。任何个人或单位未获得明确的书面许可,不得对本文内容复制、转载或进行镜像,否则将追究法律责任。)
  1.商品数量为负数
  商品数量为负数的情况多数出现在有站内货币(虚拟币)的网站上,当购买一个产品时,算法一般为"购买数量×商品单价=支付金额",但如果购买数量为负数,比如 5,那么支付金额将会为负数,看下面一段支付代码:
public class Order extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
this.doPost(request, response);
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
User u =    (User) request.getSession().getAttribute("User");
u = new UserBiz().findUserById(u.getId());
int commodityID = Integer.parseInt(request.getParameter("commodityID"));
int number = Integer.parseInt(request.getParameter("number"));
Commodity comm = new CommodityBiz().finCommodityById(commodityID);  //根据ID查询价格商品信息
if(comm.getNumber()<number){
request.setAttribute("message", "商品数量不足,无法购买");
request.getRequestDispatcher("/user/userinfo.do").forward(request, response);
}
double allprice = number * comm.getPrice() ;  //查出总价格
if(u.getMoney()<allprice){   //如果用户金额小于商品金额
request.setAttribute("message", "您的金额不足,请及时充值,还差"+(allprice -user.getMoney())+"个金币");
request.getRequestDispatcher("/user/userinfo.do").forward(request, response);
}
u.setMoney(u.getMoney()-allprice);  //把用户的金币去除
u.getCommodity().add(commodityID);
UserDao userDao = new UserBiz();
boolean flag = userDao.saveOrUpdate(u);   //更新用户金币
comm.setNumber(comm.getNumber()-number);
CommodityDao comDao = new CommodityBiz();
boolean cflag = comDao.saveOrUpdate(comm);
if(flag&& cflag){
request.setAttribute("message", "购买成功,您的余额为:"+u.getMoney());
request.setAttribute("User", u);
request.setAttribute("Commodity ", comm);
request.getRequestDispatcher("/user/userinfo.do").forward(request, response);
}else{
request.setAttribute("message", "购买失败,出现异常情况");
request.getRequestDispatcher("/user/userinfo.do").forward(request, response);
}
}
}
  简单介绍一下上述代码的执行流程。
  ① 从Session中取得User对象,也就是当前用户信息。
  ② 根据User的ID,在数据库中查询当前用户的最新信息。
  ③ 取得商品的ID,根据商品ID查询出商品的详细信息,包括价格、总数量。
  ④ 对商品数量进行判断,如果用户购买数量大于库存数量,则跳转页面,结束购物。
  ⑤ 根据数量计算出总价格。
  ⑥ 判断用户的Money是否大于总价格,如Moeny不够,则跳转页面,结束购物。
  ⑦ 将用户的Money与商品数量重置,然后保存,如果都成功,则进行下一步,否则页面跳转,结束购物。
  ⑧ 将最新的用户信息与商品信息放入Session中。
  这段代码是一个比较常见的购买流程,但却存在安全隐患,那就是用户可以"刷钱"。现在假设用户的Money为100元,商品价格为30元,商品数量为20个。用户购买1个商品后,那么Money就变为70元,商品数量也剩下19个,这属于正规流程。下面来看不正规的流程,也就是最常见的支付逻辑漏洞之一。
  将购买数量修改为 3,然后购买,当这段Servlet在计算价格时,并没有对负数进行验证,而是直接进行运算:30×( 3) =  90,现在的商品价格为 90元。接下来判断用户的金额是否大于 90,这里显然是大于的,所以通过验证,进入下一环节。
  有趣的事情出现了,u.setMoney(u.getMoney()-allprice)的意思是将用户的Money进行重置,我们来算算,100 -( 90) = 190,我们账户中的钱不但没有减少,反增加了90元,如果购买的商品数量越多,那么你刷的"钱"也就越多。
  再来看商品的数量comm. setNumber(comm.getNumber()-number),这句代码的意思是重置商品的数量,也就是原来的商品数量减去购买的数量,为:20 ( 3)=23,商品也是一样,不但没有减少,反而增加了。
  2.0元购买商品
  0元也能购买商品?对,你没听错。下面将介绍一种比较常见的0元商品的逻辑漏洞。
  至今,大多数脚本语言都会支持异常处理机制,而异常处理机制有哪些好处呢?比如,我们的程序正在读取数据库,这时突然断网了,程序无法控制网络是否畅通,如果没有正确处理,则会产生致命的错误,可能程序都会因此而崩溃,而有了异常处理机制后,程序员可以将关键性的代码、可能会出现异常的代码块使用异常处理机制处理,即使这块代码真的出了问题,程序也不会因此问题而使整个软件崩溃,这就是异常处理。
  一个存在BUG的Main.java源码如下:
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.print("请输入一个整数:");
String str =    sc.nextLine();   //接收键盘记录
int num = Integer.parseInt(str);  //将字符串转换为整数
System.out.println("您输入的是:"+num);
}
  当程序运行后,会提示用户输入一个整数,这时输入5,程序将会告诉你"您输入的是5",程序看起来没有什么错误,但如果某个不规矩的用户不输入整数,而是输入"Hello",那么程序又会怎样呢?毫无疑问,程序会崩溃,因为在Java中尝试将一个不是数字的字符串转为整型时,将会抛出一个致命的错误,java.lang.NumberFormatException类型转换异常,相信这个关键字大家并不陌生,在Java语言的SQL注射时可能会经常遇到这个关键字,如图10-17所示。
  
图10-17  类型转换错误
本文选自《Web安全深度剖析》第十章,本站经电子工业出版社和作者的授权。
版权声明:51Testing软件测试网获电子工业出版社和作者授权连载本书部分章节。
任何个人或单位未获得明确的书面许可,不得对本文内容复制、转载或进行镜像,否则将追究法律责任。
32/3<123>
《2023软件测试行业现状调查报告》独家发布~

关注51Testing

联系我们

快捷面板 站点地图 联系我们 广告服务 关于我们 站长统计 发展历程

法律顾问:上海兰迪律师事务所 项棋律师
版权所有 上海博为峰软件技术股份有限公司 Copyright©51testing.com 2003-2024
投诉及意见反馈:webmaster@51testing.com; 业务联系:service@51testing.com 021-64471599-8017

沪ICP备05003035号

沪公网安备 31010102002173号