Browse Source

Add option to control CSRF protection

Some users are using WebUI with simple port-forwarding from their router,
providing an option to control the protection will save them from setting up an
non-trival web proxy.
Closes #7274.
adaptive-webui-19844
Chocobo1 6 years ago
parent
commit
9eeef0be97
No known key found for this signature in database
GPG Key ID: 210D9C873253A68C
  1. 10
      src/base/preferences.cpp
  2. 2
      src/base/preferences.h
  3. 3
      src/gui/optionsdlg.cpp
  4. 7
      src/gui/optionsdlg.ui
  5. 3
      src/webui/api/appcontroller.cpp
  6. 7
      src/webui/webapplication.cpp
  7. 1
      src/webui/webapplication.h
  8. 6
      src/webui/www/private/preferences_content.html

10
src/base/preferences.cpp

@ -586,6 +586,16 @@ void Preferences::setWebUiClickjackingProtectionEnabled(bool enabled)
setValue("Preferences/WebUI/ClickjackingProtection", enabled); setValue("Preferences/WebUI/ClickjackingProtection", enabled);
} }
bool Preferences::isWebUiCSRFProtectionEnabled() const
{
return value("Preferences/WebUI/CSRFProtection", true).toBool();
}
void Preferences::setWebUiCSRFProtectionEnabled(bool enabled)
{
setValue("Preferences/WebUI/CSRFProtection", enabled);
}
bool Preferences::isWebUiHttpsEnabled() const bool Preferences::isWebUiHttpsEnabled() const
{ {
return value("Preferences/WebUI/HTTPS/Enabled", false).toBool(); return value("Preferences/WebUI/HTTPS/Enabled", false).toBool();

2
src/base/preferences.h

@ -197,6 +197,8 @@ public:
// WebUI security // WebUI security
bool isWebUiClickjackingProtectionEnabled() const; bool isWebUiClickjackingProtectionEnabled() const;
void setWebUiClickjackingProtectionEnabled(bool enabled); void setWebUiClickjackingProtectionEnabled(bool enabled);
bool isWebUiCSRFProtectionEnabled() const;
void setWebUiCSRFProtectionEnabled(bool enabled);
// HTTPS // HTTPS
bool isWebUiHttpsEnabled() const; bool isWebUiHttpsEnabled() const;

3
src/gui/optionsdlg.cpp

@ -379,6 +379,7 @@ OptionsDialog::OptionsDialog(QWidget *parent)
connect(m_ui->checkBypassAuthSubnetWhitelist, &QAbstractButton::toggled, this, &ThisType::enableApplyButton); connect(m_ui->checkBypassAuthSubnetWhitelist, &QAbstractButton::toggled, this, &ThisType::enableApplyButton);
connect(m_ui->checkBypassAuthSubnetWhitelist, &QAbstractButton::toggled, m_ui->IPSubnetWhitelistButton, &QPushButton::setEnabled); connect(m_ui->checkBypassAuthSubnetWhitelist, &QAbstractButton::toggled, m_ui->IPSubnetWhitelistButton, &QPushButton::setEnabled);
connect(m_ui->checkClickjacking, &QCheckBox::toggled, this, &ThisType::enableApplyButton); connect(m_ui->checkClickjacking, &QCheckBox::toggled, this, &ThisType::enableApplyButton);
connect(m_ui->checkCSRFProtection, &QCheckBox::toggled, this, &ThisType::enableApplyButton);
connect(m_ui->checkDynDNS, &QGroupBox::toggled, this, &ThisType::enableApplyButton); connect(m_ui->checkDynDNS, &QGroupBox::toggled, this, &ThisType::enableApplyButton);
connect(m_ui->comboDNSService, qComboBoxCurrentIndexChanged, this, &ThisType::enableApplyButton); connect(m_ui->comboDNSService, qComboBoxCurrentIndexChanged, this, &ThisType::enableApplyButton);
connect(m_ui->domainNameTxt, &QLineEdit::textChanged, this, &ThisType::enableApplyButton); connect(m_ui->domainNameTxt, &QLineEdit::textChanged, this, &ThisType::enableApplyButton);
@ -697,6 +698,7 @@ void OptionsDialog::saveOptions()
pref->setWebUiAuthSubnetWhitelistEnabled(m_ui->checkBypassAuthSubnetWhitelist->isChecked()); pref->setWebUiAuthSubnetWhitelistEnabled(m_ui->checkBypassAuthSubnetWhitelist->isChecked());
// Security // Security
pref->setWebUiClickjackingProtectionEnabled(m_ui->checkClickjacking->isChecked()); pref->setWebUiClickjackingProtectionEnabled(m_ui->checkClickjacking->isChecked());
pref->setWebUiCSRFProtectionEnabled(m_ui->checkCSRFProtection->isChecked());
// DynDNS // DynDNS
pref->setDynDNSEnabled(m_ui->checkDynDNS->isChecked()); pref->setDynDNSEnabled(m_ui->checkDynDNS->isChecked());
pref->setDynDNSService(m_ui->comboDNSService->currentIndex()); pref->setDynDNSService(m_ui->comboDNSService->currentIndex());
@ -1101,6 +1103,7 @@ void OptionsDialog::loadOptions()
// Security // Security
m_ui->checkClickjacking->setChecked(pref->isWebUiClickjackingProtectionEnabled()); m_ui->checkClickjacking->setChecked(pref->isWebUiClickjackingProtectionEnabled());
m_ui->checkCSRFProtection->setChecked(pref->isWebUiCSRFProtectionEnabled());
m_ui->checkDynDNS->setChecked(pref->isDynDNSEnabled()); m_ui->checkDynDNS->setChecked(pref->isDynDNSEnabled());
m_ui->comboDNSService->setCurrentIndex(static_cast<int>(pref->getDynDNSService())); m_ui->comboDNSService->setCurrentIndex(static_cast<int>(pref->getDynDNSService()));

7
src/gui/optionsdlg.ui

@ -3175,6 +3175,13 @@ Use ';' to split multiple entries. Can use wildcard '*'.</string>
</property> </property>
</widget> </widget>
</item> </item>
<item>
<widget class="QCheckBox" name="checkCSRFProtection">
<property name="text">
<string>Enable Cross-Site Request Forgery (CSRF) protection</string>
</property>
</widget>
</item>
<item> <item>
<widget class="QGroupBox" name="checkDynDNS"> <widget class="QGroupBox" name="checkDynDNS">
<property name="title"> <property name="title">

3
src/webui/api/appcontroller.cpp

@ -207,6 +207,7 @@ void AppController::preferencesAction()
data["bypass_auth_subnet_whitelist"] = authSubnetWhitelistStringList.join("\n"); data["bypass_auth_subnet_whitelist"] = authSubnetWhitelistStringList.join("\n");
// Security // Security
data["web_ui_clickjacking_protection_enabled"] = pref->isWebUiClickjackingProtectionEnabled(); data["web_ui_clickjacking_protection_enabled"] = pref->isWebUiClickjackingProtectionEnabled();
data["web_ui_csrf_protection_enabled"] = pref->isWebUiCSRFProtectionEnabled();
// Update my dynamic domain name // Update my dynamic domain name
data["dyndns_enabled"] = pref->isDynDNSEnabled(); data["dyndns_enabled"] = pref->isDynDNSEnabled();
data["dyndns_service"] = pref->getDynDNSService(); data["dyndns_service"] = pref->getDynDNSService();
@ -484,6 +485,8 @@ void AppController::setPreferencesAction()
// Security // Security
if (m.contains("web_ui_clickjacking_protection_enabled")) if (m.contains("web_ui_clickjacking_protection_enabled"))
pref->setWebUiClickjackingProtectionEnabled(m["web_ui_clickjacking_protection_enabled"].toBool()); pref->setWebUiClickjackingProtectionEnabled(m["web_ui_clickjacking_protection_enabled"].toBool());
if (m.contains("web_ui_csrf_protection_enabled"))
pref->setWebUiCSRFProtectionEnabled(m["web_ui_csrf_protection_enabled"].toBool());
// Update my dynamic domain name // Update my dynamic domain name
if (m.contains("dyndns_enabled")) if (m.contains("dyndns_enabled"))
pref->setDynDNSEnabled(m["dyndns_enabled"].toBool()); pref->setDynDNSEnabled(m["dyndns_enabled"].toBool());

7
src/webui/webapplication.cpp

@ -430,6 +430,7 @@ void WebApplication::configure()
} }
m_isClickjackingProtectionEnabled = pref->isWebUiClickjackingProtectionEnabled(); m_isClickjackingProtectionEnabled = pref->isWebUiClickjackingProtectionEnabled();
m_isCSRFProtectionEnabled = pref->isWebUiCSRFProtectionEnabled();
} }
void WebApplication::registerAPIController(const QString &scope, APIController *controller) void WebApplication::registerAPIController(const QString &scope, APIController *controller)
@ -514,9 +515,11 @@ Http::Response WebApplication::processRequest(const Http::Request &request, cons
clear(); clear();
try { try {
// block cross-site requests // block suspicious requests
if (isCrossSiteRequest(m_request) || !validateHostHeader(m_domainList)) if ((m_isCSRFProtectionEnabled && isCrossSiteRequest(m_request))
|| !validateHostHeader(m_domainList)) {
throw UnauthorizedHTTPError(); throw UnauthorizedHTTPError();
}
sessionInitialize(); sessionInitialize();
doProcessRequest(); doProcessRequest();

1
src/webui/webapplication.h

@ -145,4 +145,5 @@ private:
// security related // security related
bool m_isClickjackingProtectionEnabled; bool m_isClickjackingProtectionEnabled;
bool m_isCSRFProtectionEnabled;
}; };

6
src/webui/www/private/preferences_content.html

@ -463,6 +463,10 @@
<input type="checkbox" id="clickjacking_protection_checkbox" /> <input type="checkbox" id="clickjacking_protection_checkbox" />
<label for="clickjacking_protection_checkbox">QBT_TR(Enable clickjacking protection)QBT_TR[CONTEXT=OptionsDialog]</label> <label for="clickjacking_protection_checkbox">QBT_TR(Enable clickjacking protection)QBT_TR[CONTEXT=OptionsDialog]</label>
</div> </div>
<div class="formRow">
<input type="checkbox" id="csrf_protection_checkbox" />
<label for="csrf_protection_checkbox">QBT_TR(Enable Cross-Site Request Forgery (CSRF) protection)QBT_TR[CONTEXT=OptionsDialog]</label>
</div>
</fieldset> </fieldset>
<fieldset class="settings"> <fieldset class="settings">
@ -1029,6 +1033,7 @@
// Security // Security
$('clickjacking_protection_checkbox').setProperty('checked', pref.web_ui_clickjacking_protection_enabled); $('clickjacking_protection_checkbox').setProperty('checked', pref.web_ui_clickjacking_protection_enabled);
$('csrf_protection_checkbox').setProperty('checked', pref.web_ui_csrf_protection_enabled);
// Update my dynamic domain name // Update my dynamic domain name
$('use_dyndns_checkbox').setProperty('checked', pref.dyndns_enabled); $('use_dyndns_checkbox').setProperty('checked', pref.dyndns_enabled);
@ -1322,6 +1327,7 @@
settings.set('bypass_auth_subnet_whitelist', $('bypass_auth_subnet_whitelist_textarea').getProperty('value')); settings.set('bypass_auth_subnet_whitelist', $('bypass_auth_subnet_whitelist_textarea').getProperty('value'));
settings.set('web_ui_clickjacking_protection_enabled', $('clickjacking_protection_checkbox').getProperty('checked')); settings.set('web_ui_clickjacking_protection_enabled', $('clickjacking_protection_checkbox').getProperty('checked'));
settings.set('web_ui_csrf_protection_enabled', $('csrf_protection_checkbox').getProperty('checked'));
// Update my dynamic domain name // Update my dynamic domain name
settings.set('dyndns_enabled', $('use_dyndns_checkbox').getProperty('checked')); settings.set('dyndns_enabled', $('use_dyndns_checkbox').getProperty('checked'));

Loading…
Cancel
Save