Skip to content

Commit 6c47c5c

Browse files
committed
init
1 parent 43b21e1 commit 6c47c5c

File tree

12 files changed

+287
-0
lines changed

12 files changed

+287
-0
lines changed

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,7 @@
22
.env.*.php
33
.env.php
44
.env
5+
/vendor
6+
composer.phar
7+
composer.lock
8+
.DS_Store

composer.json

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
{
2+
"name": "paramonovav/laravel4-header-csp",
3+
"description": "Provides support for enforcing Content Security Policy with headers in Laravel 4 responses.",
4+
"keywords": ["laravel", "laravel 4", "header", "response", "content security policy", "xss protection", "csp"],
5+
"license": "MIT",
6+
"homepage": "https://github.com/paramonovav/laravel4-header-csp",
7+
"authors": [
8+
{
9+
"name": "Anton Paramonov",
10+
"email": "paramonovav@gmail.com",
11+
"homepage": "https://github.com/paramonovav",
12+
"role": "Developer"
13+
}
14+
],
15+
"require": {
16+
"php": ">=5.4.0",
17+
"illuminate/support": "4.2.*"
18+
},
19+
"autoload": {
20+
"classmap": [
21+
"src/migrations"
22+
],
23+
"psr-0": {
24+
"Paramonovav\\Laravel4HeaderCsp\\": "src/"
25+
}
26+
},
27+
"minimum-stability": "stable"
28+
}

phpunit.xml

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<phpunit backupGlobals="false"
3+
backupStaticAttributes="false"
4+
bootstrap="vendor/autoload.php"
5+
colors="true"
6+
convertErrorsToExceptions="true"
7+
convertNoticesToExceptions="true"
8+
convertWarningsToExceptions="true"
9+
processIsolation="false"
10+
stopOnFailure="false"
11+
syntaxCheck="false"
12+
>
13+
<testsuites>
14+
<testsuite name="Package Test Suite">
15+
<directory suffix=".php">./tests/</directory>
16+
</testsuite>
17+
</testsuites>
18+
</phpunit>

public/.gitkeep

Whitespace-only changes.
Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
<?php namespace Paramonovav\Laravel4HeaderCsp;
2+
3+
use Illuminate\Support\Facades\Config;
4+
use Illuminate\Support\ServiceProvider;
5+
6+
class Laravel4HeaderCspServiceProvider extends ServiceProvider {
7+
8+
/**
9+
* Indicates if loading of the provider is deferred.
10+
*
11+
* @var bool
12+
*/
13+
protected $defer = false;
14+
15+
/**
16+
* Bootstrap the application events.
17+
*
18+
* @return void
19+
*/
20+
public function boot()
21+
{
22+
$this->package('paramonovav/laravel4-header-csp');
23+
24+
$this->app['router']-> post(
25+
Config::get('laravel4-header-csp::report-uri-route-uri', 'content-security-policy-report'),
26+
array(
27+
'as' => Config::get('laravel4-header-csp::report-uri-route-name', 'header-csp-report'),
28+
function(){
29+
30+
$post_data = file_get_contents('php://input');
31+
32+
if (empty($post_data))
33+
{
34+
return;
35+
}
36+
37+
$report_folder_path = storage_path().'/logs/content-security-policy-report';
38+
39+
if (!is_dir($report_folder_path))
40+
{
41+
mkdir($report_folder_path, 0777, TRUE);
42+
}
43+
44+
file_put_contents($report_folder_path.'/'.date('Y-m-d').'.log', $post_data."\r\n", FILE_APPEND | LOCK_EX);
45+
}
46+
));
47+
48+
$this->app['router']-> filter(
49+
'response.secure',
50+
function($route, $request, $response, $value = ''){
51+
52+
$profiles = Config::get('laravel4-header-csp::default', 'global');
53+
54+
if (!empty($value))
55+
{
56+
$profiles .= '-'.$value;
57+
}
58+
$profiles = explode('-', $profiles);
59+
$profiles = array_map('trim', $profiles);
60+
61+
$config_profiles = Config::get('laravel4-header-csp::profiles');
62+
63+
if (empty($config_profiles) || empty($profiles))
64+
{
65+
return;
66+
}
67+
68+
$csp = array();
69+
foreach ($profiles as $profile)
70+
{
71+
if (empty($config_profiles[$profile]))
72+
{
73+
continue;
74+
}
75+
76+
$config_profile = $config_profiles[$profile];
77+
78+
if (!empty($config_profile['csp']) && is_array($config_profile['csp']))
79+
{
80+
foreach ($config_profile['csp'] as $key => $value)
81+
{
82+
if (!is_array($value))
83+
{
84+
if ('report-uri' == $key)
85+
{
86+
$value = route($value);
87+
}
88+
$value = array($value);
89+
}
90+
91+
foreach ($value as $val)
92+
{
93+
$csp[$key][$val] = $val;
94+
}
95+
}
96+
}
97+
98+
if (!empty($config_profile['custom']) && is_array($config_profile['custom']))
99+
{
100+
foreach ($config_profile['custom'] as $key => $value)
101+
{
102+
$response-> headers->set($key, $value);
103+
}
104+
}
105+
}
106+
107+
foreach ($csp as $key => $vals)
108+
{
109+
if (isset($vals["'none'"]) && count($vals) > 1)
110+
{
111+
unset($vals["'none'"]);
112+
}
113+
114+
$csp_parts[$key] = $key.' '.implode(' ', $vals);
115+
}
116+
117+
$csp_line = implode('; ', $csp_parts).';';
118+
119+
if (FALSE === Config::get('laravel4-header-csp::csp-report-only', FALSE))
120+
{
121+
$response-> headers->set('X-Webkit-CSP', $csp_line);
122+
$response-> headers->set('X-Content-Security-Policy', $csp_line);
123+
$response-> headers->set('Content-Security-Policy', $csp_line);
124+
}
125+
else
126+
{
127+
$response-> headers->set('X-Content-Security-Policy-Report-Only', $csp_line);
128+
$response-> headers->set('Content-Security-Policy-Report-Only', $csp_line);
129+
}
130+
}
131+
);
132+
}
133+
134+
/**
135+
* Register the service provider.
136+
*
137+
* @return void
138+
*/
139+
public function register()
140+
{
141+
//
142+
}
143+
144+
/**
145+
* Get the services provided by the provider.
146+
*
147+
* @return array
148+
*/
149+
public function provides()
150+
{
151+
return array();
152+
}
153+
154+
}

src/config/.gitkeep

Whitespace-only changes.

src/config/config.php

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
<?php
2+
/*
3+
*
4+
* http://content-security-policy.com/
5+
* http://www.sitepoint.com/improving-web-security-with-the-content-security-policy/
6+
* https://www.owasp.org/index.php/List_of_useful_HTTP_headers
7+
*
8+
*/
9+
10+
return array(
11+
12+
'report-uri-route-uri' => 'content-security-policy-report',
13+
'report-uri-route-name' => 'header-csp-report',
14+
15+
'default' => 'global',
16+
17+
'csp-report-only' => FALSE,
18+
19+
'profiles' => array(
20+
'global' => array(
21+
'csp' => array(
22+
'default-src' => "'none'",
23+
'img-src' => "'self'",
24+
'script-src' => "'self'",
25+
'style-src' => "'self'",
26+
'font-src' => "'self'",
27+
'object-src' => "'none'",
28+
'media-src' => "'none'",
29+
'frame-src' => "'none'",
30+
'connect-src' => "'self'",
31+
//'report-uri' => 'header-csp-report',
32+
//'sandbox' => 'allow-forms allow-same-origin allow-scripts allow-top-navigation',
33+
),
34+
'custom' => array(
35+
'x-frame-options' => 'DENY',
36+
'x-content-type-options' => 'nosniff',
37+
'x-xss-protection' => '1; mode=block'
38+
)
39+
),
40+
'google' => array(
41+
'csp' => array(
42+
'script-src' => array(
43+
"'unsafe-inline'",
44+
"'unsafe-eval'",
45+
'*.google.com',
46+
'*.gstatic.com',
47+
'*.google-analytics.com',
48+
'stats.g.doubleclick.net'
49+
),
50+
'style-src' => array(
51+
"'unsafe-inline'",
52+
'*.googleapis.com'
53+
),
54+
'font-src' => array(
55+
'*.gstatic.com',
56+
'*.googleapis.com',
57+
'data:'
58+
),
59+
'img-src' => array(
60+
'*.google-analytics.com',
61+
'data:'
62+
),
63+
'frame-src' => array(
64+
'*.google.com'
65+
),
66+
)
67+
),
68+
'gravatar' => array(
69+
'csp' => array(
70+
'img-src' => array(
71+
'*.gravatar.com'
72+
)
73+
)
74+
),
75+
'flickr' => array(
76+
'csp' => array(
77+
'img-src' => array(
78+
'*.staticflickr.com'
79+
)
80+
)
81+
)
82+
)
83+
);

src/controllers/.gitkeep

Whitespace-only changes.

src/lang/.gitkeep

Whitespace-only changes.

src/migrations/.gitkeep

Whitespace-only changes.

0 commit comments

Comments
 (0)