161 lines
		
	
	
		
			5.5 KiB
		
	
	
	
		
			PHP
		
	
			
		
		
	
	
			161 lines
		
	
	
		
			5.5 KiB
		
	
	
	
		
			PHP
		
	
| <?php
 | |
| 
 | |
| namespace Tests\Framework\Integration\Security;
 | |
| 
 | |
| use PHPUnit\Framework\TestCase;
 | |
| 
 | |
| require_once dirname(__DIR__, 3) . '/app/includes/security_headers_middleware.php';
 | |
| 
 | |
| class SecurityHeadersTest extends TestCase
 | |
| {
 | |
|     protected function setUp(): void
 | |
|     {
 | |
|         parent::setUp();
 | |
|         unset($_GET['page']);
 | |
|         unset($_SERVER['HTTPS']);
 | |
|         unset($_SERVER['REQUEST_URI']);
 | |
|     }
 | |
| 
 | |
|     public function testBasicSecurityHeaders()
 | |
|     {
 | |
|         // Apply security headers in test mode
 | |
|         $headers = \applySecurityHeaders(true);
 | |
| 
 | |
|         // Check security headers
 | |
|         $this->assertContains('X-Frame-Options: DENY', $headers);
 | |
|         $this->assertContains('X-XSS-Protection: 1; mode=block', $headers);
 | |
|         $this->assertContains('X-Content-Type-Options: nosniff', $headers);
 | |
|         $this->assertContains('Referrer-Policy: strict-origin-when-cross-origin', $headers);
 | |
|     }
 | |
| 
 | |
|     public function testContentSecurityPolicy()
 | |
|     {
 | |
|         // Apply security headers in test mode
 | |
|         $headers = \applySecurityHeaders(true);
 | |
| 
 | |
|         // Get CSP header
 | |
|         $cspHeader = '';
 | |
|         foreach ($headers as $header) {
 | |
|             if (strpos($header, 'Content-Security-Policy:') === 0) {
 | |
|                 $cspHeader = $header;
 | |
|                 break;
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         // Check CSP directives
 | |
|         $this->assertStringContainsString("default-src 'self'", $cspHeader);
 | |
|         $this->assertStringContainsString("script-src 'self' 'unsafe-inline' 'unsafe-eval'", $cspHeader);
 | |
|         $this->assertStringContainsString("style-src 'self' 'unsafe-inline'", $cspHeader);
 | |
|         $this->assertStringContainsString("frame-ancestors 'none'", $cspHeader);
 | |
|         $this->assertStringContainsString("form-action 'self'", $cspHeader);
 | |
|         $this->assertStringContainsString("base-uri 'self'", $cspHeader);
 | |
|     }
 | |
| 
 | |
|     public function testHstsHeader()
 | |
|     {
 | |
|         // Simulate HTTPS
 | |
|         $_SERVER['HTTPS'] = 'on';
 | |
| 
 | |
|         // Apply security headers in test mode
 | |
|         $headers = \applySecurityHeaders(true);
 | |
| 
 | |
|         // Check HSTS header
 | |
|         $this->assertContains(
 | |
|             'Strict-Transport-Security: max-age=31536000; includeSubDomains; preload',
 | |
|             $headers
 | |
|         );
 | |
|     }
 | |
| 
 | |
|     public function testNoHstsHeaderOnHttp()
 | |
|     {
 | |
|         // Apply security headers in test mode
 | |
|         $headers = \applySecurityHeaders(true);
 | |
| 
 | |
|         // Check HSTS header is not present
 | |
|         $hasHsts = false;
 | |
|         foreach ($headers as $header) {
 | |
|             if (strpos($header, 'Strict-Transport-Security:') === 0) {
 | |
|                 $hasHsts = true;
 | |
|                 break;
 | |
|             }
 | |
|         }
 | |
|         $this->assertFalse($hasHsts, 'HSTS header should not be present on HTTP');
 | |
|     }
 | |
| 
 | |
|     public function testCacheControlForSensitivePages()
 | |
|     {
 | |
|         $sensitivePages = ['login', 'register', 'profile', 'security'];
 | |
| 
 | |
|         foreach ($sensitivePages as $page) {
 | |
|             // Set current page
 | |
|             $_GET['page'] = $page;
 | |
| 
 | |
|             // Apply security headers in test mode
 | |
|             $headers = \applySecurityHeaders(true);
 | |
| 
 | |
|             // Check cache control headers
 | |
|             $this->assertContains('Cache-Control: no-store, no-cache, must-revalidate, max-age=0', $headers);
 | |
|             $this->assertContains('Pragma: no-cache', $headers);
 | |
|             $this->assertStringContainsString('Expires:', implode(' ', $headers));
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     public function testNoCacheControlForNonSensitivePages()
 | |
|     {
 | |
|         $_GET['page'] = 'dashboard';
 | |
| 
 | |
|         // Apply security headers in test mode
 | |
|         $headers = \applySecurityHeaders(true);
 | |
| 
 | |
|         // Check cache control headers are not present
 | |
|         $this->assertNotContains('Cache-Control: no-store, no-cache, must-revalidate, max-age=0', $headers);
 | |
|         $this->assertNotContains('Pragma: no-cache', $headers);
 | |
|     }
 | |
| 
 | |
|     public function testPermissionsPolicy()
 | |
|     {
 | |
|         // Apply security headers in test mode
 | |
|         $headers = \applySecurityHeaders(true);
 | |
| 
 | |
|         // Get Permissions-Policy header
 | |
|         $permissionsHeader = '';
 | |
|         foreach ($headers as $header) {
 | |
|             if (strpos($header, 'Permissions-Policy:') === 0) {
 | |
|                 $permissionsHeader = $header;
 | |
|                 break;
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         // Check basic permissions
 | |
|         $this->assertStringContainsString('geolocation=()', $permissionsHeader);
 | |
|         $this->assertStringContainsString('payment=()', $permissionsHeader);
 | |
|         $this->assertStringContainsString('camera=()', $permissionsHeader);
 | |
|         $this->assertStringContainsString('microphone=()', $permissionsHeader);
 | |
|         $this->assertStringContainsString('fullscreen=(self)', $permissionsHeader);
 | |
|         $this->assertStringContainsString('sync-xhr=(self)', $permissionsHeader);
 | |
|     }
 | |
| 
 | |
|     public function testPermissionsPolicyForMediaEnabledPages()
 | |
|     {
 | |
|         $_SERVER['REQUEST_URI'] = '/media/upload';
 | |
| 
 | |
|         // Apply security headers in test mode
 | |
|         $headers = \applySecurityHeaders(true);
 | |
| 
 | |
|         // Get Permissions-Policy header
 | |
|         $permissionsHeader = '';
 | |
|         foreach ($headers as $header) {
 | |
|             if (strpos($header, 'Permissions-Policy:') === 0) {
 | |
|                 $permissionsHeader = $header;
 | |
|                 break;
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         // Check permissions policy header
 | |
|         $this->assertStringContainsString('camera=()', $permissionsHeader);
 | |
|         $this->assertStringContainsString('microphone=()', $permissionsHeader);
 | |
|         $this->assertStringContainsString('geolocation=()', $permissionsHeader);
 | |
|         $this->assertStringContainsString('payment=()', $permissionsHeader);
 | |
|     }
 | |
| }
 |