代码安全系列(2) - Race Condition

简介:

Race Condion 中文名不知道怎么翻译,竞态条件?紊乱条件?冲突条件?在多线程编程过程中,我们常常关心的是我们的线程是否会出现死锁(deadlock)的情况,而忽视Race Condion。到底Race Condtion是什么呢?

Race Condion是在多线程(或者说多个处理过程)情况下,对有些共享资源进行混乱操作,导致整个处理过程变得混乱,引发BUG。

有一个英文解释:

A race condition is any case where the results can be different depending on the order that processes arrive or are scheduled or depending on the order that specific competing instructions are executed.

一个早期传统的Race Condion的例子:

在早期的UNIX版本中,存在一个叫UNIX login的攻击方式。当一个新用户登陆到系统后,需要从root权限切换到user权限,假如在切换过程中一直按ESC键,则会导致权限切换不成功,使得登陆的用户一直具有root权限,从而控制整个计算机。

下面我们用C#来做一个多线程情况下的Race Contion的例子:

复制代码
static  DateTime curTime;
static   void  Main( string [] args)
{
    
for  ( int  i  =   0 ; i  <   10 ; i ++ )
    {
        Thread aThread 
=   new  Thread( new  ParameterizedThreadStart(Run));
        aThread.Start(
" Thread "   +  i.ToString());
        Thread.Sleep(
1000 );
    }
}
static   void  Run( object  threadName)
{
    curTime 
=  DateTime.Now;
    
for  ( int  i  =   0 ; i  <   10 ; i ++ )
    {
        
if  (threadName.ToString()  ==   " Thread0 " )
        {
            Console.WriteLine(
" {0}, Current time is {1} " , threadName.ToString(), curTime.ToLongTimeString());
        }
        Thread.Sleep(
1000 );
    }
}
复制代码

上面的例子中,curTime其实是所有线程实例所同享的,而每个线程的执行函数内又对curTime进行了赋值,因此会引发混乱,导致线程内的curTime被其他线程所修改。我们看输出的结果如下:

复制代码
Thread0, Current time is  11 : 51 : 56
Thread0, Current time is 
11 : 51 : 57
Thread0, Current time is 
11 : 51 : 58
Thread0, Current time is 
11 : 51 : 59
Thread0, Current time is 
11 : 52 : 00
Thread0, Current time is 
11 : 52 : 01
Thread0, Current time is 
11 : 52 : 02
Thread0, Current time is 
11 : 52 : 03
Thread0, Current time is 
11 : 52 : 04
Thread0, Current time is 
11 : 52 : 05
请按任意键继续. . . 
复制代码

 

上面的例子看上去好像可笑,因为稍微有点经验的程序员都不会犯那样简单的错误。然而在实际项目中,在不知不觉中,由于对某些东西有所忽视,则可能导致RaceCondtion。下面我们来看看一个简单的Web程序,我们分别用C#和JAVA来实现。该代码的功能是:

  1. 访问该页面时,若不传入参数c,显示字符串"Empty"
  2. 访问该页面时,若传入了参数c,则显示参数c的内容。

功能很简单,下面是C#版本的实现:

复制代码
public   partial   class  _Default : System.Web.UI.Page 
{
    
private   string  userName  =  "Empty";
    
protected   void  Page_Load( object  sender, EventArgs e)
    {
        
string  name  =  Request[ " c " ];
        
if  ( ! String.IsNullOrEmpty(name))
        {
            userName 
=  name;
        }
        Label1.Text 
=  userName;
    }
}
复制代码

 

接着是Java的Servlet实现(其他不重要代码省略):


复制代码
public   class  HelloServlet  extends  HttpServlet {

    
private  String userName  =   " Empty " ;
    
public   void  doGet(HttpServletRequest request, HttpServletResponse response)
            
throws  ServletException, IOException {
        
        String name 
=  request.getParameter( " c " );
        
if  (name  !=   null )
        {
            userName 
=  name;
        }
        response.setContentType(
" text/html " );
        PrintWriter out 
=  response.getWriter();
        out.println(userName);
        out.flush();
        out.close();
    }
复制代码

 

上面两个版本看上去是那么的一样,真的是一样吗?不是的!C#版本是正确的,而JAVA版本恰恰出现了RaceCondion的问题!很多Servlet开发者常常忽视了,Servlet实际上是一个单件,除非Servlet实现SingleThreadModel接口。当多线程访问时(即多个用户一起访问时),每个线程得到的实际上是同一个Servlet实例,这样的话,他们对实例的成员变量的修改其实会影响到别人。下面是Servlet的多线程机制:

当客户端第一次请求某个Servlet时,Servlet容器将会根据 web.xml配置文件实例化这个Servlet类。当有新的客户端请求该Servlet时,一般不会再实例化该Servlet类,也就是有多个线程在使用这个实例。Servlet容器会自动使用线程池等技术来支持系统的运行,如下图:


因此,我们上面的例子中的userName成员变量其实被所有线程共享,其中某一个线程修改了userName,则其他线程的userName也同样修改。最后我们来试验一下:

首先,我们访问测试页面,不输入任何参数,然后再开一个窗口,测试页面中传入参数c=CoderZh,两个页面显示结果如下:

 

然后,我们刷新不带参数的页面,看看显示的结果:



本文转自CoderZh博客园博客,原文链接:http://www.cnblogs.com/coderzh/archive/2008/12/31/1365994.html,如需转载请自行联系原作者

目录
相关文章
|
存储 中间件 关系型数据库
数据库切片大对决:ShardingSphere与Mycat技术解析
数据库切片大对决:ShardingSphere与Mycat技术解析
1347 0
|
运维 监控 算法
从定时任务-到任务调度系统xxl-job
定时任务的今生前世以及xxl-job调度系统
2902 0
从定时任务-到任务调度系统xxl-job
|
Linux 开发者 iOS开发
QT:基于QMediaPlayer制作的视频播放器(最下方有整合包,可直接运行)
QMediaPlayer是Qt多媒体模块中的一个核心类,它提供了播放音频和视频内容的功能。这个类的设计旨在简化跨平台的媒体播放,使得开发者能够在多种操作系统(如Linux、Windows、macOS及移动平台)上轻松集成多媒体播放能力到他们的应用中,而无需关心底层实现细节。以下是关于QMediaPlayer的一些关键点:
1849 1
|
缓存 移动开发 安全
Web安全-HTTP响应拆分(CRLF注入)漏洞
Web安全-HTTP响应拆分(CRLF注入)漏洞
747 8
OWASP ESAPI 预防XSS跨站脚本攻击_xss攻击引入esapi(1)
OWASP ESAPI 预防XSS跨站脚本攻击_xss攻击引入esapi(1)
|
监控 安全 网络性能优化
什么是可管理和非可管理交换机?
【8月更文挑战第4天】
404 13
什么是可管理和非可管理交换机?
|
SQL 安全 JavaScript
Java中的代码审计与漏洞检测
Java中的代码审计与漏洞检测
|
存储 数据库 C++
"深入剖析Python元组(tuple):与列表的对比、特性解析及高效应用场景展示"
【8月更文挑战第9天】Python元组与列表虽均用于存储元素集合,但有本质差异。元组不可变,创建后无法修改,适合保护数据不被意外更改的场景,如作字典键或传递固定值。列表则可变,支持动态增删改,适用于需频繁调整的数据集。元组因不可变性而在性能上有优势,可用于快速查找。两者各有千秋,根据具体需求选择使用。例如,元组可用于表示坐标点或日期,而列表更适合管理用户列表或库存。
739 1
|
前端开发 JavaScript 机器人
从零开始构建一个聊天机器人
【8月更文挑战第7天】构建聊天机器人是一个涉及多个步骤和技术的复杂过程。从前期准备到实际部署,每一步都需要仔细规划和执行。通过不断学习和实践,你可以逐步掌握构建聊天机器人的技巧和方法,为企业创造更大的价值。
|
开发框架 前端开发 JavaScript
ASP.NET Core+Element+SQL Server开发校园图书管理系统(二)
ASP.NET Core+Element+SQL Server开发校园图书管理系统(二)
286 0