Search code examples
spring-mvcspring-securitycsrfcsrf-protectionowasp

Key for session.getAttribute() is null using OWASP_CSRFTOKEN on a spring framework 3.2.4 app


I am adding OWASP.CsrfGuard.jar to my spring 3.2.4 application to prevent CSRF attacks (CSRF is an attack which forces an end user to execute unwanted actions on a web application in which he/she is currently authenticated. The most commonly used example is "someone tricking you to click on a link to be able to get hold of your logged on banking session and then withdraw money from your bank account without your consent/knowledge)

Here my Owasp.CsrfGuard.properties :

# The OWASP CSRFGuard Project, BSD License
# Eric Sheridan ([email protected]), Copyright (c) 2011
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# 1. Redistributions of source code must retain the above copyright notice,
#    this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
#    notice, this list of conditions and the following disclaimer in the
#    documentation and/or other materials provided with the distribution.
# 3. Neither the name of OWASP nor the names of its contributors may be used
#    to endorse or promote products derived from this software without specific
#    prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
# ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

org.owasp.csrfguard.Logger=fr.balucom.devices.helpers.csrf.CsrfLogger

org.owasp.csrfguard.configuration.provider.factory = org.owasp.csrfguard.config.overlay.ConfigurationAutodetectProviderFactory


# If csrfguard filter is enabled
org.owasp.csrfguard.Enabled = true

org.owasp.csrfguard.ValidateWhenNoSessionExists = false

org.owasp.csrfguard.TokenPerPage=false
org.owasp.csrfguard.TokenPerPagePrecreate=false

org.owasp.csrfguard.Ajax=true

# The default behavior of CSRFGuard is to protect all pages. Pages marked as unprotected will not be protected.
# If the Protect property is enabled, this behavior is reversed. Pages must be marked as protected to be protected.
# All other pages will not be protected. This is useful when the CsrfGuardFilter is aggressively mapped (ex: /*),
# but you only want to protect a few pages.
#
# org.owasp.csrfguard.Protect=true
org.owasp.csrfguard.ProtectedMethods=POST

# unprotected pages

org.owasp.csrfguard.action.Log=org.owasp.csrfguard.action.Log
org.owasp.csrfguard.action.Log.Message=potential cross-site request forgery (CSRF) attack thwarted (user:%user%, ip:%remote_ip%, method:%request_method%, uri:%request_uri%, error:%exception_message%)
org.owasp.csrfguard.action.Redirect=org.owasp.csrfguard.action.Redirect
org.owasp.csrfguard.action.Redirect.Page=/devices/error.do

# Token Name
#
# The token name property (org.owasp.csrfguard.TokenName) defines the name of the HTTP parameter
# to contain the value of the OWASP CSRFGuard token for each request. The following configuration
# snippet sets the CSRFGuard token parameter name to the value OWASP_CSRFTOKEN:
#
org.owasp.csrfguard.TokenName=OWASP_CSRFTOKEN_REQUEST

# Session Key
#
# The session key property (org.owasp.csrfguard.SessionKey) defines the string literal used to save
# and lookup the CSRFGuard token from the session. This value is used by the filter and the tag
# libraries to retrieve and set the token value in the session. Developers can use this key to
# programmatically lookup the token within their own code. The following configuration snippet sets
# the session key to the value OWASP_CSRFTOKEN:
#
org.owasp.csrfguard.SessionKey=OWASP_CSRFTOKEN

# Token Length
#
# The token length property (org.owasp.csrfguard.TokenLength) defines the number of characters that
# should be found within the CSRFGuard token. Note that characters are delimited by dashes (-) in groups
# of four. For cosmetic reasons, users are encourage to ensure the token length is divisible by four.
# The following configuration snippet sets the token length property to 32 characters:
#
# org.owasp.csrfguard.TokenLength=32
org.owasp.csrfguard.TokenLength=32

# Pseudo-random Number Generator
#
# The pseudo-random number generator property (org.owasp.csrfguard.PRNG) defines what PRNG should be used
# to generate the OWASP CSRFGuard token. Always ensure this value references a cryptographically strong
# pseudo-random number generator algorithm. The following configuration snippet sets the pseudo-random number
# generator to SHA1PRNG:
#
# org.owasp.csrfguard.PRNG=SHA1PRNG
org.owasp.csrfguard.PRNG=SHA1PRNG

# Pseudo-random Number Generator Provider

# The pseudo-random number generator provider property (org.owasp.csrfguard.PRNG.Provider) defines which
# provider's implementation of org.owasp.csrfguard.PRNG we should utilize. The following configuration
# snippet instructs the JVM to leverage SUN's implementation of the algorithm denoted by the
# org.owasp.csrfguard.PRNG property:

# org.owasp.csrfguard.PRNG.Provider=SUN
org.owasp.csrfguard.PRNG.Provider=SUN

# If not specifying the print config option in the web.xml, you can specify it here, to print the config
# on startup
org.owasp.csrfguard.Config.Print=true



# seconds between checking to see if the config files are updated
org.owasp.csrfguard.configOverlay.secondsBetweenUpdateChecks = 60


###########################

Then I include this tag in my JSP :

<input type="hidden" name="<csrf:tokenname />" value="<csrf:tokenvalue />" />

But here the result:

]] Root cause of ServletException.
java.lang.IllegalArgumentException: Key for session.getAttribute() is null
        at weblogic.servlet.internal.session.SessionData.check(SessionData.java:457)
        at weblogic.servlet.internal.session.SessionData.getAttribute(SessionData.java:410)
        at org.owasp.csrfguard.CsrfGuard.getTokenValue(CsrfGuard.java:295)
        at org.owasp.csrfguard.tag.TokenValueTag.doStartTag(TokenValueTag.java:49)
        at jsp_servlet._web_45_inf._jsp._accounts.__dataaccount._jsp__tag1(__dataaccount.java:1613)
        at jsp_servlet._web_45_inf._jsp._accounts.__dataaccount._jspService(__dataaccount.java:235)
        at weblogic.servlet.jsp.JspBase.service(JspBase.java:34)
        at weblogic.servlet.internal.StubSecurityHelper$ServletServiceAction.run(StubSecurityHelper.java:280)
        at weblogic.servlet.internal.StubSecurityHelper$ServletServiceAction.run(StubSecurityHelper.java:254)
        at weblogic.servlet.internal.StubSecurityHelper.invokeServlet(StubSecurityHelper.java:136)
        at weblogic.servlet.internal.ServletStubImpl.execute(ServletStubImpl.java:341)
        at weblogic.servlet.internal.ServletStubImpl.onAddToMapException(ServletStubImpl.java:478)
        at weblogic.servlet.internal.ServletStubImpl.execute(ServletStubImpl.java:367)
        at weblogic.servlet.internal.ServletStubImpl.execute(ServletStubImpl.java:238)
        at weblogic.servlet.internal.RequestDispatcherImpl.invokeServlet(RequestDispatcherImpl.java:573)
        at weblogic.servlet.internal.RequestDispatcherImpl.include(RequestDispatcherImpl.java:480)
        at weblogic.servlet.jsp.PageContextImpl.include(PageContextImpl.java:162)
        at jsp_servlet._web_45_inf._jsp._accounts.__registeraccount._jspService(__registeraccount.java:155)
        at weblogic.servlet.jsp.JspBase.service(JspBase.java:34)
        at weblogic.servlet.internal.StubSecurityHelper$ServletServiceAction.run(StubSecurityHelper.java:280)
        at weblogic.servlet.internal.StubSecurityHelper$ServletServiceAction.run(StubSecurityHelper.java:254)
        at weblogic.servlet.internal.StubSecurityHelper.invokeServlet(StubSecurityHelper.java:136)
        at weblogic.servlet.internal.ServletStubImpl.execute(ServletStubImpl.java:341)
        at weblogic.servlet.internal.ServletStubImpl.onAddToMapException(ServletStubImpl.java:478)
        at weblogic.servlet.internal.ServletStubImpl.execute(ServletStubImpl.java:367)
        at weblogic.servlet.internal.ServletStubImpl.execute(ServletStubImpl.java:238)
        at weblogic.servlet.internal.RequestDispatcherImpl.invokeServlet(RequestDispatcherImpl.java:573)
        at weblogic.servlet.internal.RequestDispatcherImpl.include(RequestDispatcherImpl.java:480)
        at org.apache.taglibs.standard.tag.common.core.ImportSupport.acquireString(ImportSupport.java:347)
        at org.apache.taglibs.standard.tag.common.core.ImportSupport.doEndTag(ImportSupport.java:204)
        at jsp_servlet._web_45_inf._jsp._template.__template._jsp__tag2(__template.java:366)
        at jsp_servlet._web_45_inf._jsp._template.__template._jspService(__template.java:248)
        at weblogic.servlet.jsp.JspBase.service(JspBase.java:34)
        at weblogic.servlet.internal.StubSecurityHelper$ServletServiceAction.run(StubSecurityHelper.java:280)
        at weblogic.servlet.internal.StubSecurityHelper$ServletServiceAction.run(StubSecurityHelper.java:254)
        at weblogic.servlet.internal.StubSecurityHelper.invokeServlet(StubSecurityHelper.java:136)
        at weblogic.servlet.internal.ServletStubImpl.execute(ServletStubImpl.java:341)
        at weblogic.servlet.internal.ServletStubImpl.onAddToMapException(ServletStubImpl.java:478)
        at weblogic.servlet.internal.ServletStubImpl.execute(ServletStubImpl.java:367)
        at weblogic.servlet.internal.ServletStubImpl.execute(ServletStubImpl.java:238)
        at weblogic.servlet.internal.RequestDispatcherImpl.invokeServlet(RequestDispatcherImpl.java:573)
        at weblogic.servlet.internal.RequestDispatcherImpl.forward(RequestDispatcherImpl.java:272)
        at org.springframework.web.servlet.view.InternalResourceView.renderMergedOutputModel(InternalResourceView.java:2
38)
        at org.springframework.web.servlet.view.AbstractView.render(AbstractView.java:264)
        at org.springframework.web.servlet.DispatcherServlet.render(DispatcherServlet.java:1208)
        at org.springframework.web.servlet.DispatcherServlet.processDispatchResult(DispatcherServlet.java:992)
        at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:939)
        at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:856)
        at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:953)
        at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:844)

and here my web.xml

<!-- CSRF Guard -->
        <context-param>
            <param-name>Owasp.CsrfGuard.Config</param-name>
            <param-value>/WEB-INF/Owasp.CsrfGuard.properties</param-value>
        </context-param>

        <context-param>
            <param-name>Owasp.CsrfGuard.Config.Print</param-name>
            <param-value>true</param-value>
        </context-param>

        <filter>
            <filter-name>CSRFGuard</filter-name>
            <filter-class>org.owasp.csrfguard.CsrfGuardFilter</filter-class>
        </filter>
        <filter-mapping>
            <filter-name>CSRFGuard</filter-name> 
             <url-pattern>/*</url-pattern>
        </filter-mapping>

         <listener>
            <listener-class>org.owasp.csrfguard.CsrfGuardServletContextListener</listener-class>
        </listener>
        <listener>
            <listener-class>org.owasp.csrfguard.CsrfGuardHttpSessionListener</listener-class>
        </listener>
        <!-- CSRF Guard -->

Solution

  • It seems that WebLogic doesn't like Sun's SHA1PRNG implementation. On our project, we've found that in order to get CSRF Guard to work on WebLogic (i.e., avoid the exact error you're getting), we need to replace

    org.owasp.csrfguard.PRNG=SHA1PRNG
    org.owasp.csrfguard.PRNG.Provider=SUN
    

    with

    org.owasp.csrfguard.PRNG=IBMSecureRandom
    org.owasp.csrfguard.PRNG.Provider=IBMJCE
    

    I'm not sure if this means you'll need to use the IBM JDK in order to use WebLogic with CSRF Guard, or if you can use some other PRNG to make it work.

    As a note, this does seem to be specific to WebLogic, so you may have better luck with another Java web application server.