Dzisiaj kolejny, na razie ostatni z serii, artykuł dotyczący zabezpieczenia poprzez CSP. W czasie powstawania aplikacji webowej, gdy zespół programistyczny jest mnogi oraz poziom zrozumienia tematyki CSP zróżnicowany warto we wstępnej fazie wdrożyć CSP w trybie raportowania. Inną sytuacją, która może wiązać się z użyciem trybu raportowania jest dodawanie CSP do już prężnie działającego serwisu. Tak czy inaczej, tryb ten przydaje się. Czy zmienia to coś w technice deklarowania dyrektyw? Nie, zmienia się wyłącznie nazwa pola nagłówka z Content-Security-Policy na Content-Security-Policy-Report-Only.

Poniżej prezentuję jeden przykład raportowania. Tryb Report-Only powoduje dopuszczenie wszystkich zasobów, ale każde naruszenie jest raportowane na wskazany w dyrektywie report-uri adres www.

Brzmi fajnie, bo restrykcje nie będą miały charakteru trwałego, a jednocześnie zbieramy informacje czy i które dyrektywy z jakimi konkretnymi źródłami powinniśmy włączyć, by przełączenie z trybu raportowania w tryb właściwy (raportowanie może być włączone również w trybie właściwym) odbyło się bezboleśnie.

Pamiętajcie, że ustawienie nagłówka Content-Security-Policy Content-Security-Policy-Report-Onlmoże powodować zignorowanie tego drugiego (chyba że w drugim nagłówku dodamy dyrektywę report-only). To jednak należy empirycznie sprawdzić w aktualnie obsługiwanych przeglądarkach.

Rozwiązaniem tej sytuacji, gdy chcemy mieć zarówno raport, jak i blokować zasoby jest uwzględnienie dyrektywy report-uri w nagłówku pierwszym (Content-Security-Policy) – dyrektywa ta jest dozwolona w obu!

Kod przykładu:

<!DOCTYPE html>
<html>
 <head>
 <meta charset="UTF-8">
 <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
 
 <title>Project 1</title>

 <link href='https://fonts.googleapis.com/css?family=Lato:100' rel='stylesheet' type='text/css'>
 <link href='style.css' rel='stylesheet' type='text/css'>

 <script src="https://code.jquery.com/jquery-2.2.4.min.js" integrity="sha256-BbhdlvQf/xTY9gja0Dq3HiwQF8LaCRTXxZKRutelT44=" crossorigin="anonymous"></script>
 
 <script>$.get('http://localhost/version', function(data) { $('.title>span').text(' '+data); });</script>
 </head>
 <body>
 <div class="container">
 <div class="content">
 <div class="title">Laravel<span></span> - brodząc w chmurach</div>
 </div>
 </div>
 </body>
</html>

Mamy tutaj ładowanie zewnętrznych i wewnętrznych stylów, zewnętrznej biblioteki JavaScript, a także wewnętrznego skryptu. Przy okazji ładowania zewnętrznego stylu jest wysyłane żądanie po zewnętrzny zasób czcionki. Tyle z omówienia aktualnej sytuacji.

Plik routingu, gdzie ustalam nagłówek CSP wygląda następująco:

Route::get('/', function () {
 header("Content-Security-Policy-Report-Only: style-src 'self'; script-src 'self'; report-uri http://localhost/csp;");
 
 return view('welcome');
});

Route::get('/version', function() {
 return '5.2.23'; 
});

Route::post('/form', function() { return 'Dziękuję'; });

Route::post('/csp', function() { Log::error(Request::json()->all()); });

 

Strona zostaje wyrenderowana bez obostrzeń, ale restrykcje powodują przesłanie raportu po adres: http://localhost/csp

 

Rezultat:

Tryb raportowania

Tryb raportowania

 

Przesłane raporty:

[2016-06-07 16:55:01] local.ERROR: array (
 'csp-report' => 
 array (
 'document-uri' => 'http://localhost/',
 'referrer' => '',
 'violated-directive' => 'script-src \'self\'',
 'effective-directive' => 'script-src',
 'original-policy' => 'style-src \'self\'; script-src \'self\'; report-uri http://localhost/csp;',
 'blocked-uri' => 'eval',
 'status-code' => 200,
 ),
) 
[2016-06-07 16:55:01] local.ERROR: array (
 'csp-report' => 
 array (
 'document-uri' => 'http://localhost/',
 'referrer' => '',
 'violated-directive' => 'style-src \'self\'',
 'effective-directive' => 'style-src',
 'original-policy' => 'style-src \'self\'; script-src \'self\'; report-uri http://localhost/csp;',
 'blocked-uri' => 'https://fonts.googleapis.com',
 'status-code' => 200,
 ),
) 
[2016-06-07 16:55:01] local.ERROR: array (
 'csp-report' => 
 array (
 'document-uri' => 'http://localhost/',
 'referrer' => '',
 'violated-directive' => 'script-src \'self\'',
 'effective-directive' => 'script-src',
 'original-policy' => 'style-src \'self\'; script-src \'self\'; report-uri http://localhost/csp;',
 'blocked-uri' => 'https://code.jquery.com',
 'status-code' => 200,
 ),
) 
[2016-06-07 16:55:01] local.ERROR: array (
 'csp-report' => 
 array (
 'document-uri' => 'http://localhost/',
 'referrer' => '',
 'violated-directive' => 'script-src \'self\'',
 'effective-directive' => 'script-src',
 'original-policy' => 'style-src \'self\'; script-src \'self\'; report-uri http://localhost/csp;',
 'blocked-uri' => 'inline',
 'status-code' => 200,
 ),
)

 

Pierwszy mówi o funkcji eval (odpowiada za to włączona wtyczka Violentmonkey), drugi o zewnętrznym arkuszu stylów, trzeci o zewnętrznej bibliotece JS, wreszcie czwarty o wewnętrznym skrypcie JS. Wszystko jak na tacy, wystarczy dobrze zinterpretować.

Teraz tylko pokażę, jak renderuje się strona, gdy przejdziemy z trybu raportowania w tryb właściwy. Pozostawiam report-uri, aby zobaczyć co zostało zablokowane.

Nagłówek:

header("Content-Security-Policy: style-src 'self'; script-src 'self'; report-uri http://localhost/csp;");

Rezultat:

Tryb właściwy

Tryb właściwy

Już konsola deweloperska mówi nam co zostało zablokowane, a ja tylko potwierdzę, że raport, który spłynął na wskazany adres był identyczny, jak ten przedstawiony wcześniej.

 

Dziękuję za uwagę. Poprzednie dwa artykuły dotyczące CSP znajdziecie pod wskazanymi adresami:

CSP – sposób na XSS, Clickjacking, CSS-Injection i inne

CSP – przykłady

 

Pozdrawiam!