Add Content Security Policy

This commit is contained in:
Bubka 2024-11-17 20:39:27 +01:00
parent 06ad8f5cd0
commit ce1692eaf4
6 changed files with 44 additions and 2 deletions

View File

@ -274,6 +274,14 @@ TRUSTED_PROXIES=null
PROXY_FOR_OUTGOING_REQUESTS=null PROXY_FOR_OUTGOING_REQUESTS=null
# Set this to true to enable Content-Security-Policy (CSP).
# CSP helps to prevent or minimize the risk of certain types of security threats.
# This is mainly used as a defense against cross-site scripting (XSS) attacks, in which
# an attacker is able to inject malicious code into the web app
CONTENT_SECURITY_POLICY=true
# Leave the following configuration vars as is. # Leave the following configuration vars as is.
# Unless you like to tinker and know what you're doing. # Unless you like to tinker and know what you're doing.

View File

@ -6,6 +6,7 @@
use App\Facades\Settings; use App\Facades\Settings;
use Illuminate\Support\Facades\App; use Illuminate\Support\Facades\App;
use Illuminate\Support\Facades\Auth; use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Vite;
class SinglePageController extends Controller class SinglePageController extends Controller
{ {
@ -32,6 +33,7 @@ public function index()
$installDocUrl = config('2fauth.installDocUrl'); $installDocUrl = config('2fauth.installDocUrl');
$ssoDocUrl = config('2fauth.ssoDocUrl'); $ssoDocUrl = config('2fauth.ssoDocUrl');
$exportSchemaUrl = config('2fauth.exportSchemaUrl'); $exportSchemaUrl = config('2fauth.exportSchemaUrl');
$cspNonce = Vite::cspNonce();
// if (Auth::user()->preferences) // if (Auth::user()->preferences)
@ -57,6 +59,7 @@ public function index()
'isTestingApp' => $isTestingApp, 'isTestingApp' => $isTestingApp,
'lang' => $lang, 'lang' => $lang,
'locales' => $locales, 'locales' => $locales,
'cspNonce' => $cspNonce,
]); ]);
} }
} }

View File

@ -0,0 +1,29 @@
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Vite;
use Symfony\Component\HttpFoundation\Response;
class AddContentSecurityPolicyHeaders
{
/**
* Handle an incoming request.
*
* @param \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response) $next
*/
public function handle(Request $request, Closure $next) : Response
{
if (config('2fauth.config.contentSecurityPolicy')) {
Vite::useCspNonce();
return $next($request)->withHeaders([
'Content-Security-Policy' => "script-src 'nonce-" . Vite::cspNonce() . "';style-src 'self' 'unsafe-inline';connect-src 'self';img-src 'self' data:;object-src 'none';base-uri 'none';",
]);
}
return $next($request);
}
}

View File

@ -31,6 +31,7 @@
'proxyLogoutUrl' => env('PROXY_LOGOUT_URL', null), 'proxyLogoutUrl' => env('PROXY_LOGOUT_URL', null),
'appSubdirectory' => env('APP_SUBDIRECTORY', ''), 'appSubdirectory' => env('APP_SUBDIRECTORY', ''),
'authLogRetentionTime' => envUnlessEmpty('AUTHENTICATION_LOG_RETENTION', 365), 'authLogRetentionTime' => envUnlessEmpty('AUTHENTICATION_LOG_RETENTION', 365),
'contentSecurityPolicy' => envUnlessEmpty('CONTENT_SECURITY_POLICY', true),
], ],
/* /*

View File

@ -22,7 +22,7 @@
<div id="app"> <div id="app">
<app></app> <app></app>
</div> </div>
<script type="text/javascript"> <script type="text/javascript" nonce="{{ $cspNonce }}">
var appSettings = {!! $appSettings !!}; var appSettings = {!! $appSettings !!};
var appConfig = {!! $appConfig !!}; var appConfig = {!! $appConfig !!};
var urls = {!! $urls !!}; var urls = {!! $urls !!};

View File

@ -14,6 +14,7 @@
use App\Http\Controllers\Auth\WebAuthnRegisterController; use App\Http\Controllers\Auth\WebAuthnRegisterController;
use App\Http\Controllers\SinglePageController; use App\Http\Controllers\SinglePageController;
use App\Http\Controllers\SystemController; use App\Http\Controllers\SystemController;
use App\Http\Middleware\AddContentSecurityPolicyHeaders;
use App\Http\Middleware\CustomCreateFreshApiToken; use App\Http\Middleware\CustomCreateFreshApiToken;
use App\Http\Middleware\SetLanguage; use App\Http\Middleware\SetLanguage;
use Illuminate\Routing\Middleware\SubstituteBindings; use Illuminate\Routing\Middleware\SubstituteBindings;
@ -117,4 +118,4 @@
/** /**
* Route for the main landing view * Route for the main landing view
*/ */
Route::get('/{any}', [SinglePageController::class, 'index'])->where('any', '.*')->name('landing'); Route::get('/{any}', [SinglePageController::class, 'index'])->where('any', '.*')->name('landing')->middleware(AddContentSecurityPolicyHeaders::class);