add('default-src', "'none'"); $csp->add('style-src', "'self'"); $csp->emit(); */ class ContentSecurityPolicy { #private $csp=array(); public $csp=array(); # for debugging just to track which extension/plugins wants to add csp-entries #public $history=array(); function __construct(){ $this->csp=array(); } /** * get the constructed concatenated value string part for the http Content-Security-Header * * TODO: maybe some syntax checks and logical verification when building the string. * * MAYBE: add optional parameter to get only a part like $csp->get('img-src') * Alternatively the user can just access the currently public $csp->csp['img-src'] to get that values as array. * */ public function get(){ $out = ''; foreach ( $this->csp as $key => $values ) { $out .= $key.' '.implode(' ', $values).'; '; } $out = trim($out, '; '); return $out; } /** * adds a value to a csp type * * @param type * @param value single values for a type * * examples: * $csp->add('default-src', "'self'"); # surrounding double quotes "" used to pass the single quotes * $csp->add('img-src', 'mycdn.example.com'); # single quoted string ok */ public function add($type, $value){ if( isset($this->csp[$type]) ) { if( !in_array( $value, $this->csp[$type] ) ) { $this->csp[$type][] = $value; } } else { $this->csp[$type] = array($value); } #$this->history[]=debug_backtrace()[1]; } /** * sends the Content-Security-Policy http headers */ public function emit() { $string=$this->get(); header('Content-Security-Policy: '.$string ); # some older web browsers used vendor prefixes before csp got w3c recommendation. # maybe use useragent string to detect who should receive this outdated vendor csp strings. # for IE 10-11 header('X-Content-Security-Policy: '.$string ); # for Chrome 15-24, Safari 5.1-6, .. header('X-WebKit-CSP: '.$string ); } /** * Put the csp as meta-tags in the HTML-head section. * * Q: What is the benefit of adding csp as meta tags too? * * I don't know, maybe this way the csp persist if someone saves a page to his harddrive for instance or if bad web proxies rip off csp http headers? * Do webbrowsers store the CSP-HTTP header to the HTML-head as metatags automatically if there is no related metatag in the original page? Mhh.. */ public function getMeta() { $string=$this->get(); $out= ''; # enable if you think it is necessary for your customers. # older web browsers used vendor prefixes before csp2 got a w3c recommendation standard.. # maybe use useragent string to detect who should receive this outdated vendor csp strings. # for IE 10-11 $out.= ''; # for Chrome 15-24, Safari 5.1-6, .. $out.= ''; return $out; } }