Author: Nicholas Bamber <nicholas@periapt.co.uk>
Subject: Polish up English usage in Pod
Bug: http://rt.cpan.org/Ticket/Display.html?id=72342
Last-Upate: 2011-11-09
--- a/CGI/Application/Plugin/ProtectCSRF.pm
+++ b/CGI/Application/Plugin/ProtectCSRF.pm
@@ -4,7 +4,7 @@
 
 =head1 NAME
 
-CGI::Application::Plugin::ProtectCSRF - Plug-in protected from CSRF
+CGI::Application::Plugin::ProtectCSRF - generate and verify anti-CSRF tickets
 
 =head1 VERSION
 
@@ -14,7 +14,7 @@
 
   use Your::App;
   use base qw(CGI::Application);
-  use CGI::Application::Plugin::Session; # require!!
+  use CGI::Application::Plugin::Session; # mandatory !!
   use CGI::Application::Plugin::ProtectCSRF;
 
   sub input_form : PublishCSRFID {
@@ -30,9 +30,20 @@
 
 =head1 DESCRIPTION
 
-CGI::Application::Plugin::ProtectCSRF is C::A::P protected from CSRF.
-
-When CSRF is detected, Forbidden is returned and processing is interrupted.
+CGI::Application::Plugin::ProtectCSRF provides tools to protect forms in
+L<CGI::Application> web applications from CSRF attacks. Run mode handlers
+may be declared with the C<PublishCSFRID> or C<ProtectCSFR> attributes.
+The former should usually be applied to a run mode, whose HTML includes
+a C<form> tag. In this case a ticket is generated and stored in the session
+during a prerun callback and a C<hidden> control field, publishing the
+ticket, is added to the form during a postrun callback. Conversely the
+C<ProtectCSRF> attribute should normally be applied to the corresponding
+run modes that process data from a submitted form. A prerun callback checks
+for the hidden field and checks that it matches the ticket saved
+in the session. If the check fails the page is redirected to a
+customizable error page. On success the form processing run mode should
+use the C<clear_csrf_id> method, so that subsequent calls to forms from that
+session will generate fresh tickets.
 
 =cut
 
@@ -67,7 +78,7 @@
 <head><title>CSRF ERROR</title></head>
 <body>
 <h1>CSRF ERROR</h1>
-<p>This access is illegal. you don't have permission to access on this server.</p>
+<p>Access denied. Please contact the website administrator.</p>
 </body>
 </html>
 };
@@ -82,7 +93,7 @@
     my $pkg = caller;
 
 # C::A::P::Session method check
-    croak("C::A::P::Session module is not load to your app") if !$pkg->can("session");
+    croak("CGI::Aplication::Plugin::Session module is not loaded in your app") if !$pkg->can("session");
 
     $pkg->add_callback("prerun",  \&_publish_csrf_id);
     $pkg->add_callback("prerun",  \&_csrf_forbidden);
@@ -97,10 +108,18 @@
 
 =head2 PublishCSRFID
 
-PublishCSRFID is action publishes CSRF ticket. CSRF ticket is published when I
-define it as an attribute of runmode method publishing CSRF ticket, and it is saved in session.
-If there is form tag in HTML to display after the processing end, as for runmode method to
-publish, CSRF ticket is set automatically by hidden field
+Run modes declared with the C<PublishCSRFID> attribute, take the following
+actions:
+
+=over
+
+=item - generate CSRF ticket and store it in the session;
+
+=item - generate the form as per the module code;
+
+=item - add a hidden element to the form publishing the CSRF ticket.
+
+=back
 
   # publish CSRF ticket
   sub input_form : PublishCSRFID {
@@ -124,15 +143,33 @@
 
 =head2 ProtectCSRF
 
-ProtectCSRF is action to protect from CSRF Attack. If session CSRF ticket does not accord
-with query CSRF ticket, application consideres it to be CSRF attack and refuse to access it.
-Carry out the processing that you want to perform after having carried out clear_csrf_id method
-when access it, and it was admitted.
+Run modes declared with the C<ProtectCSRF> attribute, take the following
+actions:
+
+=over
+
+=item - verify that the submitted CSRF ticket matches the ticket saved in the
+session. If there is any sort of issue with the ticket the page is
+redirected to a customizable error page;
+
+=item - the form is processed as per the module code;
+
+=item - the form should call the C<clear_csfr_id> method so that subsequent forms
+generate fresh tickets. The code does not do this because if the form validation
+fails it might be best to retain the same ticket.
+
+=back
 
   sub finish : ProtectCSRF {
     my $self = shift;
-    $self->clear_csrf_id; # require! There is not a meaning unless I do it
-    do_something();       # The processing that you want to perform (DB processing etc)
+
+    # required! Unless forms and their processing are tightly
+    # coupled by clearing the ticket between invocations,
+    # the meaning of the ticket is lost.
+    $self->clear_csrf_id;
+
+    # The processing that you want to perform (DB processing etc)
+    do_something();
   }
 
 =cut
@@ -154,7 +191,7 @@
 
 =head2 csrf_id
 
-Get ticket for protect CSRF
+This method returns the CSRF ticket saved in the session.
 
 Example: 
 
@@ -175,16 +212,44 @@
 
 =head2 protect_csrf_config
 
-Initialize ProtectCSRF
+This method initializes the ProtectCSRF state using any configuration options
+that were passed to it. The available options are:
+
+=over
+
+=item B<csrf_error_status> - The HTTP status code that would be set on the
+CSRF error page if a CSRF attack is identified. It defaults to 200.
+
+=item B<csrf_error_mode> - The L<CGI::Application> runmode name. This defaults to C<_csrf_error>.
+
+=for comment
+
+The Debian maintainer is unclear why this option is useful. Surely an
+anonymous run mode would be cleaner here.
+
+=end comment
+
+=item B<csrf_error_tmpl> - The HTML displayed in the event of a CSRF attack being
+detected in the form of a scalarref or filepath or filehandle. One may
+consider L<HTML::Template> for inspiration on thse formats. The default is
+C<$CSRF_ERROR_TMPL> which is a scalarref.
+
+=item B<csrf_error_tmpl_param> - A hashref of parameters to be placed in the
+above template. See L<HTML::Template>.
+
+=for comment
+
+The Debian maintainer thinks other templating systems should work but is
+unlikely to experiment with this in the near future.
+
+=end comment
+
+=item B<csrf_id> - The name of the session parameter used to store the CSRF ticket.This defaults to C<_csrf_id>.
 
-Option:
+=item B<csrf_post_only> - If set non-POST requests to a run mode which is protected
+by this module would be rejected. By default this is 0.
 
-  csrf_error_status      : CSRF error status code (default: 200)
-  csrf_error_mode        : CSRF error runmode name (default: _csrf_error)
-  csrf_error_tmpl        : CSRF error display html. scalarref or filepath or filehandle (default: $CSRF_ERROR_TMPL - scalarref)
-  csrf_error_tmpl_param  : CSRF error display html parameter (for HTML::Template)
-  csrf_id                : CSRF ticket name (default: _csrf_id)
-  csrf_post_only         : CSRF protect runmode request method check(default:0  1:POST Only)
+=back
 
 Example:
 
@@ -233,7 +298,8 @@
 
 =head2 clear_csrf_id
 
-Clear csrfid. It is preferable to make it execute after processing ends.
+This method clears the CSFR ticket. This should be done during the processing
+of a form request.
 
 Example : 
 
@@ -415,11 +481,21 @@
 
 =head1 CAUTION
 
-It has only the protection function of basic CSRF,and mount other security checks in the application, please.
+This module should not be seen as a panacea for all web security issues.
+The user should fully understand and act on all security threats his
+application may face, including whether this module is an adequate and
+useful tool.
 
 =head1 SEE ALSO
 
-L<Attribute::Handlers> L<Carp> L<CGI::Application> L<CGI::Application::Plugin::Session> L<Digest::SHA1> L<Exporter> L<HTML::TokeParser> 
+L<Attribute::Handlers>,
+L<Carp>,
+L<CGI::Application>,
+L<CGI::Application::Plugin::Session>,
+L<Digest::SHA1>,
+L<Exporter>,
+L<HTML::TokeParser>,
+L<HTML::Template>
 
 =head1 AUTHOR
 
