mirror of https://github.com/MISP/MISP
new: [security] Content-Security-Policy support
parent
38f785ea63
commit
8a3144f112
|
@ -123,6 +123,9 @@ class AppController extends Controller
|
|||
if (Configure::read('Security.disable_browser_cache')) {
|
||||
$this->response->disableCache();
|
||||
}
|
||||
if (!$this->_isRest()) {
|
||||
$this->__contentSecurityPolicy();
|
||||
}
|
||||
$this->response->header('X-XSS-Protection', '1; mode=block');
|
||||
|
||||
if (!empty($this->params['named']['sql'])) {
|
||||
|
@ -314,11 +317,11 @@ class AppController extends Controller
|
|||
$this->__accessMonitor($user);
|
||||
|
||||
} else {
|
||||
$pre_auth_actions = array('login', 'register', 'getGpgPublicKey');
|
||||
$preAuthActions = array('login', 'register', 'getGpgPublicKey');
|
||||
if (!empty(Configure::read('Security.email_otp_enabled'))) {
|
||||
$pre_auth_actions[] = 'email_otp';
|
||||
$preAuthActions[] = 'email_otp';
|
||||
}
|
||||
if (!$this->_isControllerAction(['users' => $pre_auth_actions])) {
|
||||
if (!$this->_isControllerAction(['users' => $preAuthActions, 'servers' => ['cspReport']])) {
|
||||
if (!$this->request->is('ajax')) {
|
||||
$this->Session->write('pre_login_requested_url', $this->here);
|
||||
}
|
||||
|
@ -685,6 +688,50 @@ class AppController extends Controller
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate Content-Security-Policy HTTP header
|
||||
*/
|
||||
private function __contentSecurityPolicy()
|
||||
{
|
||||
$default = [
|
||||
'default-src' => "'self' data: 'unsafe-inline' 'unsafe-eval'",
|
||||
'style-src' => "'self' 'unsafe-inline'",
|
||||
'object-src' => "'none'",
|
||||
'frame-ancestors' => "'none'",
|
||||
'worker-src' => "'none'",
|
||||
'child-src' => "'none'",
|
||||
'frame-src' => "'none'",
|
||||
'base-uri' => "'self'",
|
||||
'img-src' => "'self' data:",
|
||||
'font-src' => "'self'",
|
||||
'form-action' => "'self'",
|
||||
'connect-src' => "'self'",
|
||||
'manifest-src' => "'none'",
|
||||
'report-uri' => '/servers/cspReport',
|
||||
];
|
||||
if (env('HTTPS')) {
|
||||
$default['upgrade-insecure-requests'] = null;
|
||||
}
|
||||
$custom = Configure::read('Security.csp');
|
||||
if ($custom === false) {
|
||||
return;
|
||||
}
|
||||
if (is_array($custom)) {
|
||||
$default = $default + $custom;
|
||||
}
|
||||
$header = [];
|
||||
foreach ($default as $key => $value) {
|
||||
if ($value !== false) {
|
||||
if ($value === null) {
|
||||
$header[] = $key;
|
||||
} else {
|
||||
$header[] = "$key $value";
|
||||
}
|
||||
}
|
||||
}
|
||||
$this->response->header('Content-Security-Policy', implode('; ', $header));
|
||||
}
|
||||
|
||||
private function __rateLimitCheck()
|
||||
{
|
||||
$info = array();
|
||||
|
|
|
@ -533,6 +533,7 @@ class ACLComponent extends Component
|
|||
'uploadFile' => array(),
|
||||
'viewDeprecatedFunctionUse' => array(),
|
||||
'killAllWorkers' => ['perm_site_admin'],
|
||||
'cspReport' => ['*'],
|
||||
),
|
||||
'shadowAttributes' => array(
|
||||
'accept' => array('perm_add'),
|
||||
|
|
|
@ -35,8 +35,11 @@ class ServersController extends AppController
|
|||
|
||||
public function beforeFilter()
|
||||
{
|
||||
$this->Auth->allow(['cspReport']); // cspReport must work without authentication
|
||||
|
||||
parent::beforeFilter();
|
||||
$this->Security->unlockedActions[] = 'getApiInfo';
|
||||
$this->Security->unlockedActions[] = 'cspReport';
|
||||
// permit reuse of CSRF tokens on some pages.
|
||||
switch ($this->request->params['action']) {
|
||||
case 'push':
|
||||
|
@ -2419,6 +2422,27 @@ misp.direct_call(relative_path, body)
|
|||
}
|
||||
}
|
||||
|
||||
public function cspReport()
|
||||
{
|
||||
if (!$this->request->is('post')) {
|
||||
throw new MethodNotAllowedException('This action expects a POST request.');
|
||||
}
|
||||
|
||||
$report = $this->Server->jsonDecode($this->request->input());
|
||||
if (!isset($report['csp-report'])) {
|
||||
throw new RuntimeException("Invalid report");
|
||||
}
|
||||
|
||||
$message = 'CSP reported violation';
|
||||
$ipHeader = Configure::read('MISP.log_client_ip_header') ?: 'REMOTE_ADDR';
|
||||
if (isset($_SERVER[$ipHeader])) {
|
||||
$message .= ' from IP ' . $_SERVER[$ipHeader];
|
||||
}
|
||||
$this->log("$message: " . json_encode($report['csp-report'], JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES));
|
||||
|
||||
return new CakeResponse(['statusCodes' => 204]);
|
||||
}
|
||||
|
||||
public function viewDeprecatedFunctionUse()
|
||||
{
|
||||
$data = $this->Deprecation->getDeprecatedAccessList($this->Server);
|
||||
|
|
Loading…
Reference in New Issue