【SDL实践指南】Foritify数据流规则

admin 2023年4月2日01:26:58评论96 views字数 33433阅读111分26秒阅读模式

基本介绍

Fortify静态代码分析器数据流分析器可以发现涉及污染数据(用户控制的输入)的安全问题,这些数据被用于潜在的危险用途,数据流分析器使用过程间污染传播分析来检测源(用户输入站点)和汇点(危险的函数调用或操作)之间的数据流,数据流分析使Fortify静态代码分析器能够准确识别许多不同类型的安全问题,比较常见的例子是SQL注入,在SQL注入中程序最终使用从污染源(例如:HTTP请求参数)获取的污染数据来构造和调用SQL查询(污染接收器),当分析器检测到这一点时,数据流分析器会报告SQL注入问题

核心概念

Taint Sink

Taint Sink是受污染数据不能流向的程序点,当数据流分析器检测到受污染数据可以从源流向汇点的路径时,它会报告问题,污染接收器规则可以包含一个条件表达式,通过检查污染标志可以限制报告以接收器结尾的路径,常见示例包括:

  • 获取SQL字符串并对数据库连接执行查询的函数 

  • 获取字符串并执行字符串所描述的命令的函数 

  • 对由基础框架自动写入网页的变量的赋值、

Taint Write

污点写入是通过写入操作引入的污染源,污点写入的常见示例包括写入变量,该变量用作:

  • 字段访问

  • 变量访问

  • 数组访问

  • 函数调用的参数

  • 函数调用的实例对象

Taint Flags

污染标志是污染数据的一个属性,它使数据流分析器能够区分不同类型的污染,因为它使数据流分析器能够准确地识别问题,例如:来自Web应用程序的HTTP参数和本地配置文件的输入可能被污染,每种情况下的攻击向量都大不相同,攻击者可以轻松操纵HTTP参数,在系统上操作配置文件要困难得多

这里我们考虑一个检查SQL元字符输入的函数,受污染的数据通过此函数后可以安全地将其用于SQL注入的污点接收器,然而您不能认为数据未被污染,在其他环境中使用它仍然很危险,例如用于命令注入的污点接收器,在规则中使用污染标志使数据流分析器能够确定受污染的数据在特定上下文中是否安全

程序中的每个污点路径都带有一组污点标志,数据流分析器可以添加或删除源于污染源点的污染标志,因为污染通过程序中的传递和清除点,污染接收器可以检查是否存在污染标志以确定数据流分析器是否报告从源到接收器的路径

Taint Path

当数据流分析器在应用程序中找到源和sinkC之间的一个或多个污染路径时,它会报告一个漏洞,污染路径包含一系列方法调用、存储(赋值变量或字段)和加载(从变量或字段读取),它表示污染数据从污染源点传播到污染源点的路径,事实上因为程序可以包含循环或递归,所以可以有无限多的路径,由于性能问题数据流分析器无法考虑从源到接收器的所有污染路径,但是它确实会考虑应用了一组唯一的污染标志的每个路径,一些污染标志表示某些内容已验证,这意味着数据流分析器不会报告该路径上的问题,如果存在未验证数据的其他路径,Dataflow Analyzer将报告问题

Taint Source

污点数据通过一个称为污染源的程序点进入程序,污染源是函数和方法调用、变量和字段访问以及从源代码中显式调用的引入污染输入的其他表达式,常见示例包括:

  • 从网络源(例如:HTTP请求)读取数据的函数  

  • 从不受信任的数据源(例如:其他程序写入的数据库读取数据的函数  

  • 访问存储从用户收集的输入的字段

Taint Cleanse

污点清洗被去除或修改的点,通常这是一个验证函数,有两种类型的污点清洗点:

  • 部分清除:指定添加或删除污染标志的规则,在本例中数据仍然受到污染,但污染标志Closed集发生了变化

  • 完整清洗规则:描述不指定要添加或删除的污染标志的污染清洗,此时Dataflow AnalyzerClosed完全停止污染传播

清理规则始终是扫描期间应用的最后一组规则,如果清除规则Closed与函数调用、字段、变量或其他代码构造匹配则清除规则将应用于污点路径Closed的顶部,它在匹配相同代码构造的任何传递规则之后应用,通常可以根据传递或清除规则来描述代码构造

Taint Entrypoint

污染入口点是一种特殊类型的污染源,它描述了使用来自环境、框架或传递的参数的污染输入调用的函数,一些编程框架调用应用程序中的函数,而不在用户代码中进行任何显式调用,例如:main()函数在大多数现代编程语言中很常见,在执行过程中充当入口点,操作系统在运行时调用用C或C++编写的main()函数可执行文件,Java运行时环境调用Java应用程序中的main()函数,当首次访问包含applet的页面时以及当浏览器关闭时,web浏览器中运行的JVM分别调用Java applet中的init()和destroy()函数,常见示例:

  • 用命令行上指定的参数调用的程序的主函数 

  • WEB应用程序框架中的一个函数,由框架使用输入参数直接调用 

  • 带有注释的函数的参数,该注释指示基础框架使用输入参数调用函数

Validation Constructs

最基本的规则编写任务之一是为验证构造(如验证函数)编写规则,您可以通过编写传递或清除规则来完成此操作,合适的规则取决于具体情况,在函数完全验证所有情况下的输入的情况下一个完整的清除规则(它可以删除所有污点)是合适的,在大多数情况下最好在污点路径中添加一个污点标志,以指示执行了某种类型的验证

Taint Passthrough/Transfer

数据流分析器自动跟踪数据并传播源代码中定义的函数的污点(传递行为),您必须使用规则对外部定义的函数(源代码不可用于翻译,例如JDK库中的函数)进行传递行为建模,例如默认的Fortify安全编码规则包包含描述StringBuilder.append()传递行为的规则,传递或污染传输规则可能会从受污染的数据中添加或删除污染标志

规则类型

数据流分析需要定义源和Sink规则以标记跟踪受污染数据的数据流路径的端点,了解数据流路径上发生的各种操作的上下文可以导致更精确的规则并可以减少分析期间报告的误报数量,您只能使用数据流规则来定义函数调用周围的污染源、接收器和传递,污染特征化规则提供了一种指定数据流中各种函数的执行上下文特征的方法,您还可以使用污点特征化规则通过任意表达式跟踪受污染的数据,这为数据流跟踪中的各个节点创建了更简洁的约束,污染特征化规则被认为是数据流规则的超集,下表总结了可用于表示各种数据流分析器规则概念的规则类型

【SDL实践指南】Foritify数据流规则

规则结构

以下示例显示了数据流规则的一般XML结构

<CharacterizationRule formatVersion="22.1" language="...">  <RuleID>...</RuleID>  <MetaInfo>...</MetaInfo> <!-- TaintSink only -->  <VulnKingdom>...</VulnKingdom> <!-- TaintSink only -->  <VulnCategory>...</VulnCategory> <!-- TaintSink only -->  <VulnSubCategory>...</VulnSubcategory> <!-- TaintSink only -->  <Description>...</Description> <!-- TaintSink only -->  <StructuralMatch><[CDATA[   ...  ]]></StructuralMatch>  <Definition><![CDATA[   ...  ]]><Definition></CharacterizationRule>

下表描述了上一个示例中所示的特征化规则中引入的XML元素:

  • StructuralMatch:使用一个或多个结构查询指定规则应在代码中匹配的内容,这与结构规则中的<Predicate>元素相同,将此元素的内容封装在CDATA部分中,以避免需要转义XML特殊字符

  • Definition:指定规则类型(TaintSource、TaintWrite、TaintEntrypoint、TantLink、TaintTransfer或TaintCleanse)、污染的输入/输出参数、添加污染和污染标志约束,将此元素的内容封装在CDATA部分中,以避免需要转义XML特殊字符

规则定义

Source Rules

使用数据流分析器源规则来识别污染数据进入程序的点,以下示例显示了一个数据流源规则,该规则将Java方法ServletRequest.getParameter()标识为受污染的数据源

<DataflowSourceRule formatVersion="22.1" language="java">  <RuleID>82EBC382-1341-4A81-9FA0-3A9AF3D3EFDA</RuleID>  <FunctionIdentifier>    <NamespaceName>      <Pattern>javax.servlet</Pattern>    </NamespaceName>    <ClassName>      <Value>ServletRequest</Value>    </ClassName>    <FunctionName>      <Value>getParameter</Value>    </FunctionName>    <ApplyTo implements="true" overrides="true" extends="true"/>  </FunctionIdentifier>  <OutArguments>return,this</OutArguments>  <TaintFlags>+WEB,+XSS</TaintFlags></DataflowSourceRule>

下面描述了在上一个示例中显示的数据流源规则中引入的XML元素

  • OutArguments:确定将污点引入应用程序的方法参数

  • TaintFlags:指定要与规则匹配的方法引入的污点关联的污点标志(可选)

您还可以将前面的数据流源规则编写为两个污点特征化规则:

  • TaintSource用于污染方法调用的返回值

  • TaintWrite以污染调用方法的请求对象

以下示例显示了一个TaintSource特征化规则,该规则相当于在上一个<DataflowSourceRule>的<OutArgument>中污染返回值:

<CharacterizationRule formatVersion="22.1" language="java">  <RuleID>75A7A75E-BBB7-44CB-B12C-CE13D0DE3DC8</RuleID>  <StructuralMatch><![CDATA[    FunctionCall call: call.function is      [Function f: f.name == "getParameter" and   f.enclosingClass.supers contains        [Class c: c.name == "javax.servlet.ServletRequest"]]  ]]></StructuralMatch>  <Definition><![CDATA[    TaintSource(call, {+XSS +WEB})  ]]></Definition></CharacterizationRule

前面的污点特征化规则查找对类中定义的getParameter()方法的调用,其中一个超级类是javax.servlet.ServletRequest类,这里的f.enclosingClassses.supers contains[…]子句等效于将<DataflowSourceRule>中的<ApplyTo>元素属性设置为true,<Definition>元素指定规则表示读取操作中发生的污染源,下面描述了TaintSource特征化规则类型的参数:TaintSource(Expression,{TaintFlags})

  • Expression:指定要视为受污染的表达式和可选访问路径(例如:.foo.bar),如果表达式是函数调用则返回值被污染

  • TaintFlags:指定要与规则匹配的构造引入的污点关联的污点标志(可选),将污染标志指定为空格分隔的列表,每个污染标志必须包含一个加号(+)前缀以指示它已添加到污染路径

以下示例显示了附带的TaintWrite特征化规则,该规则相当于在上一个<DataflowSourceRule>的<OutArgument>中对其进行污染:

<CharacterizationRule formatVersion="22.1" language="java">  <RuleID>B27373A5-1403-4986-8221-112CE21D7A5F</RuleID>  <StructuralMatch><![CDATA[    FunctionCall call: call.function is      [Function f: f.name == "getParameter" and   f.enclosingClass.supers contains        [Class c: c.name == "javax.servlet.ServletRequest"]]      and call.instance is [Expression request: ]  ]]></StructuralMatch>  <Definition><![CDATA[    TaintWrite(request, {+XSS +WEB})   ]]></Definition></CharacterizationRule>

前面的污点特征化规则查找对类中定义的getParameter()方法的调用,其中一个超级类是javax.servlet.ServletRequest类,<Definition>元素指定规则表示写入操作中发生的污染源,下表描述了TaintWrite特征化规则类型的参数:TaintWrite(Expression,{aintFlags})

  • Expression:指定被视为受污染的表达式和可选访问路径(例如:.foo.bar)

  • TaintFlags:指定要与规则匹配的构造引入的污点关联的污点标志(可选)

Sink Rules

使用数据流分析器接收器规则来识别程序中受污染数据不能到达的点,以下示例显示了一个数据流接收器规则,该规则指示taint不能到达Statement.executeQuery()方法:

<DataflowSinkRule formatVersion="22.1" language="java">  <RuleID>CCC3523A-3E34-4890-8F7D-23F16CB3C4339</RuleID>  <VulnCategory>SQL Injection</VulnCategory>  <DefaultSeverity>2.0</DefaultSeverity>  <Description/>  <Sink>    <InArguments>0</InArguments>  </Sink>  <FunctionIdentifier>    <NamespaceName>      <Value>java.sql</Value>    </NamespaceName>    <ClassName>      <Value>Statement</Value>    </ClassName>    <FunctionName>      <Value>executeQuery</Value>    </FunctionName>    <ApplyTo overrides="true" implements="true" extends="true"/>  </FunctionIdentifier></DataflowSinkRule>

InArguments:指定不能接收污染的方法的参数,如果污点达到这些参数中的任何一个,Fortify静态代码分析器会报告一个问题,将参数指定为以逗号分隔的关键字列表return、this或globals或目标参数的从零开始的索引

您还可以将之前的数据流接收规则作为污点特征化规则编写,以下示例显示了TaintLink特征化规则

<CharacterizationRule formatVersion="22.1" language="java">  <RuleID>0434D772-00B8-44AA-A23F-04C9BD7115D3</RuleID>  <VulnCategory>SQL Injection</VulnCategory>  <DefaultSeverity>2.0</DefaultSeverity>  <Description/>  <StructuralMatch><![CDATA[    FunctionCall call: call.function is     [Function f: f.name == "executeQuery" and f.enclosingClass.supers contains       [Class c: c.name == "java.sql.Statement"]]     and call.arguments[0] is [Expression inArgument: ]  ]]></StructuralMatch>  <Definition><![CDATA[    TaintSink(inArgument, [])  ]]></Definition></CharacterizationRule>

前面的污点特征化规则查找对类中定义的方法executeQuery()的调用,其中一个超级类是java.sql.Statement类,并将参数零指定为接收器,<Definition>元素指定规则表示污染接收器,下表描述了TaintLink特征化规则类型的参数:TaintLink(Sink,TaintFlags)

  • Sink:指定被认为是受污染数据的接收器的表达式,如果满足条件表达式的污点到达表达式则会产生问题

  • TaintFlags:指定条件污染flagClosed表达式,使用逻辑&&、||和!指定污染标志!运算符,例如:WEB||NETWORK)&&!文件,若要指定规则匹配而不管所涉及的污点,请使用空大括号({})

Passthrough Rules

使用数据流分析器传递规则描述函数和方法如何将污染从输入传播到输出,以下示例显示了一个数据流传递规则,该规则指示调用trim()方法字符串上的污点也会从该方法返回

<DataflowPassthroughRule formatVersion="22.1" language="java">  <RuleID>8A1E8BA1-6C03-4F77-B648-75C3CF3C28CB</RuleID>  <FunctionIdentifier>    <NamespaceName>      <Value>java.lang</Value>    </NamespaceName>    <ClassName>      <Value>String</Value>    </ClassName>    <FunctionName>      <Value>trim</Value>    </FunctionName>  </FunctionIdentifier>  <InArguments>this</InArguments>  <OutArguments>return</OutArguments><DataflowPassthroughRule>

上一个示例中的数据流传递规则结合了<InArguments>和<OutArguments>的概念,将进入一个参数的方法的污染映射到退出另一个参数方法的污染,如果传递规则包含污染标志(上一个示例中没有),则会从<OutArguments>元素指定的参数中添加这些污染标志(以加号+开头的标志)或删除(以减号-结尾的标志),您还可以将之前的数据流传递规则作为污点特征化规则编写,以下示例显示了TaintTransfer特征化规则:

<CharacterizationRule formatVersion="22.1" language="java">  <RuleID>C30E2CFB-5133-48FF-86A5-854E4D282631</RuleID>  <StructuralMatch><![CDATA[    FunctionCall call: call.function is      [Function f: f.name == "trim" and f.enclosingClass.supers contains        [Class c: c.name == "java.lang.String"]]      and call.instance is [Expression inArgument: ]   ]]></StructuralMatch>  <Definition><![CDATA[    TaintTransfer(inArgument, call, {})    ]]></Definition></CharacterizationRule>

前面的污点特征化规则查找对类中定义的方法trim()的调用,其中一个超级类是java.lang.String类,该规则还指定污点需要从调用方法的对象传播到返回值,<Definition>元素指定规则表示传递,下表描述了TaintTransfer特征化规则类型的参数:TaintTransfer(In,Out,{TaintFlags})

  • In:指定包含传入污染的表达式和可选访问路径(例如:inArgument.foo)

  • Out:指定接收传出污染的表达式和可选访问路径(例如:.foo.bar)

  • TaintFlags:指定要与规则匹配的构造引入的污点关联的污点标志,将污染标志指定为空格分隔的列表,每个标志必须包含一个加号(+)或减号(-)前缀,以指示是否将其添加到污染路径Closed或从污染路径Close中删除,如果您没有添加或删除污点标志,请包含空大括号({})或将其省略

Entrypoint Rules

使用数据流分析器入口点规则来描述将受污染数据引入程序的程序点,入口点规则通过描述程序可以调用的函数和方法(外部或通过内部框架或源代码未包含在分析中的其他机制)来实现这一点,以下示例显示了一个数据流入口点规则,该规则指示作为第一个参数传递给Java main()方法的字符串数组被污染:

<DataflowEntryPointRule formatVersion="22.1" language="java"><RuleID>64FDA988-4770-498E-9709-4497CCDA4E48</RuleID>  <TaintFlags>+ARGS</TaintFlags>  <FunctionIdentifier>    <NamespaceName>      <Pattern>.*</Pattern>    </NamespaceName>    <ClassName>      <Pattern>.*</Pattern>    </ClassName>    <FunctionName>      <Value>main</Value>    </FunctionName>    <Parameters>      <ParamType>java.lang.String[]</ParamType>    </Parameters>    <ApplyTo implements="true" overrides="true" extends="true"/>    <Modifiers>      <Modifier>static</Modifier>    </Modifiers>   </FunctionIdentifier>  <InArguments>0</InArguments></DataflowEntryPointRule>

前面的数据流入口点规则示例使用<InArguments>元素定义在分析指定方法的主体时要考虑的参数,您还可以将之前的数据流入口点规则作为污点特征化规则编写,以下示例显示了TaintEntrypoint特征化规则:

<CharacterizationRule formatVersion="22.1" language="java">   <RuleID>278379D6-7CA3-4195-8857-7E5435B13053</RuleID>  <StructuralMatch><![CDATA[    Function f: f.static and f.name == "main" and f.parameters.length == 1      and f.parameterTypes[0] == T"java.lang.String[]"      and f.parameters[0] is [Expression inArgument: ]  ]]></StructuralMatch>  <Definition><![CDATA[    TaintEntrypoint(inArgument, {+ARGS})  ]]></Definition></CharacterizationRule>

前面的污点特征化规则查找静态函数main()的声明,该函数将java.lang.String数组作为参数,<Definition>元素指定规则表示污染entrypointClosed,下表描述了TaintEntrypoint特征化规则类型的参数:TaintEntrypoint(In,{TaintFlags})

  • In:指定被视为受污染的表达式和可选访问路径(例如:inArgument.foo)

  • TaintFlags:指定要与规则匹配的构造引入的污点关联的污点标志,将污染标志指定为空格分隔的列表,每个标志必须包含一个加号(+)前缀以指示它已添加到污染路径

Cleanse Rules

使用数据流分析器清理规则来描述验证逻辑和其他操作,这些操作可以部分或完全清理受污染的数据,您可以在清理规则中添加或删除指定的污点,以下示例显示了一个数据流清理规则,该规则演示了Map.clear()方法如何清理映射:

<DataflowCleanseRule formatVersion="22.1" language="java">  <RuleID>878BFCE2-6333-4AA2-8E3F-211B477FF409</RuleID>  <FunctionIdentifier>    <NamespaceName>      <Value>java.util</Value>    </NamespaceName>    <ClassName>      <Value>Map</Value>    </ClassName>    <FunctionName>      <Value>clear</Value>    </FunctionName>    <ApplyTo implements="true" overrides="true" extends="true"/>  </FunctionIdentifier>  <OutArguments>this</OutArguments></DataflowCleanseRule>

上一个示例中的数据流清理规则使用<OutArguments>元素指定在调用指定方法后应考虑清理参数,如果清理规则包含污染标志,而上一个示例没有,则指定的污染标志将从<OutArguments>元素指定的参数中添加(以加号+开头的标志)或删除(以减号-开头的标志),您还可以将之前的数据流清理规则作为污点特征化规则编写,以下示例显示了TaintCleanse特征化规则:

<CharacterizationRule formatVersion="22.1" language="java">  <RuleID>C56AE490-963B-45E8-86D1-FF1DEE474639</RuleID>  <StructuralMatch><![CDATA[    FunctionCall call: call.function is      [Function f: f.name == "clear" and f.enclosingClass.supers contains        [Class c: c.name == "java.util.Map"]]      and call.instance is [Expression outArgument: ]  ]]></StructuralMatch>  <Definition><![CDATA[    TaintCleanse(outArgument, {})  ]]></Definition></CharacterizationRule>

前面的污点特征化规则查找对类中定义的方法clear()的调用,其中一个超级类是java.util.Map类并指定从调用该方法的映射中完全删除污点,<Definition>元素指定规则表示一个清理,下表描述了TaintCleanse特征化规则类型的参数:TaintClease(Expr,{TaintFlags})

  • Expr:指定一个表达式和可选的访问路径(例如:outArgument.foo),该路径在删除污染标志时清除所有污染或一组污染,或在添加污染标志时接收污染

  • TaintFlags:指定要与规则匹配的构造引入的污点关联的污点标志,将污染标志指定为空格分隔的列表,每个标志必须包含一个加号(+)或减号(-)前缀以指示是否将其添加到污染路径Closed或从污染路径Close中删除,若要删除所有污点,请省略污点标志列表(指定空大括号{})

规则方案

SQL Injection

此场景强调了数据流分析器检测应用程序中的访问控制漏洞所必需的规则,因为分析器使用类似的规则检测SQL注入漏洞,所以该场景还包括SQL注入漏洞和相应的检测规则,该场景描述了包含SQL注入漏洞示例的源代码,然后演示了数据流分析器如何使用source、sink和passthrough规则来识别这种类型的漏洞,此场景突出显示了以下漏洞:

  • 访问控制:如果没有适当的访问控制,执行包含用户控制的主键的SQL语句可能会使攻击者查看未经授权的记录

  • SQL注入:使用用户输入构建动态SQL语句可以使攻击者修改语句意图或执行任意SQL命令

该场景强调了以下分析和规则概念:

  • Conditionals 

  • Full cleanse function 

  • Neutral taint 

  • Paired sinks 

  • Partial cleanse functions 

  • Passthrough

以下应用程序示例包括显示事务详细信息并具有访问控制漏洞的JSP页面:

<% String accountNumber = request.getParameter("acctno");%>...<%if ((accountNumber != null) && (accountNumber.length() > 0)) {  Long account = Long.valueOf(accountNumber);  List transactions = TransactionService.getTransactions(account);  PrintWriter outputWriter = response.getWriter();  outputWriter.println("<h1>Transactions reported from database     for account <i>"+accountNumber+"</i></h1>");  try {    ...  }%>

JSP使用帐号作为参数调用TransactionService.getTransactions()以检索帐户详细信息,事务服务在数据库中查询相关事务,以下示例显示了此方法如何检索帐户

public static List getTransactions(Long acctno) throws Exception {  Session session = ConnectionFactory.getInstance().getSession();  String queryStr = "from Transaction transaction where     transaction.acctno ='" + acctno + "'ORDER BY date DESC";  if (ServletActionContext.getServletContext() != null) {    ServletActionContext.getServletContext().log(queryStr);  }  Query query = session.createQuery(queryStr);  List transactions = query.list();  session.close();
return transactions;}

该方法使用从请求参数读取的帐号生成动态SQL语句,代码假定帐号只属于当前用户,该代码不会验证用户是否有权查看返回的数据,此漏洞类型与SQL注入漏洞类型密切相关,当代码附加不受信任的字符串时,存在SQL注入漏洞,该字符串可能包含任意字符,攻击者可以输入其他SQL代码并更改查询的全部含义,以上示例其实不包含SQL注入漏洞,因为攻击向量的类型为Long并且只能包含数字,以下示例显示了一个等效的SQL注入漏洞

public static List getTransactions(String acctno) throws Exception {  Session session = ConnectionFactory.getInstance().getSession();  String queryStr = "from Transaction transaction where     transaction.acctno ='" + acctno + "' ORDER BY date DESC";  if (ServletActionContext.getServletContext() != null)    ServletActionContext.getServletContext().log(queryStr);  Query query = session.createQuery(queryStr);  List transactions = query.list();  session.close();  return transactions;}

在第一个JSP页面示例中不受信任的数据通过对getParameter()的方法进入应用程序,下面的示例显示了一个数据流源规则,该规则对作为污染数据源调用的数据流进行建模

<DataflowSourceRule formatVersion="22.1" language="java">  <RuleID>120E80B3-7EA2-4A18-82F2-0F7E53E97480</RuleID>  <FunctionIdentifier>    <NamespaceName>      <Pattern>javax.servlet</Pattern>    </NamespaceName>    <ClassName>      <Value>ServletRequest</Value>    </ClassName>    <FunctionName>      <Value>getParameter</Value>    </FunctionName>    <ApplyTo overrides="true" implements="true" extends="true"/>  </FunctionIdentifier>  <OutArguments>return</OutArguments></DataflowSourceRule>

上一个示例中的数据流源规则与ServletRequest.getParameter()方法匹配,<OutArguments>元素表示该方法的返回值被污染,缺少<TaintFlags>元素表示这是一个不指定任何污染标志的一般污染源,第一个JSP页面示例通过将传入的帐号从字符串类型转换为数字类型来处理该帐号。以下示例显示了数据流传递规则,该规则使数据流分析器能够跟踪从accountNumber变量到account变量的污染:

<DataflowPassthroughRule formatVersion="22.1" language="java">  <RuleID>73371DA9-10AD-4D13-823D-4BD0C9F2104F</RuleID>  <TaintFlags>-XSS,+NUMBER</TaintFlags>  <FunctionIdentifier>    <NamespaceName>      <Pattern>java.lang</Pattern>    </NamespaceName>    <ClassName>      <Value>Long</Value>    </ClassName>    <FunctionName>      <Value>valueOf</Value>    </FunctionName>  </FunctionIdentifier>  <InArguments>0</InArguments>  <OutArguments>return</OutArguments></DataflowPassthroughRule>

传递规则以Long.valueOf()方法为目标,<InArguments>和<OutArguments>元素指定受污染的数据如何流经该方法,当代码使用受污染的参数调用方法时,Fortify静态代码分析器认为调用的返回值是受污染的,该规则在返回值中添加一个特定的污染标志以指示对象本质上是严格的数字,该规则从返回值中删除任何XSS污染标志,因为它不能再用于进行XSS攻击,最后JSP页面示例执行TransactionService.getTransactions()方法,然后执行Session.createQuery()方法,以下示例显示了检测访问控制漏洞的接收器规则,它检查VALIDATED_ACCESS_CONTROL_DATABASE污损标志是否不存在,如果验证函数后来被引入到源代码中的数据流中则可以为验证函数编写一个规则,添加VALIDATED_ACCESS_CONTROL_DATABASE污损标志,这确保Fortify静态代码分析器不会报告通过该函数的路径的漏洞

<DataflowSinkRule formatVersion="22.1" language="java">  <RuleID>2B8502DE-E54E-4C59-AFC6-B6E3BCA67B3B</RuleID>  <VulnCategory>Access Control</VulnCategory>  <VulnSubcategory>Database</VulnSubcategory>  <DefaultSeverity>2.0</DefaultSeverity>  <Description/>  <Sink>    <InArguments>0</InArguments>    <Conditional>      <And>        <TaintFlagSet taintFlag="NUMBER"/>        <Not>          <TaintFlagSet taintFlag="VALIDATED_ACCESS_CONTROL_DATABASE"/>        </Not>      </And>    </Conditional>  </Sink>  <FunctionIdentifier>    <NamespaceName>      <Pattern>net.sf.hibernate</Pattern>    </NamespaceName>    <ClassName>      <Value>Session</Value>    </ClassName>    <FunctionName>      <Value>createQuery</Value>    </FunctionName>    <ApplyTo overrides="true" implements="true" extends="true"/> </FunctionIdentifier></DataflowSinkRule>

通常访问控制接收器规则与SQL注入规则配对,方法Session.createQuery()包含访问控制漏洞,您可以将访问控制接收器规则转换为SQL注入接收器规则,以下示例显示了与以前的访问控制接收器规则等效的SQL注入接收器规则:

<DataflowSinkRule formatVersion="22.1" language="java">  <RuleID>AE637178-A9D2-4BE6-A7B2-EEEA293B506F</RuleID>  <VulnCategory>SQL Injection</VulnCategory>  <DefaultSeverity>2.0</DefaultSeverity>  <Description/>  <Sink>    <InArguments>0</InArguments>    <Conditional>      <And>        <Not>          <TaintFlagSet taintFlag="NUMBER"/>        </Not>        <Not>          <TaintFlagSet taintFlag="VALIDATED_SQL_INJECTION"/>        </Not>      </And>    </Conditional>  </Sink>  <FunctionIdentifier>    <NamespaceName>      <Value>net.sf.hibernate</Value>    </NamespaceName>    <ClassName>      <Value>Session</Value>    </ClassName>    <FunctionName>      <Value>createQuery</Value>    </FunctionName>    <ApplyTo overrides="true" implements="true" extends="true"/>  </FunctionIdentifier></DataflowSinkRule>

这两个规则都以同一方法的第一个参数为目标,与访问控制接收器规则不同,SQL注入接收器规则必须具有非数字的传入参数,数据流分析器检查是否存在中性污染标志VALIDATED_SQL_INJECTION,如果存在该污点则不会发生漏洞并且Fortify静态代码分析器不会报告漏洞

Cross-Site Scripting

此场景强调了Fortify检测应用程序中跨站点脚本(XSS)漏洞所需的规则,数据流分析器使用source、sink和passthrough规则来识别此类漏洞,该场景演示了攻击者如何利用跨站点脚本漏洞,然后显示了DataflowAnalyzer如何使用source、sink和passthrough规则来识别此类漏洞,该场景强调了以下分析和规则概念:

  • General taintClosed

  • Neutral taint

  • Passthrough

  • Sink

  • Source

  • Specific taint

该应用程序在事务页面中包含跨站点脚本漏洞,攻击者可以在事务描述中键入恶意内容,当受害者查看交易详细信息时应用程序会向浏览器发送恶意内容,攻击者可以使用此向量在受害者浏览器中执行JavaScript或其他恶意内容,任何呈现事务细节的代码都可能容易受到此攻击,以下示例显示了呈现给定帐号的这些详细信息的JSP页面:

<%  String accountNumber = request.getParameter("acctno");  if ((accountNumber != null) && (accountNumber.length() > 0)) {    Long account = Long.valueOf(accountNumber);    List transactions = TransactionService.getTransactions(account);    pageContext.getOut().println(        "<h1>Transactions reported from database for account <i>"        + accountNumber + "</i></h1>");
try { for (Iterator it = transactions.iterator(); it.hasNext();) { Transaction transaction = (Transaction)it.next(); String transactionDescription = "Transaction reported["+transaction.getId()+"]: " + "Account "+ transaction.getAcctno() + "; " + "Amount " + transaction.getAmount() + "; " + "Date " + transaction.getDate() + "; " + "Description " + transaction.getDescription(); pageContext.getOut().flush(); pageContext.getOut().println("<pre>"+transactionDescription+"</pre>"); } ...

 该代码枚举帐户的事务并将每个事务的详细信息打印到响应流中,为此JSP页面调用TransactionService.getTransactions()以检索与acctno指定的帐户关联的事务,以下示例显示了从数据库中检索数据的源代码

public static List getTransactions(Long acctno) throws Exception {  Session session = ConnectionFactory.getInstance().getSession();  String queryStr = "from Transaction transaction where transaction.acctno ='"                    + acctno                    + "' ORDER BY date DESC";  if (ServletActionContext.getServletContext() != null)    ServletActionContext.getServletContext().log(queryStr);  Query query = session.createQuery(queryStr);  List transactions = query.list();  session.close();
return transactions;}

首先JSP代码调用一个方法从数据库中检索数据,数据流源规则将此方法建模为Fortify静态代码分析器的污染源,然后JSP代码调用方法来遍历数据,Fortify静态代码分析器使用数据流传递规则来跟踪通过这些方法关闭的受污染数据,最后JSP代码将数据写入响应流,Fortify静态代码分析器使用数据流接收器规则来检测最终输出,以下示例数据流源规则将对Query.list()的调用建模为污染数据源:

<DataflowSourceRule formatVersion="22.1" language="java">  <RuleID>9ECA2C61-7625-41DB-967B-92768358C811</RuleID>  <TaintFlags>+XSS,+DATABASE</TaintFlags>  <FunctionIdentifier>    <NamespaceName>      <Value>net.sf.hibernate</Value>    </NamespaceName>    <ClassName>      <Value>Query</Value>    </ClassName>    <FunctionName>      <Value>list</Value>    </FunctionName>    <ApplyTo overrides="true" implements="true" extends="true"/>  </FunctionIdentifier>  <OutArguments>return</OutArguments></DataflowSourceRule>

前一条规则中的<OutArguments>元素表示该方法的返回值应该被认为是受污染的,该规则还添加了污点标记XSS,这是一个通用污染标志,使数据流分析器能够将可能用于跨站点脚本攻击的数据源与可能易受跨站点脚本影响的接收器相关联,源代码中的代码遍历从调用TransactionService.getTransactions()返回的事务列表对象,数据流分析器应用先前的源规则,结果是列表对象被认为是受污染的,以下示例显示了一个passthrough规则,它使数据流分析器能够将污染从源代码中的事务列表传播并跟踪到it迭代器变量:

<DataflowPassthroughRule formatVersion="22.1" language="java">  <RuleID>217417FB-7E50-41BA-ACB7-8159BD5211AC</RuleID>  <FunctionIdentifier>    <NamespaceName>      <Value>java.util</Value>    </NamespaceName>    <ClassName>      <Value>Collection</Value>    </ClassName>    <FunctionName>      <Value>iterator</Value>    </FunctionName>    <ApplyTo overrides="true" implements="true" extends="true"/>  </FunctionIdentifier>  <InArguments>this</InArguments>  <OutArguments>return</OutArguments></DataflowPassthroughRule>

in和out参数指定受污染的数据如何流经该方法,当应用程序代码在受污染的目标对象(this)上调用方法时,数据流分析器将污染传播到返回值,以下示例显示了传递规则,该规则使分析器能够了解如何在调用iterator.next()时从迭代器对象返回污点:

<DataflowPassthroughRule formatVersion="22.1" language="java">  <RuleID>D56C1363-C303-4AAB-99A9-98075D0FEB80</RuleID>  <FunctionIdentifier>    <NamespaceName>      <Pattern>java.util</Pattern>    </NamespaceName>    <ClassName>      <Value>Iterator</Value>    </ClassName>    <FunctionName>      <Value>next</Value>    </FunctionName>    <ApplyTo overrides="true" implements="true" extends="true"/>  </FunctionIdentifier>  <InArguments>this</InArguments>  <OutArguments>return</OutArguments></DataflowPassthroughRule>

最后以下示例中的JSP代码构造了一个事务描述并使用以下代码将其显示给用户

...  String transactionDescription = "Transaction reported["+transaction.getId()+"]: "                                  + "Account "+ transaction.getAcctno() + "; "                                  + "Amount " + transaction.getAmount() + "; "                                  + "Date " + transaction.getDate() + "; "                                  + "Description " + transaction.getDescription();      outputWriter.flush();      outputWriter.println("<pre>"+transactionDescription+"</pre>");  ...

Fortify静态代码分析器可以访问事务对象的所有源代码,这意味着数据流分析器可以通过对象的getter方法自动跟踪污点,这意味着数据流分析器可以成功地从事务对象跟踪污染到transactionDescription字符串而不需要额外的规则,以下示例显示了数据流分析器用于识别XSS漏洞的数据流接收器规则,此规则将JspWriter.println()函数标记为接收器,该规则检查XSS标志是否存在,VALIDATED_CROSS_SITE_SCRIPTING标志是否不存在,开发人员稍后可能会引入验证数据内容的验证函数,Fortify静态代码分析器需要为验证函数添加一个新的清除规则,该规则将VALIDATED_CROSS_SITE_SCRIPTING污损标志添加到数据中,这确保Fortify静态代码分析器不会报告通过该函数的路径的漏洞

<DataflowSinkRule formatVersion="22.1" language="java">  <RuleID>5F0C1BA2-3F30-483F-9232-9DB09442801E</RuleID>  <VulnCategory>Cross-Site Scripting</VulnCategory>  <VulnSubcategory>Persistent</VulnSubcategory>  <DefaultSeverity>2.0</DefaultSeverity>  <Description/>  <Sink>    <InArguments>0</InArguments>    <Conditional>      <And>        <TaintFlagSet taintFlag="XSS"/>        <Not>          <TaintFlagSet        taintFlag="VALIDATED_CROSS_SITE_SCRIPTING_PERSISTENT"/>        </Not>      </And>    </Conditional>  </Sink>  <FunctionIdentifier>    <NamespaceName>      <Value>javax.servlet.jsp</Value>    </NamespaceName>    <ClassName>      <Value>JspWriter</Value>    </ClassName>    <FunctionName>      <Value>println</Value>    </FunctionName>    <Parameters>      <ParamType>java.lang.String</ParamType>      <WildCard min="0" max="2"/>     </Parameters>    <ApplyTo implements="true" overrides="true" extends="true"/>  </FunctionIdentifier></DataflowSinkRule>

函数标识符中的<Parameters>元素确保此规则仅与JspWriter.println()函数的版本匹配,该函数将字符串作为第一个参数,<Sink>元素指定第一个参数是对污染敏感的参数并在<Conditional>元素中指定一组污染标志约束

Path Manipulation

此场景强调了Fortify静态代码分析器数据流分析器检测路径操纵漏洞所需的规则,该场景演示了攻击者如何利用路径操纵漏洞,它展示了数据流分析器如何使用TaintEntrypoint和sink规则来识别路径操纵漏洞,该场景强调了以下分析和规则概念:

  • Conditional

  • Constructor token

  • TaintEntrypoint

  • General taintClosed

  • Input argument

  • Annotation

  • Neutral taint

  • Parameter signature

  • Sink

本场景中的应用程序使用Spring MVC框架编写,并在其横幅广告web服务中包含路径操纵漏洞,网络服务使附属公司能够提供标识符并检索包含广告的JPEG图像,攻击者可以在Web请求中输入恶意标识符,从而导致服务器使用敏感文件的内容响应请求,以下代码检索附属公司的横幅广告

@Controller@RequestMapping("/ad")public class BannerAdController {  static private String baseDirectory = "/images/bannerAds";
@RequestMapping("/retrieveBannerAd") public @ResponseBody File retrieveBannerAd(@RequestParam("clientAd") String clientAd) { // Retrieve banner with given guid File targetFile = new File(baseDirectory + clientAd); return targetFile; }...}

当分支机构对BannerAdController.reiveBannerAd()方法执行web服务调用时,应用程序将返回与分支机构标识符clientAd关联的图像文件,该代码假定传入的分支机构标识符仅指定了一个文件名,但如果攻击者提供了标识符"../../../..",服务器检索文件/images/bannerAds/../../../..//windows/system.ini,在大多数系统上这相当于/windows/system.ini

在本例中不受信任的数据通过web服务入口点进入并传递给文件构造函数,分析器使用TaintEntrypoint特征化规则将该入口点建模为污染源,以下示例显示了将此方法建模为污染源的规则

<CharacterizationRule formatVersion="22.1" language="java">  <RuleID>AE31740B-140B-4338-BE4F-33D7F05CC840</RuleID>  <StructuralMatch><![CDATA[    Variable p: p.enclosingFunction is       [Function f: f.parameters contains p]      and p.annotations contains      [Annotation: type.name ==      "org.springframework.web.bind.annotation.RequestParam"]  ]]></StructuralMatch>  <Definition><![CDATA[    foreach p {TaintEntrypoint(p, {+WEB +XSS}) }  ]]></Definition></CharacterizationRule>

上一个示例中的入口点规则与BannerAdController.reveiveBannerAD()方法匹配,该方法的参数用org.springframework.web.bind.annotation.RequestParam注释进行了注释,foreach块表示对满足谓词而不是任意谓词的所有赋值感兴趣,在该规则中污点标志被添加到满足谓词的所有变量,而不是来自满足谓词的集合的单个变量,以下示例描述了与相应构造函数匹配的数据流接收器规则:

<DataflowSinkRule formatVersion="22.1" language="java">  <RuleID>98558CD1-708D-48E8-8C68-F93481CB15A9</RuleID>  <VulnCategory>Path Manipulation</VulnCategory>  <DefaultSeverity>2.0</DefaultSeverity>  <Description ref="desc.dataflow.java.path_manipulation"/>  <Sink>    <InArguments>0</InArguments>    <Conditional>      <Not>        <TaintFlagSet taintFlag="VALIDATED_PATH_MANIPULATION"/>      </Not>    </Conditional>  </Sink>  <FunctionIdentifier>    <NamespaceName>      <Value>java.io</Value>    </NamespaceName>    <ClassName>      <Value>File</Value>    </ClassName>    <FunctionName>      <Pattern>init^</Pattern>    </FunctionName>    <Parameters>      <ParamType>java.lang.String</ParamType>    </Parameters>    <ApplyTo overrides="true" implements="true" extends="true"/>  </FunctionIdentifier></DataflowSinkRule>

数据流接收器规则使用特殊关键字init来匹配File.File()构造函数。此关键字为类构造函数保留,并使规则能够在继承关系之间匹配,当污点到达接收器时,<Conditional>元素确保如果还存在中性污点标志VALIDATED_PATH_MANIPULATION,则不会报告任何漏洞,此污损标志表示数据已事先正确验证,您可以编写一个单独的清除或传递规则将中性污染标志VALIDATED_PATH_MANIPULATION添加到通过适当验证方法的数据中

Command Injection

此场景强调了数据流分析器检测命令注入漏洞所需的规则,该场景演示了攻击者如何利用命令注入漏洞,然后说明了Dataflow Analyzer如何使用特征化TaintSource、sink和passthrough规则来识别这种类型的漏洞,该场景强调了以下分析和规则概念:

  • Input arguments

  • Output arguments

  • Passthrough

  • Sink

  • TaintSource

下面的应用程序的消息服务中包含命令注入漏洞,攻击者可以使用消息服务生成电子邮件,攻击者向目标地址输入恶意命令,然后攻击者将消息提交给服务器进行处理,当受害者收到消息时,服务器执行嵌入的命令,使用内部消息传递类生成电子邮件的代码易受此攻击,以下示例显示了一个JSP页面,该页面使用该类广播警报消息:

<% GlobalURLObject globalURLObject = applicationContext.getGlobalURLObject();  String alertMessage = globalURLObject.message;   int messageCount = 0;
if ((alertMessage != null) && (alertMessage.length() > 0)) { SendMessage msgClass = new SendMessage(); String specifiedUsers = globalURLObject.users; if ((specifiedUsers != null) && (specifiedUsers.length() > 0)) { String[] users = specifiedUsers.split(";"); for (int index=0; index < users.length; index++) { String emailAddress = users[index]; msgClass.setTo(emailAddress); msgClass.setSubject("Technical Difficulties");
String processedMessage = alertMessage.replaceAll("<code1>" "The system is currently experiencing technical difficulties.");
msgClass.setBody(processedMessage); msgClass.setSeverity("Highest"); msgClass.execute(); messageCount++; } ...

JSP对消息进行一些表面处理然后调用SendMessage.execute(),以下示例显示了此方法如何处理已处理的消息

public void execute() {  if (isInvalidEmail(this.to)) return INPUT;
String[] cmd = getMailCommand(); String message = sendMail(cmd);
addActionMessage(message);}

SendMessage.execute()方法调用SendMessage.getMailCommand()生成一个命令字符串,该字符串用于发送电子邮件,以下示例显示了如何生成命令字符串:

public String[] getMailCommand() {  ...  cmd[2] = java + " -cp "+ cp +    " com.fortify.samples.riches.legacy.mail.SendMail "    " + subject + "" "" + severity + "" "" + body + ""    " + to;
return cmd;}

此代码假定电子邮件字段不包含|、;、;,或&符号,这些符号表示不同平台上的命令字符串分隔符,可以在命令字符串中包含这些分隔符以在同一字符串中执行多个命令,例如攻击者可以提供消息体"&dir C:>C:files.txt&",JSP代码最终调用SendMessage.execute()方法,根据mail命令生成并执行shell命令字符串,该方法调用SendMessage.sendMail()方法来执行命令字符串:

public String sendMail(String[] cmd) {  Runtime rt = Runtime.getRuntime();  //call "legacy" mail program  Process proc = null;  StringBuilder message = new StringBuilder();  try {    proc = rt.exec(cmd);    ...

污染数据通过访问GlobalURLObject对象的字段进入JSP代码,源代码在第2行和第7行说明了这种访问,以下污染特征化规则示例使Fortify静态代码分析器将该字段访问建模为污染数据源

<CharacterizationRule formatVersion="22.1" language="java">  <RuleID>471ABD87-96E0-4327-ACBB-D74C9B767155</RuleID>  <StructuralMatch><![CDATA[    FieldAccess fa0: fa0.instance is    [FieldAccess fa: fa.field.enclosingClass.supers contains    [Class c: c.name == "com.mypackage.GlobalURLObject"]    and not fa in [AssignmentStatement: lhs.location is    [Location l: l.transitiveBase === fa.transitiveBase]]]  ]]></StructuralMatch>  <Definition><![CDATA[    TaintSource(fa0, {+XSS +WEB})  ]]></Definition></CharacterizationRule>

该规则将从类型为GlobalURLObject的对象访问的任何字段,如果该对象不在赋值语句的左侧,则该字段带有WEB污点以指示该对象包含源自WEB的数据,Fortify将WEB污点与XSS污点相关联,因为来自WEB源的对象也可能包含JavaScript,其他规则使用此额外污点来识别跨站点脚本漏洞,不直接适用于命令注入漏洞检测,注意在这个示例特征化规则中<Definition>元素中不需要foreach块,因为TaintSource是关于与主谓词相关联的fa0编写的,它指示规则只匹配一个代码结构,JSP代码通过调用String.replaceAll()方法将标识符键替换为消息文本来处理传入的电子邮件消息,以下示例显示了一个数据流传递规则,该规则使Fortify静态代码分析器能够跟踪从alertMessage变量到processedMessage变量的污染:

<DataflowPassthroughRule formatVersion="22.1" language="java">  <RuleID>B1D159AE-EE88-4760-A112-8BFC5F774DE3</RuleID>  <FunctionIdentifier>    <NamespaceName>      <Value>java.lang</Value>    </NamespaceName>    <ClassName>      <Value>String</Value>    </ClassName>    <FunctionName>      <Value>replaceAll</Value>    </FunctionName>    <ApplyTo implements=true"overrides="true"extends="true"/>  </FunctionIdentifier>  <InArguments>this</InArguments>  <OutArguments>return</OutArguments></DataflowPassthroughRule>

以下示例数据流接收器规则检测命令注入漏洞,此规则将JavaRuntime.exec()方法标记为接收器,它验证VALIDATED_COMMAND_INJECTION污损标志是否不存在,要添加验证函数来验证数据的内容,开发人员可以为验证函数编写一个规则,将VALIDATED_COMMAND_INJECTION污损标志添加到数据对象,这确保Fortify静态代码分析器不会报告通过该函数的路径的漏洞

<DataflowSinkRule formatVersion="22.1" language="java">  <RuleID>E6E0AC3D-1C7B-48B1-B80D-2AC4619B0D81</RuleID>  <VulnCategory>Command Injection</VulnCategory>  <DefaultSeverity>2.0</DefaultSeverity>  <Description/>  <Sink>    <InArguments>0...</InArguments>    <Conditional>      <Not>        <TaintFlagSet taintFlag="VALIDATED_COMMAND_INJECTION"/>      </Not>    </Conditional>  </Sink>  <FunctionIdentifier>    <NamespaceName>      <Value>java.lang</Value>    </NamespaceName>    <ClassName>      <Value>Runtime</Value>    </ClassName>    <FunctionName>      <Value>exec</Value>    </FunctionName>     <ApplyTo implements="true" overrides="true" extends="true"/>  </FunctionIdentifier></DataflowSinkRule>

构造实例

以下示例显示了针对Java中的SQL注入进行验证的源代码

package com.company.package;public final class MyValidationClass {  ...  public static String cleanseSQLString(String arg) {     return arg.replaceAll("[^a-zA-Z\s]", "");  }  ...}

如果该函数是外部库的一部分并且其源未包含在扫描中则需要编写带有适当污损标志修改的传递规则,以下示例传递规则向数据流分析器描述了受污染的数据确实流经函数,但验证是在过程中执行的

<DataflowPassthroughRule formatVersion="22.1" language="java">  <RuleID>98DE1262-6A55-4C74-8A24-497FD8198421</RuleID>  <TaintFlags>+VALIDATED_SQL_INJECTION</TaintFlags>  <FunctionIdentifier>    <NamespaceName>      <Value>com.company.package</Value>    </NamespaceName>    <ClassName>      <Value>MyValidationClass</Value>    </ClassName>    <FunctionName>      <Value>cleanseSQLString</Value>    </FunctionName>    <ApplyTo implements="true" overrides="true" extends="true"/>  </FunctionIdentifier>  <InArguments>0</InArguments>  <OutArguments>return</OutArguments></DataflowPassthroughRule>

还需要以下示例接收器规则来检查此污染标志

<DataflowSinkRule formatVersion="22.1" language="java">  <RuleID>B5808D41-BA35-4D2F-89BF-4273BCA763E4</RuleID>   <VulnCategory>SQL Injection</VulnCategory>  <DefaultSeverity>2.0</DefaultSeverity>  <Description/>  <Sink>    <InArguments>0</InArguments>    <Conditional>      <And>        <Not>          <TaintFlagSet taintFlag="NUMBER"/>        </Not>        <Not>          <TaintFlagSet taintFlag="VALIDATED_SQL_INJECTION"/>        </Not>      </And>    </Conditional>  </Sink>  <FunctionIdentifier>    <NamespaceName>      <Value>com.company.package</Value>    </NamespaceName>    <ClassName>      <Value>Connection</Value>    </ClassName>    <FunctionName>      <Value>executeQuery</Value>    </FunctionName>    <ApplyTo implements="true" overrides="true" extends="true"/>  </FunctionIdentifier></DataflowSinkRule>

如果该函数是正在扫描的源代码的一部分,则清除规则更合适,由于数据流分析器已经通过查看其代码来派生函数的传递行为,因此只需描述分析器使用清理规则添加或删除的污染标志,如下例所示:

<DataflowCleanseRule formatVersion="22.1" language="java">  <RuleID>E01B88BE-F6B2-4EF9-BE43-035A008FE1C0</RuleID>  <TaintFlags>+VALIDATED_SQL_INJECTION</TaintFlags>  <FunctionIdentifier>    <NamespaceName>      <Value>com.company.package</Value>    </NamespaceName>    <ClassName>      <Value>MyValidationClass</Value>    </ClassName>    <FunctionName>      <Value>cleanseSQLString</Value>    </FunctionName>    <ApplyTo implements="true" overrides="true" extends="true"/>  </FunctionIdentifier>  <OutArguments>return</OutArguments></DataflowCleanseRule>

使用清理规则执行此操作,以便分析器在派生传递之后将清理规则应用于污点路径并行应用传递规则,创建单独的污染路径不会产生所需的效果,下图说明了这一概念:

package com.company.package;public class MyClass {  ...  public void myMethod(HttpRequest request, Connection connection) {    String query = request.getParameter("query");    connection.executeQuery(MyValidationClass.cleanseSQLString(query));  }  ...}

【SDL实践指南】Foritify数据流规则

前面的规则适用于验证函数的以下用法:

package com.company.package;public class MyClass {  ...  public void myMethod(HttpRequest request, Connection connection) {    String query = request.getParameter("query");    connection.executeQuery(MyValidationClass.cleanseSQLString(query));  }  ...}

许多开发人员根据输入的有效性定义验证函数返回true或false,这可能会给代码维护带来挑战,因为数据是否经过验证尚不清楚,这可能会导致意外引入漏洞,如果以这种方式定义验证函数则必须修改以前的用法和规则,以下示例显示了重新定义的验证函数

package com.company.package;...public final class MyValidationClass {  ...  public static boolean isBadQuery(String arg) {    return arg.matches("[^a-zA-Z\s]");  }    ...}

对于前一种情况,可以按以下方式使用验证函数:

package com.company.package;public class MyClass {  ...  public void myMethod(HttpRequest request, Connection connection)    throw BadInputException {    String query = request.getParameter("query");    if (!MyValidationClass.isBadQuery(query)) {      connection.executeQuery(query);    }    else {      throw BadInputException("Invalid query.");    }    }  ...}

由于性能影响,Fortify静态代码分析器不执行路径敏感的数据流分析,因此可能会产生误报,但是可以编写自定义TaintLink特性规则来处理这种类型的场景,尽管您可以用不同的方式编写if语句但以下污点特征化规则仅对上一个示例有效

<CharacterizationRule formatVersion="16.20" language="java">  <RuleID>D06F30A5-DB9C-46A2-965C-A74FBC23501C</RuleID>  <VulnCategory>SQL Injection</VulnCategory>  <DefaultSeverity>2.0</DefaultSeverity>  <Description/>  <StructuralMatch><![CDATA[    FunctionCall call: call.function is    [Function f: f.name == "executeQuery" and f.enclosingClass.supers     contains [Class c: c.name == "com.company.package.Connection"]]    and call.arguments[0] is [Expression inArgument: ]    and not call.enclosingFunction contains     [IfStatement ifStmt: ifStmt.ifBlock contains     [FunctionCall fc2: fc2 == call] and ifStmt.expression is     [Operation onot: onot.unary and onot.lhs is     [FunctionCall fc: fc.function is [Function valf: valf.name == "isBad"     and valf.enclosingClass.supers contains     [Class valc: valc.name == "com.company.package.MyValidationClass"]]]]]   ]]></StructuralMatch>  <Definition><![CDATA[    TaintSink(inArgument, [!NUMBER && !VALIDATED_SQL_INJECTION])  ]]></Definition></CharacterizationRule>

前面的污点特征化规则匹配对com.company.package.Connection.executeQuery()的调用,其中非数字且未验证的污点到达其第一个参数,如果调用发生在if语句的if块内Fortify静态代码分析器不会报告该漏洞,该if块检查对com.company.package.MyValidationClass.isBad()函数的调用是否返回false

文末小结

本篇文章对Foritify数据流规则进行了简单介绍,同时就具体的应用做了简易示例~

原文始发于微信公众号(七芒星实验室):【SDL实践指南】Foritify数据流规则

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2023年4月2日01:26:58
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   【SDL实践指南】Foritify数据流规则http://cn-sec.com/archives/1646513.html

发表评论

匿名网友 填写信息