>>>>> On Wed, 17 Aug 2011 15:12:16 -0700, Ed Burns <edward.burns_at_oracle.com> said:
EB> Relative to proposal version 20110726 of
EB> <
http://javaserverfaces-spec-public.java.net/nonav/proposals/JAVASERVERFACES_SPEC_PUBLIC-869-CSRF.txt>.
EB> This email contains my responses to Blake's helpful 27 July reply.
EB> I will produce a new version of the proposal as time allows this
EB> week.
And here it is. Sorry for the delay. ACTION: Please review by 09:00 -5
Tuesday 30 August 2011. That's 9am Eastern Daylight Time.
Thanks,
Ed
Version 20110825
http://jsf-spec.java.net/nonav/proposals/JAVASERVERFACES_SPEC_PUBLIC-869-CSRF.txt
SECTION: Discussion
>>>>> On Mon, 25 Jul 2011 18:43:53 -0700, Blake Sullivan <blake.sullivan_at_oracle.com> said:
B> On the GET side, we have two problems--one implementation and one
B> controlling which pages this applies to (or doesn't apply to). I laid
B> out the implementation possibilities. The problem of determining when
B> to apply is that any page that needs to be directly accessible from
B> outside the application can not have this check applied to it, but JSF
B> doesn't currently keep track of valid external entry points.
I assert that we only need to keep track of views that should be
protected. Any view that is in the app, but not in the set of protected
views, is a valid external entry point. When JSF renders a view that is
an external entry point, if it is rendering a link to a protected view,
it will include information in the link such that when the protected
view is requested by the user agent, CSRF protection is applied.
B> If we are specifying rules, should the rules be based purely
B> on the URL?
I think the rules should be based on viewId.
B> If we are modifying the generated URLs, I worry some about
B> the performance impact of stamped actions.
Noted, we must ensure the overhead of discovering "is this view
protected" is very small.
B> Even if we end up falling back to URL manipulation for GETs, I would
B> prefer that we use referer checking if the referer was present in the
B> HTTP Request that initially created the session, as this doesn't
B> require any URL manipulation.
Blake also requested a way to declare protection on a per-view level,
within the view. I assert this will be too tricky to implement because
we would have to crawl the views at startup time to discover which pages
were declared for protection in this way. I don't think it's worth the
trouble and complexity.
B> Shouldn't we be more specific about the exception thrown? I would think
B> that an IllegalStateException would do the trick, but we might want an
B> explicit exception so that the exception handling system knows what kind
B> of exception this is. I don't think that anyone would do this, but why
B> can't the token be in the exception?
Yes, I'll declare an explicit exception.
SECTION: Proposal
JSF offers three varieties of navigation from view to view, all of which
can be used at any point in an application.
SUBSECTION: Terms for Navigation in JSF
PostBack
In this variety, the user agent issues an initial HTTP GET to enter
into the navigation and subsequent navigations are done by the browser
sending a POST request with a server side RequestDispatcher.forward()
to another view.
PostRedirectGet
This is the same as PostBack except that the server sends a
redirect to the user agent, causing it to issue a new GET request.
GetGet
This variety can be used when form submission is not required.
All three varieties must be protected from Cross Site Request Forgery
attacks.
PostBack navigation is protected implicitly by virtue of the
requirement, new in JSF 2.2, that the view state token must be
cryptographically strong and verified.
PostRedirectGet and GetGet navigation is protected by the developer
taking explicit action to mark any views which should be protected.
SUBSECTION: Developer Experience
Within the <faces-config-extension> element, we introduce a new element:
<protected-views/>. This element contains zero or more <url-pattern />
elements. Any view that matches any of the url-patterns in this element
may only reached from another JSF view in the same web
application. Because the runtime is aware of which views are protected,
any navigation from an unprotected view to a protected view is
automatically subject to protection.
To support dynamic views, there must be a way at runtime to modify the
set of protected views. API has been added to ViewHandler to support
this feature.
public List<String> getProtectedViewsUnmodifiable();
public void addProtectedView(String urlPattern);
public void removeProtectedView(String urlPattern);
This API is also called by the runtime when it needs to determine if a
view is protected when rendering navigation to that view.
SUBSECTION: Specification and Implementation Details
* In the spec PDF, in the section titled
"faces-config-extension-handling", add a section after the section on
the <facelets-processing /> element, specifying the handling of the
<protected-views/> element. Follow the example of
<facelets-processing />. Specify that the content of the
<protected-views /> element must populate the protected view API on
the ViewHandler.
* In the spec PDF, in the section titled "Default ViewHandler
Implementation" declare the protected view API and refer to the
javadoc for the methods for the specification.
* In the ViewHandler javadoc, specify the protected view API.
* In the spec PDF, in the section titled "ResponseStateManager" modify
the spec for writeState(FacesContext,Object) to point to the javadoc.
* In an apparent spec bug, there is no javadoc on
ResponseStateManager.writeState(FacesContext,Object). Move the text
from the corresponding section in the PDF into the javadoc. Include
text requiring the state to be encrypted and tamper evident.
* In the spec PDF, in the section titled "ResponseStateManager", modify
the spec for getState(FacesContext, String) to point to the javadoc.
* In the javadoc for ResponseStateManager.getState(FacesContext,String),
specify that the state written by the previous call to
RSM.writeState() must by decrypted and verified before being
restored. Specify that if the state fails to decrypt or verify, a
ProtectedViewException must be thrown.
class javax.faces.application.ProtectedViewException extends
IllegalStateException
* In the spec PDF, in the section titled "Restore View", add a bullet
immediately before the first bullet in the section that starts with
"If the request is not a postback". This bullet will say something
like:
If the request is not a postback, use the protected view API to
determine if the view for this viewId is protected. If not,
continue. Otherwise, look for a "Referer" request header. If the
header is present, use the protected view API to see if any of the
protected views match the value of the Referer header. Note that
this allows a web app to be constructed so that it accepts arbitrary
urls, even from other web apps. If so, continue. If not, verify
that the Referer header value corresponds to a view in the current
web app. If not, throw a ProtectedViewException. If so, continue.
If the Referer header is not present, verify the request parameter's
value given by the value of the constant
ResponseStateManager.NON_POSTBACK_VIEW_TOKEN_PARAM is the same as
the token value generated from the "secret key" stored in the
session. If the values do not match, throw a ProtectedViewException.
* In the spec PDF, in the section titled "Default ViewHandler
Implementation", in the specification for getActionURL(), incorporate
text similar to the following.
If the current view is one of the views to which CSRF protection
should be applied, the returned URL must contain the parameter with
a name consisting of the form's fully namespaced client identifier,
the NamingContainer.SEPARATOR_CHAR and the constant defined by
ResponseStateManager.NON_POSTBACK_VIEW_TOKEN_PARAM. The value of
this parameter, known as the "token value" must be a
cryptographically produced random generated value (known as the
"secret key") retrieved from the session. If the "secret key" does
not already exist in the session, create the random value and store
it in the session. Implementations may choose to produce a more
complex token value by combining the random "secret key" with other
values.
--
| edward.burns_at_oracle.com | office: +1 407 458 0017
| homepage: | http://ridingthecrest.com/
| 21 business days until JSF 2.2 Early Draft Review
| 25 business days until JavaOne 2011