| @@ -53,9 +53,14 @@ | ||
| 53 | 53 | * Apply security headers to .htaccess |
| 54 | 54 | * |
| 55 | 55 | * @return bool|WP_Error |
| 56 | 56 | */ |
| 57 | - public function apply_rules() { | |
| 57 | + /** | |
| 58 | + * @param bool $automatic True when Vigilant is refreshing the block by | |
| 59 | + * itself rather than because someone pressed Save. | |
| 60 | + * See Vigilante_Htaccess_Manager::add_block(). | |
| 61 | + */ | |
| 62 | + public function apply_rules( $automatic = false ) { | |
| 58 | 63 | require_once VIGILANTE_INCLUDES_DIR . 'class-htaccess-manager.php'; |
| 59 | 64 | |
| 60 | 65 | $manager = Vigilante_Htaccess_Manager::get_instance(); |
| 61 | 66 | |
| @@ -68,9 +73,9 @@ | ||
| 68 | 73 | } |
| 69 | 74 | |
| 70 | 75 | $rules = $this->generate_rules_content(); |
| 71 | 76 | |
| 72 | - $result = $manager->add_block( self::MARKER_START, self::MARKER_END, $rules, 'top' ); | |
| 77 | + $result = $manager->add_block( self::MARKER_START, self::MARKER_END, $rules, 'top', $automatic ); | |
| 73 | 78 | |
| 74 | 79 | if ( true === $result ) { |
| 75 | 80 | /** This action is documented in class-wpconfig-security.php */ |
| 76 | 81 | do_action( 'vigilante_critical_file_written', '.htaccess' ); |
| @@ -304,8 +309,28 @@ | ||
| 304 | 309 | return str_replace( array( '"', "\r", "\n" ), '', (string) $value ); |
| 305 | 310 | } |
| 306 | 311 | |
| 307 | 312 | /** |
| 313 | + * Whether the site address is an https:// one | |
| 314 | + * | |
| 315 | + * Read from the stored address and from nothing else. is_ssl() is false | |
| 316 | + * behind a proxy that terminates TLS and says nothing in a cron run or from | |
| 317 | + * WP-CLI, and home_url() takes its scheme from is_ssl() when the request is | |
| 318 | + * secure (wp-includes/link-template.php:3471-3477 in 7.1.2), so the same site | |
| 319 | + * would write different rules from an https request and from a scheduled | |
| 320 | + * task. Vigilante_Htaccess_Recovery and File | |
| 321 | + * Integrity compare the file with what this class would write now, so the | |
| 322 | + * answer has to be the same wherever it is asked. | |
| 323 | + * | |
| 324 | + * @since 3.0.2 | |
| 325 | + * | |
| 326 | + * @return bool | |
| 327 | + */ | |
| 328 | + private function site_address_is_https() { | |
| 329 | + return 0 === strpos( (string) get_option( 'home' ), 'https://' ); | |
| 330 | + } | |
| 331 | + | |
| 332 | + /** | |
| 308 | 333 | * Generate rules content (without markers) |
| 309 | 334 | * |
| 310 | 335 | * Public since 2.10.0: it is also "what this configuration would write right |
| 311 | 336 | * now", which is what Vigilante_Htaccess_Recovery compares the file against. |
| @@ -409,9 +434,25 @@ | ||
| 409 | 434 | } |
| 410 | 435 | } |
| 411 | 436 | |
| 412 | 437 | if ( ! empty( $csp['directives'] ) && is_array( $csp['directives'] ) ) { |
| 438 | + $site_is_https = $this->site_address_is_https(); | |
| 439 | + | |
| 413 | 440 | foreach ( $csp['directives'] as $directive => $value ) { |
| 441 | + /* | |
| 442 | + * upgrade-insecure-requests tells the browser to ask for every | |
| 443 | + * http:// resource of the page over https. On a site whose | |
| 444 | + * address is http:// nothing answers there, so every | |
| 445 | + * stylesheet, script and image stops loading, and the factory | |
| 446 | + * policy carries it. It is written only when the site address | |
| 447 | + * is https://. The setting itself is left as it is, so the | |
| 448 | + * next rewrite of the block after the address changes writes | |
| 449 | + * it. | |
| 450 | + */ | |
| 451 | + if ( 'upgrade-insecure-requests' === strtolower( (string) $directive ) && ! $site_is_https ) { | |
| 452 | + continue; | |
| 453 | + } | |
| 454 | + | |
| 414 | 455 | // Override frame-ancestors with synchronized value if X-Frame-Options is set |
| 415 | 456 | if ( 'frame-ancestors' === $directive && ! empty( $frame_ancestors_value ) ) { |
| 416 | 457 | $directives[] = $directive . ' ' . $frame_ancestors_value; |
| 417 | 458 | } elseif ( true === $value ) { |