代码安全系列(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,如需转载请自行联系原作者

目录
相关文章
|
前端开发 Java Maven
frontend-maven-plugin
frontend-maven-plugin
927 1
|
存储 数据采集 分布式计算
从 0 到 1 搭建大数据平台之数据采集系统
从 0 到 1 搭建大数据平台之数据采集系统
1382 0
|
存储 中间件 关系型数据库
数据库切片大对决:ShardingSphere与Mycat技术解析
数据库切片大对决:ShardingSphere与Mycat技术解析
1225 0
|
12月前
|
缓存 移动开发 安全
Web安全-HTTP响应拆分(CRLF注入)漏洞
Web安全-HTTP响应拆分(CRLF注入)漏洞
638 8
OWASP ESAPI 预防XSS跨站脚本攻击_xss攻击引入esapi(1)
OWASP ESAPI 预防XSS跨站脚本攻击_xss攻击引入esapi(1)
|
分布式计算 Java Serverless
EMR Serverless Spark 实践教程 | 通过 spark-submit 命令行工具提交 Spark 任务
本文以 ECS 连接 EMR Serverless Spark 为例,介绍如何通过 EMR Serverless spark-submit 命令行工具进行 Spark 任务开发。
722 7
EMR Serverless Spark 实践教程 | 通过 spark-submit 命令行工具提交 Spark 任务
|
前端开发 JavaScript 机器人
从零开始构建一个聊天机器人
【8月更文挑战第7天】构建聊天机器人是一个涉及多个步骤和技术的复杂过程。从前期准备到实际部署,每一步都需要仔细规划和执行。通过不断学习和实践,你可以逐步掌握构建聊天机器人的技巧和方法,为企业创造更大的价值。
|
SQL 安全 JavaScript
Java中的代码审计与漏洞检测
Java中的代码审计与漏洞检测
|
SQL 监控 安全
数据库安全:SQL注入防御实践
【7月更文挑战第11天】SQL注入攻击作为一种常见的网络攻击手段,对数据库的安全性和业务稳定构成了严重威胁。为了有效防御SQL注入攻击,开发者和数据库管理员应采取一系列实践措施,包括输入验证与过滤、使用参数化查询、限制数据库用户权限、使用Web应用程序防火墙、定期更新和打补丁、实施实时监控和审计以及使用HTTPS协议等。通过这些措施的实施,可以显著提升数据库的安全性,降低遭受SQL注入攻击的风险。同时,开发者和数据库管理员应持续关注新的安全威胁和防御技术,不断提升自身的安全防护能力。
|
开发框架 前端开发 JavaScript
ASP.NET Core+Element+SQL Server开发校园图书管理系统(二)
ASP.NET Core+Element+SQL Server开发校园图书管理系统(二)
254 0