如何在ColdFusion中使用验证尝试组实现OWASP ESAPI验证器?

时间:2013-06-25 18:28:09

标签: coldfusion coldfusion-9 cfml esapi

我一直在使用ColdFusion 9附带的OWASP ESAPI实用程序。ColdFusion's Builtin Enterprise Security APIencoder实用程序非常简单,我相信我让它们正常工作。我的问题在于validator实用程序。

我可以让他们单独工作 。也就是说,如果我用“无效”数据调用validator.getValidInput()方法,它将抛出一个我可以捕获的错误。但是,当我尝试在 batch 中调用validator方法时,我得到一个空指针异常。通过 batch 我的意思是尝试执行验证尝试组。这应该通过传递validator.getValidInput()方法ValidationErrorList方法来工作,该参数应该告诉它不要抛出错误,而只是将错误添加到错误列表中。我不能让它在这种模式下工作。我最好的尝试是给我一个空指针异常。

以下是具体错误:

java.lang.NullPointerException

使用此堆栈跟踪:

java.lang.NullPointerException at 
org.owasp.esapi.reference.DefaultValidator.getValidInput(DefaultValidator.java:238) at 
sun.reflect.GeneratedMethodAccessor377.invoke(Unknown Source) at 
sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source) at 
java.lang.reflect.Method.invoke(Unknown Source) at 
coldfusion.runtime.StructBean.invoke(StructBean.java:536) at 
coldfusion.runtime.CfJspPage._invoke(CfJspPage.java:2393) at 
cftest2ecfm989071068.runPage(D:\Web\internet\fboc\test.cfm:19) at 
coldfusion.runtime.CfJspPage.invoke(CfJspPage.java:231) at 
coldfusion.tagext.lang.IncludeTag.doStartTag(IncludeTag.java:416) at 
coldfusion.runtime.CfJspPage._emptyTcfTag(CfJspPage.java:2722) at 
cfApplication2ecfc1705903666$funcONREQUEST.runFunction(D:\Web\internet\fboc\Application.cfc:70) at 
coldfusion.runtime.UDFMethod.invoke(UDFMethod.java:472) at 
coldfusion.runtime.UDFMethod$ReturnTypeFilter.invoke(UDFMethod.java:405) at 
coldfusion.runtime.UDFMethod$ArgumentCollectionFilter.invoke(UDFMethod.java:368) at 
coldfusion.filter.FunctionAccessFilter.invoke(FunctionAccessFilter.java:55) at 
coldfusion.runtime.UDFMethod.runFilterChain(UDFMethod.java:321) at 
coldfusion.runtime.UDFMethod.invoke(UDFMethod.java:220) at 
coldfusion.runtime.TemplateProxy.invoke(TemplateProxy.java:491) at 
coldfusion.runtime.TemplateProxy.invoke(TemplateProxy.java:337) at 
coldfusion.runtime.AppEventInvoker.invoke(AppEventInvoker.java:88) at 
coldfusion.runtime.AppEventInvoker.onRequest(AppEventInvoker.java:280) at 
coldfusion.filter.ApplicationFilter.invoke(ApplicationFilter.java:356) at 
coldfusion.filter.RequestMonitorFilter.invoke(RequestMonitorFilter.java:48) at 
coldfusion.filter.MonitoringFilter.invoke(MonitoringFilter.java:40) at 
coldfusion.filter.PathFilter.invoke(PathFilter.java:94) at 
coldfusion.filter.ExceptionFilter.invoke(ExceptionFilter.java:70) at 
coldfusion.filter.BrowserDebugFilter.invoke(BrowserDebugFilter.java:79) at 
coldfusion.filter.ClientScopePersistenceFilter.invoke(ClientScopePersistenceFilter.java:28) at 
coldfusion.filter.BrowserFilter.invoke(BrowserFilter.java:38) at 
coldfusion.filter.NoCacheFilter.invoke(NoCacheFilter.java:46) at 
coldfusion.filter.GlobalsFilter.invoke(GlobalsFilter.java:38) at 
coldfusion.filter.DatasourceFilter.invoke(DatasourceFilter.java:22) at 
coldfusion.filter.CachingFilter.invoke(CachingFilter.java:62) at 
coldfusion.filter.RequestThrottleFilter.invoke(RequestThrottleFilter.java:126) at 
coldfusion.CfmServlet.service(CfmServlet.java:201) at 
coldfusion.bootstrap.BootstrapServlet.service(BootstrapServlet.java:89) at 
jrun.servlet.FilterChain.doFilter(FilterChain.java:86) at 
coldfusion.monitor.event.MonitoringServletFilter.doFilter(MonitoringServletFilter.java:42) at 
coldfusion.bootstrap.BootstrapFilter.doFilter(BootstrapFilter.java:46) at 
jrun.servlet.FilterChain.doFilter(FilterChain.java:94) at 
jrun.servlet.FilterChain.service(FilterChain.java:101) at 
jrun.servlet.ServletInvoker.invoke(ServletInvoker.java:106) at 
jrun.servlet.JRunInvokerChain.invokeNext(JRunInvokerChain.java:42) at 
jrun.servlet.JRunRequestDispatcher.invoke(JRunRequestDispatcher.java:286) at 
jrun.servlet.ServletEngineService.dispatch(ServletEngineService.java:543) at 
jrun.servlet.jrpp.JRunProxyService.invokeRunnable(JRunProxyService.java:203) at 
jrunx.scheduler.ThreadPool$ThreadThrottle.invokeRunnable(ThreadPool.java:428) at 
jrunx.scheduler.WorkerThread.run(WorkerThread.java:66)

这是一个简单的测试脚本。你会注意到我有一行注释掉了。该行在没有ErrorList的情况下工作,但会抛出错误(应该如此)。我试图让方法工作而不抛出错误:

<cftry>
<cfsilent>
<cfparam name="form.TestField" default="" type="string" />

<cfset Esapi = CreateObject("java", "org.owasp.esapi.ESAPI") />
<cfset EsapiEncoder = Esapi.encoder() />
<cfset EsapiValidator = Esapi.validator() />

<cfset Clean = StructNew() />
<cfset Clean.Css = EsapiEncoder.encodeForCss(form.TestField) />
<cfset Clean.Html = EsapiEncoder.encodeForHtml(form.TestField) />
<cfset Clean.HtmlAttribute = EsapiEncoder.encodeForHtmlAttribute(form.TestField) />
<cfset Clean.JavaScript = EsapiEncoder.encodeForJavaScript(form.TestField) />
<cfset Clean.Url = EsapiEncoder.encodeForUrl(form.TestField) />
<cfset Clean.Xml = EsapiEncoder.encodeForXml(form.TestField) />

<cfset ErrorList = CreateObject("java", "org.owasp.esapi.ValidationErrorList") />
<cfset Valid = StructNew() />
<cfset Valid.Input = EsapiValidator.getValidInput("Test Field", form.TestField, "SafeString", 128, false, true, ErrorList) />
<!---<cfset Valid.Input = EsapiValidator.getValidInput("Test Field", form.TestField, "SafeString", 128, false, true) />--->
</cfsilent>

<!DOCTYPE HTML>
<head>
    <meta charset='UTF-8' />
    <title>ESAPI Test</title>
</head>
<body>
    <div>
        <h3>ESAPI Test</h3>
        <cfoutput>
        <form name="frmtest" id="frmtest" action="#cgi.script_name#" method="post">
            <p>Enter text to test:</p>
            <p><input type="text" name="TestField" id="TestField" size="64" maxlength="128" value="#Clean.HtmlAttribute#" /></p>
            <p><input type="submit" name="submit" id="submit" value=" Submit " /></p>
        </form>
        </cfoutput>
        <hr />
        <cfdump var="#Clean#" label="Clean Structure" />
        <hr />
        <cfdump var="#Valid#" label="Valid Structure" />
    </div>
</body>
</html>
<cfcatch type="any">
    <hr />
    <div>
        <h3>ERROR</h3>
        <cfdump var="#cfcatch#" label="Error" />
    </div>
</cfcatch>
</cftry>

当我使用“有效”数据运行此脚本时,它可以正常工作(不会抛出任何错误)。如果我输入“无效”字符,那么我会得到空指针异常。

“有效”数据示例:this is a safe string 0123456789
“无效”数据的示例:this is a safe string 0123456789-(注意结尾处的连字符)

Here is a link to the documentation for the validator.getValidInput method that I am trying to implement

Here is a link to the documentation that shows what I am trying to implement

对于它的价值,验证“规则”在ColdFusion附带的validation.properties文件中定义。该文件位于{cfusion lib}目录中。以下是我服务器中该文件的内容:

# The ESAPI validator does many security checks on input, such as canonicalization
# and whitelist validation. Note that all of these validation rules are applied *after*
# canonicalization. Double-encoded characters (even with different encodings involved,
# are never allowed.
#
# To use:
#
# First set up a pattern below. You can choose any name you want, prefixed by the word
# "Validation." For example:
#   Validation.Email=^[A-Za-z0-9._%-]+@[A-Za-z0-9.-]+\\.[a-zA-Z]{2,4}$
# 
# Then you can validate in your code against the pattern like this:
#     ESAPI.validator().isValidInput("User Email", input, "Email", maxLength, allowNull);
# Where maxLength and allowNull are set for you needs, respectively.
#
# But note, when you use boolean variants of validation functions, you lose critical 
# canonicalization. It is preferable to use the "get" methods (which throw exceptions) and 
# and use the returned user input which is in canonical form. Consider the following:
#  
# try {
#    someObject.setEmail(ESAPI.validator().getValidInput("User Email", input, "Email", maxLength, allowNull));
#
Validator.SafeString=^[.\\p{Alnum}\\p{Space}]{0,1024}$
Validator.Email=^[A-Za-z0-9._%-]+@[A-Za-z0-9.-]+\\.[a-zA-Z]{2,4}$
Validator.IPAddress=^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$
Validator.URL=^(ht|f)tp(s?)\\:\\/\\/[0-9a-zA-Z]([-.\\w]*[0-9a-zA-Z])*(:(0-9)*)*(\\/?)([a-zA-Z0-9\\-\\.\\?\\,\\:\\'\\/\\\\\\+=&amp;%\\$#_]*)?$
Validator.CreditCard=^(\\d{4}[- ]?){3}\\d{4}$
Validator.SSN=^(?!000)([0-6]\\d{2}|7([0-6]\\d|7[012]))([ -]?)(?!00)\\d\\d\\3(?!0000)\\d{4}$
Validator.CFContainerID=^[\\p{Alnum}_\\-\\.:]+$
Validator.GOOGLEMAPAPI=^[\\p{Alnum}_\\+=\\/\\-]+$
Validator.CFFORMSCRIPTSRC=^[^\\*\\?\"'<>|%]*$

我认为我的想法是为您自己的应用程序添加此文件的规则。

是否有人使用validator.getValidInput()方法在批处理(验证尝试组)中工作?


更新1

我注意到每次得到空指针异常时,都会在服务器上写入cfusion-out.log。它让我相信它正在起作用,但在尝试分配验证异常时获得空指针:

06/25 16:08:14 [jrpp-3225] WARN  [SECURITY FAILURE Anonymous:null@unknown -> /IntrusionDetector] Invalid input: context=Test Field, type(SafeString)=^[.\p{Alnum}\p{Space}]{0,1024}$, input=this is a safe string 0123456789-
org.owasp.esapi.errors.ValidationException: Test Field: Invalid input. Please conform to regex ^[.\p{Alnum}\p{Space}]{0,1024}$ with a maximum length of 128
at org.owasp.esapi.reference.validation.StringValidationRule.checkWhitelist(StringValidationRule.java:144)
at org.owasp.esapi.reference.validation.StringValidationRule.checkWhitelist(StringValidationRule.java:160)
at org.owasp.esapi.reference.validation.StringValidationRule.getValid(StringValidationRule.java:284)
at org.owasp.esapi.reference.DefaultValidator.getValidInput(DefaultValidator.java:199)
at org.owasp.esapi.reference.DefaultValidator.getValidInput(DefaultValidator.java:236)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at coldfusion.runtime.StructBean.invoke(StructBean.java:508)
at coldfusion.runtime.CfJspPage._invoke(CfJspPage.java:2393)
at cftest2ecfm989071068.runPage(D:\Web\internet\fboc\test.cfm:19)
at coldfusion.runtime.CfJspPage.invoke(CfJspPage.java:231)
at coldfusion.tagext.lang.IncludeTag.doStartTag(IncludeTag.java:416)
at coldfusion.runtime.CfJspPage._emptyTcfTag(CfJspPage.java:2722)
at cfApplication2ecfc1705903666$funcONREQUEST.runFunction(D:\Web\internet\fboc\Application.cfc:70)
at coldfusion.runtime.UDFMethod.invoke(UDFMethod.java:472)
at coldfusion.runtime.UDFMethod$ReturnTypeFilter.invoke(UDFMethod.java:405)
at coldfusion.runtime.UDFMethod$ArgumentCollectionFilter.invoke(UDFMethod.java:368)
at coldfusion.filter.FunctionAccessFilter.invoke(FunctionAccessFilter.java:55)
at coldfusion.runtime.UDFMethod.runFilterChain(UDFMethod.java:321)
at coldfusion.runtime.UDFMethod.invoke(UDFMethod.java:220)
at coldfusion.runtime.TemplateProxy.invoke(TemplateProxy.java:491)
at coldfusion.runtime.TemplateProxy.invoke(TemplateProxy.java:337)
at coldfusion.runtime.AppEventInvoker.invoke(AppEventInvoker.java:88)
at coldfusion.runtime.AppEventInvoker.onRequest(AppEventInvoker.java:280)
at coldfusion.filter.ApplicationFilter.invoke(ApplicationFilter.java:356)
at coldfusion.filter.RequestMonitorFilter.invoke(RequestMonitorFilter.java:48)
at coldfusion.filter.MonitoringFilter.invoke(MonitoringFilter.java:40)
at coldfusion.filter.PathFilter.invoke(PathFilter.java:94)
at coldfusion.filter.ExceptionFilter.invoke(ExceptionFilter.java:70)
at coldfusion.filter.BrowserDebugFilter.invoke(BrowserDebugFilter.java:79)
at coldfusion.filter.ClientScopePersistenceFilter.invoke(ClientScopePersistenceFilter.java:28)
at coldfusion.filter.BrowserFilter.invoke(BrowserFilter.java:38)
at coldfusion.filter.NoCacheFilter.invoke(NoCacheFilter.java:46)
at coldfusion.filter.GlobalsFilter.invoke(GlobalsFilter.java:38)
at coldfusion.filter.DatasourceFilter.invoke(DatasourceFilter.java:22)
at coldfusion.filter.CachingFilter.invoke(CachingFilter.java:62)
at coldfusion.filter.RequestThrottleFilter.invoke(RequestThrottleFilter.java:126)
at coldfusion.CfmServlet.service(CfmServlet.java:201)
at coldfusion.bootstrap.BootstrapServlet.service(BootstrapServlet.java:89)
at jrun.servlet.FilterChain.doFilter(FilterChain.java:86)
at coldfusion.monitor.event.MonitoringServletFilter.doFilter(MonitoringServletFilter.java:42)
at coldfusion.bootstrap.BootstrapFilter.doFilter(BootstrapFilter.java:46)
at jrun.servlet.FilterChain.doFilter(FilterChain.java:94)
at jrun.servlet.FilterChain.service(FilterChain.java:101)
at jrun.servlet.ServletInvoker.invoke(ServletInvoker.java:106)
at jrun.servlet.JRunInvokerChain.invokeNext(JRunInvokerChain.java:42)
at jrun.servlet.JRunRequestDispatcher.invoke(JRunRequestDispatcher.java:286)
at jrun.servlet.ServletEngineService.dispatch(ServletEngineService.java:543)
at jrun.servlet.jrpp.JRunProxyService.invokeRunnable(JRunProxyService.java:203)
at jrunx.scheduler.ThreadPool$ThreadThrottle.invokeRunnable(ThreadPool.java:428)
at jrunx.scheduler.WorkerThread.run(WorkerThread.java:66)


更新2

我一直在挖掘ColdFusion的Damon Miller's implementation of the OWASP ESAPI方法。我在他的代码中注意到他没有使用getValidInput()属性调用ValidationErrorList方法。相反,他编写代码来捕获生成的错误,然后将错误添加到列表本身。嗯?我以为这个方法应该为你做那个????

顺便说一句,我试图不使用像他这样的库来避免我不需要的额外膨胀。

摘自他的代码:

if(structKeyExists( arguments, "errorList" )) {
        try {
            return getValidInput( arguments.context, arguments.input, arguments.type, arguments.maxLength, arguments.allowNull );
        }
        catch(esapi4cf.org.owasp.esapi.errors.ValidationException e) {
            arguments.errorList.addError( arguments.context, e );
        }
        return arguments.input;
    }
    else {
    ...

1 个答案:

答案 0 :(得分:6)

这看起来是ESAPI的Coldfusion实现中的一个错误 - 我们在ESAPI的单元测试套件中对getValidInput方法进行了全面覆盖测试,证明该方法与广告一样有效。

根据您上面的第二次更新,我猜想在CF实现代码中有一个未初始化的变量被访问(可能在此上下文中未初始化errorList)

我是OWASP ESAPI项目的项目负责人,非常熟悉ESAPI本身的这段代码,但我不是CF开发人员,也没有看到CF9的所有实现代码。

** 修改 **

为了使验证方法使用ColdFusion批量工作,在调用init()之前,org.owasp.esapi.ValidationErrorList需要调用validator方法。方法。将以下行添加到测试脚本中,它将起作用:

<cfset ErrorList = ErrorList.init() />

在上下文中:

<cfset ErrorList = CreateObject("java", "org.owasp.esapi.ValidationErrorList") />
<cfset ErrorList = ErrorList.init() />
<cfset Valid.TestField = EsapiValidator.getValidInput("Test Field", form.TestField, "SafeString", 128, true, true, ErrorList) />

现在输入无效输入时,错误将被添加到ErrorList变量而不是抛出错误。