cutelyst
4.5.1
A C++ Web Framework built on top of Qt, using the simple approach of Catalyst (Perl) framework.
|
Protect input forms against Cross Site Request Forgery (CSRF/XSRF) attacks. More...
#include <Cutelyst/Plugins/CSRFProtection/CSRFProtection>
Protected Member Functions | |
bool | setup (Application *app) override |
Protected Member Functions inherited from QObject | |
virtual void | childEvent (QChildEvent *event) |
virtual void | connectNotify (const QMetaMethod &signal) |
virtual void | customEvent (QEvent *event) |
virtual void | disconnectNotify (const QMetaMethod &signal) |
bool | isSignalConnected (const QMetaMethod &signal) const const |
int | receivers (const char *signal) const const |
QObject * | sender () const const |
int | senderSignalIndex () const const |
virtual void | timerEvent (QTimerEvent *event) |
Additional Inherited Members | |
Public Member Functions inherited from Cutelyst::Plugin | |
Plugin (Application *parent) | |
Public Member Functions inherited from QObject | |
QObject (QObject *parent) | |
QBindable< QString > | bindableObjectName () |
bool | blockSignals (bool block) |
const QObjectList & | children () const const |
QMetaObject::Connection | connect (const QObject *sender, const char *signal, const char *method, Qt::ConnectionType type) const const |
void | deleteLater () |
void | destroyed (QObject *obj) |
bool | disconnect (const char *signal, const QObject *receiver, const char *method) const const |
bool | disconnect (const QObject *receiver, const char *method) const const |
void | dumpObjectInfo () const const |
void | dumpObjectTree () const const |
QList< QByteArray > | dynamicPropertyNames () const const |
virtual bool | event (QEvent *e) |
virtual bool | eventFilter (QObject *watched, QEvent *event) |
T | findChild (const QString &name, Qt::FindChildOptions options) const const |
QList< T > | findChildren (const QRegularExpression &re, Qt::FindChildOptions options) const const |
QList< T > | findChildren (const QString &name, Qt::FindChildOptions options) const const |
QList< T > | findChildren (Qt::FindChildOptions options) const const |
bool | inherits (const char *className) const const |
void | installEventFilter (QObject *filterObj) |
bool | isQuickItemType () const const |
bool | isWidgetType () const const |
bool | isWindowType () const const |
void | killTimer (int id) |
virtual const QMetaObject * | metaObject () const const |
void | moveToThread (QThread *targetThread) |
QString | objectName () const const |
void | objectNameChanged (const QString &objectName) |
QObject * | parent () const const |
QVariant | property (const char *name) const const |
Q_CLASSINFO (Name, Value) | |
Q_EMIT Q_EMIT | |
Q_ENUM (...) | |
Q_ENUM_NS (...) | |
Q_ENUMS (...) | |
Q_FLAG (...) | |
Q_FLAG_NS (...) | |
Q_FLAGS (...) | |
Q_GADGET Q_GADGET | |
Q_GADGET_EXPORT (EXPORT_MACRO) | |
Q_INTERFACES (...) | |
Q_INVOKABLE Q_INVOKABLE | |
Q_MOC_INCLUDE Q_MOC_INCLUDE | |
Q_NAMESPACE Q_NAMESPACE | |
Q_NAMESPACE_EXPORT (EXPORT_MACRO) | |
Q_OBJECT Q_OBJECT | |
Q_PROPERTY (...) | |
Q_REVISION Q_REVISION | |
Q_SET_OBJECT_NAME (Object) | |
Q_SIGNAL Q_SIGNAL | |
Q_SIGNALS Q_SIGNALS | |
Q_SLOT Q_SLOT | |
Q_SLOTS Q_SLOTS | |
T | qobject_cast (const QObject *object) |
T | qobject_cast (QObject *object) |
QT_NO_NARROWING_CONVERSIONS_IN_CONNECT QT_NO_NARROWING_CONVERSIONS_IN_CONNECT | |
void | removeEventFilter (QObject *obj) |
void | setObjectName (const QString &name) |
void | setObjectName (QAnyStringView name) |
void | setParent (QObject *parent) |
bool | setProperty (const char *name, const QVariant &value) |
bool | setProperty (const char *name, QVariant &&value) |
bool | signalsBlocked () const const |
int | startTimer (int interval, Qt::TimerType timerType) |
int | startTimer (std::chrono::milliseconds interval, Qt::TimerType timerType) |
QThread * | thread () const const |
Static Public Member Functions inherited from QObject | |
QMetaObject::Connection | connect (const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type) |
QMetaObject::Connection | connect (const QObject *sender, const QMetaMethod &signal, const QObject *receiver, const QMetaMethod &method, Qt::ConnectionType type) |
QMetaObject::Connection | connect (const QObject *sender, PointerToMemberFunction signal, const QObject *context, Functor functor, Qt::ConnectionType type) |
QMetaObject::Connection | connect (const QObject *sender, PointerToMemberFunction signal, const QObject *receiver, PointerToMemberFunction method, Qt::ConnectionType type) |
QMetaObject::Connection | connect (const QObject *sender, PointerToMemberFunction signal, Functor functor) |
bool | disconnect (const QMetaObject::Connection &connection) |
bool | disconnect (const QObject *sender, const char *signal, const QObject *receiver, const char *method) |
bool | disconnect (const QObject *sender, const QMetaMethod &signal, const QObject *receiver, const QMetaMethod &method) |
bool | disconnect (const QObject *sender, PointerToMemberFunction signal, const QObject *receiver, PointerToMemberFunction method) |
QString | tr (const char *sourceText, const char *disambiguation, int n) |
Public Attributes inherited from QObject | |
typedef | QObjectList |
Properties inherited from QObject | |
objectName | |
The CSRFProtection plugin implements a synchronizer token pattern (STP) to protect input forms against Cross Site Request Forgery (CSRF/XSRF) attacks. This type of attack occurs when a malicious website contains a link, a form button or some JavaScript that is intended to perform some action on your website, using the credentials of a logged-in user who visits the malicious site in their browser.
The first defense against CSRF attacks is to ensure that GET requests (and other safe methods, as defined by RFC 7231) are side effect free. Requests via unsafe methods, such as POST, PUT, and DELETE, can then be protected by this plugin.
This plugin has been inspired by the CSRF protection of the Django web framework.
For general usage and to protect any unsafe action, simply add the plugin to your application.
To ignore an action from CSRF protection, add :CSRFIgnore
to the attributes.
If you have optionally ignored complete namespaces from the CSRF protection, you can require the protection for single namespace members by adding :CSRFRequire
to the attributes.
In your Cutelee template you should then use the {% c_csrf_token %}
tag in your forms to add a hidden input field that contains the CSRF protection token.
You can optionally get the token by using CSRFProtection::getToken() static function if you want to add it to the stash or want to use it elsewhere. For example, if you don't have a form on your site but want to use the token for an AJAX request and want to add it therefore into a meta tag or something like that.
If the CSRF protection check fails, the return code will be set to 403 - Forbidden and an error message will be set to the stash key defined by setErrorMsgStashKey(). You can set a default action the application should detach to if the check failed via setDefaultDetachTo(), optionally there is the attribute :CSRFDetachTo
that can be used to define a detach to action per method. When using an action to detach to if the check fails, do not forget to call Context::finalize() to escape the processing chain after that action. If the detach to action is not set or could not be found it will either set the response body to the content set by setGenericErrorMessage() of if that is absent it will generate a generic HTML content containing error information.
If you are using ajax to submit form requests or if you use AJAX without a HTML form, you have to provide the CSRF token too. If you are using the normal way by setting a cookie, you can read the CSRF token from that cookie. If you use the session to store the token, you have to include the token somewhere into the DOM tree from where you can read it. You can then add the extracted token to the POST data of every POST request or you can can set a custom X-CSRFToken header to the value of the CSRF token. The latter method is often easier, because many JavaScript frameworks provide hooks that allow headers to be set on every request.
On every request, a secret token is set that is stored in a cookie or in the user session and has to be send back to the application when performing actions on unsafe methods like POST. The token stored in the cookie or in the session is salted with another random value. The same secret with a different salt has then to be sent to the application either via a hidden form field or via a HTTP request header.
To get the form field you can use the {% c_csrf_token %}
tag in your Cutelee templates. If you are not using Cutelee or if you do not use a form but AJAX, you can use CSRFProtection::getToken() to place the token somewhere in your DOM tree so that you can read it with JavaScript.
Subdomains within a site will be able to set cookies on the client for the whole domain. By setting the cookie and using a corresponding token, subdomains will be able to circumvent the CSRF protection. The only way to avoid this is to ensure that subdomains are controlled by trusted users (or, are at least unable to set cookies). Note that even without CSRF, there are other vulnerabilities, such as session fixation, that make giving subdomains to untrusted parties a bad idea, and these vulnerabilities cannot easily be fixed with current browsers.
There are some options you can set in your application configuration file in the Cutelyst_CSRFProtection_Plugin
section. You can override the defaults by setting a QVariantMap with selected default values to the constructor.
Type: string
Default: 1 year
The expiration time of the cookie. The value will be parsed by Utils::durationFromString(), so you can use one of the supported human readable time spans.
The reason for setting a long-lived expiration time is to avoid problems in the case of a user closing a browser or bookmarking a page and then loading that page from a browser cache. Without persistent cookies, the form submission would fail in this case.
Some browsers (specifically Internet Explorer) can disallow the use of persistent cookies or can have the indexes to the cookie jar corrupted on disk, thereby causing CSRF protection checks to (sometimes intermittently) fail. Change this setting to 0
to use session-based CSRF cookies, which keep the cookies in-memory instead of on persistent storage.
Type: string
Default: empty
The domain to be used when setting the CSRF cookie. This can be useful for easily allowing cross-subdomain requests to be excluded from the normal cross site request forgery protection. It should be set to a string such as ".example.com" to allow a POST request from a form on one subdomain to be accepted by a view served from another subdomain.
Please note that the presence of this setting does not imply that the CSRF protection is safe from cross-subdomain attacks by default - please see the limitations section.
Type: bool
Default: false
Whether to use a secure cookie for the CSRF cookie. If this is set to true
, the cookie will be marked as secure, which means browsers may ensure that the cookie is only sent with an HTTPS connection.
Type: string
Default: strict
Acceptable values: default,none,lax,strict
Defines the SameSite attribute of the CSRF cookie. See MDN to learn more about SameSite cookies. See also QNetworkCookie::SameSite. This configuration key is available since Cutelyst 3.8.0.
Type: string
Default: empty
A comma separated list of hosts which are trusted origins for unsafe requests (e.g. POST). For a secure unsafe request, the CSRF protection requires that the request have a Referer header that matches the origin present in the Host header. This prevents, for example, a POST request from subdomain.example.com
from succeeding against api.example.com
. If you need cross-origin unsafe requests over HTTPS, continuing the example, add "subdomain.example.com"
to this list. The setting also supports subdomains, so you could add ".example.com"
, for example, to allow access from all subdomains of example.com
.
Type: bool
Default: false
If this is set to true
, the log output for failed checks will contain the IP address of the remote client.
This plugin is not enabled by default. Use -DPLUGIN_CSRFPROTECTION:BOOL=ON
for your cmake configuration. To link it to your application use Cutelyst::CSRFProtection
.
Definition at line 233 of file csrfprotection.h.
|
overrideprotectedvirtual |
Reimplement this if you need to connect to the signals emitted from Cutelyst::Application.
Reimplemented from Cutelyst::Plugin.
Definition at line 69 of file csrfprotection.cpp.
References Cutelyst::Application::beforeDispatch(), Qt::CaseInsensitive, QString::compare(), Cutelyst::Engine::config(), QObject::connect(), Cutelyst::Utils::durationFromString(), Cutelyst::Application::engine(), Cutelyst::Application::loadTranslations(), Cutelyst::Application::plugin(), Cutelyst::Application::postForked(), Qt::SkipEmptyParts, QString::split(), and QList::value().