Package: collective.honeypot
ContentsIntroductionUse casesIdeaInstallation and usageFixesProtecting your own formsConfigurationWhen are the checksnotdone?z3c.formCompatibilityChangelog2.1 (2022-11-04)2.0 (2021-01-27)1.0.3 (2020-04-08)1.0.2 (2015-10-01)1.0.1 (2015-08-25)1.0 (2015-08-24)0.7 (2014-04-18)0.6 (2014-04-17)0.5 (2014-04-16)0.4 (2014-04-15)0.3 (2014-03-14)0.2 (2014-03-14)0.1 (2014-03-14)IntroductionThis package gives honeypot protection for forms.Use casesSpammers have found you and are pounding various forms on your
website.  Prime victims are the join form, contact form, sendto form
and comment form.Maybe you have some captcha protection in place but spammers have
found a way around it.  Or you want to detect a spammer before doing a
possibly time consuming validation.You have noticed that some scripts send e-mails or add a comment even
when they receive aGETinstead of aPOSTrequest.You do not want to put up any user unfriendly captchas, but do not
want to make it easy for spammers either.Or, rather differently, you wonder if you can temporarily disallow allPOSTrequests while you are doing a big migration.IdeaOne anti-spam idea that has found adoption is a honeypot: adding a
field that would never be filled in by a human.  The reasoning is that
spammers will likely fill in all fields in a form, for two reasons:The bots do not know which fields are required, so they
fill everything in, just to be sure.After a successful submission, each field might be shown on the
website, so they fill all fields to get their message in the face
of unsuspecting visitors.The field should be hidden so it does not distract humans.  But:
making the input type hidden could mean that a spammer ignores it and
does not fill it in after all, so we hide it with css instead.Some spambots seem to know a bit about Plone.  They know which fields
are required on a few forms in a standard Plone website without
captchas, or they even know a way around validation.  If we add an
invisible field they will simply not use it.  So: for a few explicitly
selected forms we require that the invisible field is in the submitted
form, although it must be empty.Installation and usageAddcollective.honeypotto the eggs of your zope instance in your
buildout config:[instance]
eggs =
    collective.honeypotRun buildout and start the zope instance.What does this do?This registers overrides for several templates and scripts (usingz3c.jbot).It adds those templates and scripts to the list of extra protected
actions.  This means that aPOSTrequest to these actions nowmusthave the honeypot field and itmustbe empty.FixesSome scripts in standard Plone happily add a comment or send an e-mail
when you use aGETrequest.  This package does not agree with that
policy and has fixes to require aPOSTrequest.When usingz3c.jbot, the package detects which fixes are needed.
Some add-ons may or may not be
available, so we only load fixes that can be applied, especially forplone.app.discussion.If you override a script or template in an own skin layer or via some
zcml, then our fixes may have no effect, so you need to do a fix
yourself.So, what are the actual fixes that this package contains?Some forms may get the invisible honeypot field automatically.  This
package registers an override for the@@authenticatorview fromplone.protectthat is used in several templates for csrf
protection (cross site request forgery).  So any template that
already uses this, is automatically loading our honeypot field.plone.app.discussion:Add the honeypot field to the ‘add comment’ form.  This fix is
only done when you loadfixes.zcml.The honeypot field isnotrequired, because the ‘add comment’
form posts to the context, not to a specific action.Plone:RequirePOSTfor thesend_feedback_siteandsendtoscripts.Add the honeypot field to thesendto_formandcontact-infoforms.The register form is automatically protected by our@@authenticatoroverride.Require the honeypot field for the above actions and the join
form, specifically:sendto_form,sendto,contact-info,send_feedback_site,register,join_form.Protecting your own formsIn a form that you want to protect, you must add this:<div tal:replace="structure context/@@honeypot_field|nothing" />This is all that is needed to have the basic protection of an
invisible field that captures spammers if they fill it in.  AForbiddenexception is raised in that case.Some forms may get this invisible field automatically.  This package
registers an override for the@@authenticatorview fromplone.protectthat is used in several templates for csrf
protection (cross site request forgery).  So any template that already
uses this, is automatically loading our honeypot field.For extra protection, you can add the page on which the form appears
to theEXTRA_PROTECTED_ACTIONS.  This means that theForbiddenexception is also raised if the field is not submitted in the form at
all.  See theConfigurationsection.Note that it would be nice to accept all posts from authenticated
users, but our code is run too early in the Zope process: we cannot
know yet if the user is logged in or not.ConfigurationThere is no configuration that you can do within a Plone Site.  That
would be too easy to get wrong, possibly even disabling the means to
undo the damage.  Also, with multiple Plone Sites in one Zope instance
this would get even trickier.  So we chose a different approach.You can configure settings via environment variables in thezope.confof your zope instance.  For testing you could set an
environment variable in your command shell and start the zope instance
and it will get picked up.  But the usual way would be to do this inbuildout.cfg:[instance]
environment-vars =
    HONEYPOT_FIELD pooh
    EXTRA_PROTECTED_ACTIONS discussion_reply join_form sendto_form
    WHITELISTED_ACTIONS jq_reveal_email
    WHITELISTED_START jq_*
    IGNORED_FORM_FIELDS secret_field
    ACCEPTED_LOG_LEVEL info
    SPAMMER_LOG_LEVEL error
    DISALLOW_ALL_POSTS noGeneral notes:None of the options are required.  It will work fine without any
environment variables.Values are split on whitespace or comma.Any@character gets automatically replaced by a space, to make
it easier to reference@@some_viewby simplysome_view, as
we always protect them both.These are the supported variables:HONEYPOT_FIELDName to use as input name of the honeypot field.  If you give no
value here, no honeypot checks are done, so you only get some
logging.  This is obviously not the main goal of this package, but
it may be useful when you need to do some debugging.  If you do
not list the variable, you get the default value ofprotected_1.  In case spammers learn about this package and do
not fill in the standard name, you can change the name here.EXTRA_PROTECTED_ACTIONSFor these form actions the honeypot field is required: the fieldmustbe in the posted request, though it of course stillmustbe empty.  If you add actions here but do not change the forms,
they become unusable for visitors, which is not what you want.  On
the other hand, if you have a form that you no longer wish to use,
you can add it here and it will stop functioning.  For@@viewsimply useviewand it will match both.WHITELISTED_ACTIONSThese form actions are not checked.  List here actions that are
harmless, for example actions that load some data via an AJAX
call.  Generally, actions that change nothing in the database and
do not send emails are safe to add here.  If you add this
environment variable but leave it empty, you override the
default and do not whitelist anything.  By default we whitelist
these actions:at_validate_field(inline validation)atct_edit(edit form)edit(edit form)kssValidateField(inline validation)jq_reveal_email(zest.emailhider)z3cform_validate_field(inline validation)WHITELISTED_STARTForm actions starting with one of these strings are not checked.
SeeWHITELISTED_ACTIONSfor more info.  If you have lots of
harmless actions that start withjq_you can add that string
to this list.  Regular expression are too easy to get wrong, so we
do not support it.IGNORED_FORM_FIELDSWe log information aboutPOSTrequests, to allow a system admin to
go through the log and discover posts that are obviously spam
attempts but are not caught yet and need extra handling, perhaps
an extra form that should get protection.  This information may
contain form fields that should be left secret or that are not
interesting.  No matter what you fill in here, we always ignore
fields that contain the termpassword.ACCEPTED_LOG_LEVELLog level for accepted posts.  This accepts standard lower or
upper case log levels: debug, info, warn, warning, error,
critical.  When an unknown level is used or the setting is empty,
we fall back to the default:INFO.SPAMMER_LOG_LEVELLog level for caught spammers.  This accepts standard lower or
upper case log levels: debug, info, warn, warning, error,
critical.  When an unknown level is used or the setting is empty,
we fall back to the default:ERROR.DISALLOW_ALL_POSTSSet this to1,on,true, oryesto disallow allPOSTrequests.  This may be handy if you want to effectively
make a Plone Site read-only, for example in preparation of a
security release or when you are doing a big migration in a new
zope instance and want to keep the old instance alive for the time
being.  Note that, like the rest of the checks, this only has an
effect in a Plone (or CMF) site, not in the Zope root.When are the checksnotdone?This package does not check fields on anyGETrequests, it actually blocks
theGETrequests on selected forms and requires aPOSTthere. Hence the
field checks only work onPOSTrequests.If you have made theHONEYPOT_FIELDconfiguration option empty, no
honeypot checks are done, so you only get some logging.If Zope does any traversal, only the original action is checked.  For
example:A visitor makes a POST request to amy_formaction.  The
honeypot checks are done for that action.Themy_formaction may be an old-style CMF form controller
action that calls a validation scriptvalidate_my_form.  This
validation script doesnotget honeypot checks.After validation, the action may do a traverse to a scriptdo_actionthat does the real work, like changing the database or
sending an email.  This script doesnotget honeypot checks.As an aside, if you have such a setup, you should make sure thedo_actionscript calls a validation script too and only acceptsPOSTrequests.  Otherwise a smart spammer can bypass thevalidate_my_formvalidation script by requesting thedo_actionscript directly.  And he can bypass the honeypot checks by using aGETrequest.z3c.formYou can easily add a honeypot field to az3c.form.  Just add aTextLinefield to your formInterfacedefinition, set thewidgetFactoryto the widget thatcollective.honeypotsupplies,
and make it hidden.  Something like this:from collective.honeypot.z3cform.widget import HoneypotFieldWidget
from z3c.form import form, interfaces
from zope import schema
from zope.interface import Interface

class IHoneypot(Interface):
    # Keep field title empty so visitors do not see it.
    honeypot = schema.TextLine(title=u"", required=False)

class MyForm(form.Form):
    fields = form.field.Fields(IHoneypot)

    def update(self):
        self.fields['honeypot'].widgetFactory = HoneypotFieldWidget
        self.fields['honeypot'].mode = interfaces.HIDDEN_MODESeecollective/honeypot/discussion/z3cformextender.pyfor an
example of how to extend an existing form, in this case the comment
form inplone.app.discussion.CompatibilityThis works on Plone 5.2.Changelog2.1 (2022-11-04)Add support for restapi POST.
[cekk]Support Plone 5.2 on Py 2.7+3.7+3.8 and Plone 6.0 on Py 3.8+3.9+3.10.  [maurits]Test on GitHub Actions instead of Travis.  [maurits]2.0 (2021-01-27)Automatically load the fixes if package is loaded. No need to explicitly include thefixes.zcmlanymore.
[thet]Secure collective.easyform with honeypot if available.
[thet]Add a generic z3c.form honeypot extender module which can be configured via ZCML only and configure plone.app.discussion to use it.
[thet]Add a dummy widget display view which renders empty - form renderings may expect it.
[thet]Add data converter for z3c.form validation to not fail when multiple HoneyPot fields were injected.
[thet]Update for support of Plone 5.2 and Python 3. Remove support for Plone 3 and 4.
[thet, reinhardt]1.0.3 (2020-04-08)Fix adapter registration conflict.
[rodfersou]1.0.2 (2015-10-01)Split honeypot_field and authenticator view.  When@@authenticator`is called, return the view without rendering it.
Fixes AttributeError: ‘unicode’ object has no attribute ‘token’, for
example on PloneFormGen quickedit form.
[maurits]Added Travis badge to readme.
[maurits]1.0.1 (2015-08-25)Require POST forsend_feedbackscript.  This script can only be
used by authenticated users, so there is little danger, but POST is
still better.
[maurits]1.0 (2015-08-24)First official public release.Add kssValidateField to the default WHITELIST_ACTIONS to suppress kss inline
validation being logged on Plone <= 4.2 .
[fredvd]0.7 (2014-04-18)Add GenericSetup profile, which adds skin layers with our fixes.
This is recommended on Plone 3.  The reason is that this technique
does not needz3c.jbot, which can have a few ugly side effects
in Plone 3:Products.CacheSetupdoes not like it and in other
cases Zope does not even start up.
[maurits]0.6 (2014-04-17)Whitelist edit forms by default.
[maurits]Log when we load patches and add extra protected actions.
[maurits]0.5 (2014-04-16)Support disallowing all posts.
[maurits]Support checking start strings for white listed actions.
[maurits]Allow configuring log levels.
[maurits]Print less when logging the form.
[maurits]0.4 (2014-04-15)Add fixes forquintagroup.plonecomments.
[maurits]Add fixes for Plone 3.
[maurits]0.3 (2014-03-14)Removez3c.jbotfrom the default dependencies so the
last change actually works.
[maurits]0.2 (2014-03-14)Makez3c.jbotan extra dependency ofcollective.honeypot[fixes].
This way, you only getz3c.jbotwhen you need it.
[maurits]0.1 (2014-03-14)Initial release.
[maurits]