# Apache를 통한 보안설정



# [SECURITY] http header의 cookie

<table id="bkmrk-%EC%BF%A0%ED%82%A4-%EC%9D%B4%EB%A6%84-%EC%97%AD%ED%95%A0-secure-%ED%94%8C%EB%9E%98%EA%B7%B8-" style="width: 82.5926%;"><thead><tr><th style="width: 25.1672%;">**쿠키 이름**</th><th style="width: 27.0784%;">**역할**</th><th style="width: 26.6467%;">**Secure** 플래그</th><th style="width: 21.1078%;">**HttpOnly** 플래그</th></tr></thead></table>

<table id="bkmrk-phpsessid-php-%EA%B8%B0%EB%B3%B8-%EC%84%B8%EC%85%98-" style="width: 82.4691%;"><tbody><tr><td style="width: 25.7871%;">`PHPSESSID`</td><td style="width: 26.6867%;">PHP 기본 세션 쿠키</td><td style="width: 26.3882%;">**적용 안됨**</td><td style="width: 21.1381%;">**적용 안됨**</td></tr></tbody></table>

<table id="bkmrk-xsrf-token-csrf-%EB%B3%B4%ED%98%B8%EB%A5%BC-" style="width: 82.716%;"><tbody><tr><td style="width: 25.8595%;">`XSRF-TOKEN`</td><td style="width: 26.7564%;">CSRF 보호를 위한 토큰</td><td style="width: 26.1607%;">적용됨</td><td style="width: 21.2235%;">**적용 안됨**</td></tr></tbody></table>

<table id="bkmrk-laravel-%EC%84%B8%EC%85%98-%EC%BF%A0%ED%82%A4%3A-larav" style="width: 82.963%;"><tbody><tr><td style="width: 25.7824%;">`Laravel 세션 쿠키:`</td><td style="width: 27.4218%;">Laravel 세션 쿠키</td><td style="width: 25.6356%;">적용됨</td><td style="width: 21.1602%;">적용됨</td></tr></tbody></table>

XSRF-ROKEN과 Laravel 세션 쿠키는 프론트에서 처리 가능

> ## **PHPSESSID의 Secure 플래그 추가 방법**

- #### **`php.ini` 설정 수정**
    
    <div class="contain-inline-size rounded-md border-[0.5px] border-token-border-medium relative bg-token-sidebar-surface-primary dark:bg-gray-950"><div class="sticky top-9 md:top-[5.75rem]">  
    </div><div class="overflow-y-auto p-4" dir="ltr">`<span class="hljs-attr">session.cookie_secure</span> = <span class="hljs-literal">On</span>`</div></div>
- #### **PHP 코드에서 설정  
    `session_start()`를 호출하기 전에 아래와 같이 설정합니다:
    
    <div class="contain-inline-size rounded-md border-[0.5px] border-token-border-medium relative bg-token-sidebar-surface-primary dark:bg-gray-950"><div class="sticky top-9 md:top-[5.75rem]">  
    </div><div class="overflow-y-auto p-4" dir="ltr">`<span class="hljs-title function_ invoke__">ini_set</span>(<span class="hljs-string">'session.cookie_secure'</span>, <span class="hljs-number">1</span>);<span class="hljs-title function_ invoke__">ini_set</span>(<span class="hljs-string">'session.cookie_httponly'</span>, <span class="hljs-number">1</span>); <span class="hljs-comment">// HttpOnly 추가</span><span class="hljs-title function_ invoke__">session_start</span>();`</div></div>
- #### **`.htaccess` 파일에서 설정**
- `.htaccess`를 사용하여 PHP 설정을 수정할 수 있습니다:
    
    <div class="contain-inline-size rounded-md border-[0.5px] border-token-border-medium relative bg-token-sidebar-surface-primary dark:bg-gray-950"><div class="sticky top-9 md:top-[5.75rem]">  
    </div><div class="overflow-y-auto p-4" dir="ltr">`php_value session.cookie_secure On`</div><div class="overflow-y-auto p-4" dir="ltr">`php_value session.cookie_httponly On`</div></div>

# [Security] Content-Security-Policy

Content-Security-Policy header is not set. It restricts resources the page can load and prevents XSS attacks.

seo 진단시 위와 같은 진단내용이 잡힌다면 아래 내용들을 확인해주세요.

> ### **Content-Security-Policy(CSP)란?**

CSP는 HTTP 응답 헤더 중 하나로, 브라우저가 페이지에 어떤 리소스를 로드할 수 있는지 제어하는 보안 정책을 정의합니다.  
이를 통해 아래와 같은 보안 위협을 방지할 수 있습니다:

1. **XSS(크로스 사이트 스크립팅)**  
    공격자가 악성 JavaScript를 주입하는 것을 방지합니다.
2. **데이터 주입 공격**  
    악성 리소스(URL, CSS, 폰트 등)의 로드를 제한합니다.
3. **Clickjacking**  
    악성 iframe 삽입 등을 방지합니다.

---

> ### **Content-Security-Policy가 중요한 이유**

CSP가 없으면 다음과 같은 문제가 발생할 수 있습니다:

- 외부에서 악성 스크립트를 주입하여 **사용자 세션 탈취**, **피싱 공격** 가능.
- 비인가된 리소스가 로드되어 정보 유출 가능.
- HTTPS 환경에서도 보안이 취약한 HTTP 리소스가 로드될 가능성.

---

> ### **해결 방법: Content-Security-Policy 헤더 설정**

<p class="callout info">**Apache 설정을 통해 CSP 추가**</p>

  
Apache에서 `Content-Security-Policy` 헤더를 설정하려면 `.htaccess` 파일이나 서버 설정 파일(`httpd.conf`, `apache2.conf`)에 다음 규칙을 추가합니다.

```bash
<IfModule mod_headers.c>
Header set Content-Security-Policy "default-src 'self'; script-src 'self' https://www.googletagmanager.com https://d3js.org https://cdnjs.cloudflare.com https://cdn.jsdelivr.net 'unsafe-inline' 'unsafe-eval'; style-src 'self' https://fonts.googleapis.com https://cdn.jsdelivr.net 'unsafe-inline'; font-src 'self' https://fonts.gstatic.com https://cdn.jsdelivr.net data:; connect-src 'self' https://www.google-analytics.com; img-src 'self' data: https://cdn.jsdelivr.net;"
</IfModule>
```

<p class="callout success">default-src 'self'</p>

현재 사이트 외의 다른 출처에서 리소스(스크립트, 스타일, 이미지)를 불러오지 못하게 방지합니다.

<p class="callout success">self</p>

현재 사이트 자체에서 제공되는 스크립트만 허용합니다.

<p class="callout success">unsafe-inline</p>

인라인 스크립트를 허용합니다 (보안상 추천되지 않음).

<p class="callout success">unsafe-eval</p>

`eval()`이나 `setTimeout(string)` 같은 동적 코드 실행을 허용합니다.

<p class="callout success">data:</p>

데이터 URI를 통해 폰트, 이미지 등의 데이터를 허용합니다.

<span style="color: rgb(224, 62, 45);">\* 줄바꿈이 포함되면 500 server error가 발생할 수 있습니다.</span>

<p class="callout info">**2. 프론트에서 미들웨어 추가 (라라벨 기준)**  
</p>

1\. app/Http/Middleware에 새로운 class를 생성합니다.

2\. 아래와 같이 handle function을 추가합니다. $csp 변수 안에 내용은 직접 변경하셔야합니다.

```php
public function handle(Request $request, Closure $next)
    {
        $response = $next($request);


        $csp = "default-src 'self'; " .
       "script-src 'self' https://www.googletagmanager.com https://d3js.org https://cdnjs.cloudflare.com https://cdn.jsdelivr.net 'unsafe-inline' 'unsafe-eval'; " .
       "style-src 'self' https://fonts.googleapis.com https://cdn.jsdelivr.net 'unsafe-inline'; " .
       "font-src 'self' https://fonts.gstatic.com https://cdn.jsdelivr.net data:; " .
       "connect-src 'self' https://www.google-analytics.com; " .
       "img-src 'self' data: https://cdn.jsdelivr.net;";


        $response->headers->set('Content-Security-Policy', $csp);


        return $response;
    }
```

3\. `app/Http/Kernel.php`에 미들웨어를 추가합니다.

```php
protected $middleware = [ \App\Http\Middleware\ContentSecurityPolicy::class, ];
```

> ## 권장사항

<p class="callout info">**엄격한 정책으로 전환**</p>

- 초기에는 `unsafe-inline`을 사용할 수 있지만, 최종 배포시 제거하는 것이 좋습니다.
- `nonce` 또는 `hash` 기반 CSP를 사용하여 특정 스크립트만 허용하도록 설정하는 것이 좋습니다.

<p class="callout info">Nonce를 사용 (권장)</p>

아래 코드는 nonce 적용에 대한 예시코드입니다.

\- apache 설정

```bash
Header set Content-Security-Policy "default-src 'self'; script-src 'self' https://www.googletagmanager.com https://d3js.org https://cdnjs.cloudflare.com 'nonce-abc123'; style-src 'self' https://fonts.googleapis.com https://cdn.jsdelivr.net 'unsafe-inline'; font-src 'self' https://fonts.gstatic.com; connect-src 'self' https://api.example.com; img-src 'self' data:;"
```

\- script 사용부분

```js
<script nonce="abc123"> console.log('Inline script with nonce'); </script>
```

\- 동적 Nonce 생성

```php
<?php 
// php + javascript
$nonce = base64_encode(random_bytes(16)); 
header("Content-Security-Policy: script-src 'self' 'nonce-$nonce'"); 
?> 

<script nonce="<?php echo $nonce; ?>"> 
  console.log('This script uses a nonce'); 
</script>

```

```js
<script>
  // only javascript
  // Generate a random nonce
  const array = new Uint8Array(16); 
  window.crypto.getRandomValues(array); 
  const nonce = btoa(String.fromCharCode.apply(null, array)); 

  // Set the Content-Security-Policy header
  const meta = document.createElement('meta'); 
  meta.setAttribute('http-equiv', 'Content-Security-Policy'); 
  meta.setAttribute('content', `script-src 'self' 'nonce-${nonce}'`); 
  document.head.appendChild(meta); 

  // Dynamically create a script element with the nonce
  const script = document.createElement('script'); 
  script.setAttribute('nonce', nonce); 
  script.textContent = "console.log('This script uses a nonce')"; 
  document.body.appendChild(script); 
</script>

```

# [SECURITY] Header 보안설정하기

```bash
Header              OK    Notice    Warning    Critical    Recommendation
---------------------------------------------------------------------------------------------
X-Frame-Options      0      0          77         0        X-Frame-Options header is not set.
                                                       It prevents clickjacking attacks when 
                                                       set to 'deny' or 'sameorigin.'

X-Content-Type-Options 
                     0      0          77         0        X-Content-Type-Options header is not set.
                                                       It stops MIME type sniffing and mitigates 
                                                       content type attacks.

Referrer-Policy      0      0          77         0        Referrer-Policy header is not set.
                                                       It controls referrer header sharing and 
                                                       enhances privacy and security.

Feature-Policy       0      0          77         0        Feature-Policy header is not set.
                                                       It allows enabling/disabling browser APIs 
                                                       and features for security. Not important 
                                                       if Permissions-Policy is set.

Permissions-Policy   0      0          77         0        Permissions-Policy header is not set.
                                                       It allows enabling/disabling browser APIs 
                                                       and features for security.

Server               0      0          77         0        Server header is set to known 'Apache.'
                                                       It is better not to reveal used technologies.

Set-Cookie           70     65         70         0        Set-Cookie header for 'PHPSESSID' does not 
                                                       have 'SameSite' flag. Consider using 
                                                       'SameSite=Strict' or 'SameSite=Lax.'

                                                       Set-Cookie header for 'XSRF-TOKEN' does not 
                                                       have 'HttpOnly' flag. Attacker can steal 
                                                       the cookie using XSS. Consider using 
                                                       'HttpOnly' when cookie is not used by JavaScript.
---------------------------------------------------------------------------------------------

```

> ### X-Frame-Options

#### 문제:

- <span style="color: rgb(224, 62, 45);">X-Frame-Options 헤더가 설정되지 않음.</span>

#### 해결:

Apache 설정 파일에 다음을 추가:

```bash
Header always set X-Frame-Options "DENY"
```

- **DENY**: iframe 로딩을 완전히 차단.
- **SAMEORIGIN**: 같은 도메인에서만 iframe 로딩 허용.

> ### **X-Content-Type-Options**

#### 문제:

- <span style="color: rgb(224, 62, 45);">X-Content-Type-Options 헤더가 설정되지 않음.</span>

#### 해결:

Apache 설정 파일에 다음을 추가:

```bash
Header always set X-Content-Type-Options "nosniff"
```

- MIME 타입 스니핑 방지.

> ### **Referrer-Policy**

#### 문제:

- <span style="color: rgb(224, 62, 45);">Referrer-Policy 헤더가 설정되지 않음.</span>

#### 해결:

Apache 설정 파일에 다음을 추가:

```bash
Header always set Referrer-Policy "no-referrer"
```

- **no-referrer**: 참조 헤더를 완전히 숨김.
- 다른 옵션: `strict-origin`, `strict-origin-when-cross-origin`, `same-origin` 등.

> ### **Feature-Policy / Permissions-Policy**

#### 문제:

- <span style="color: rgb(224, 62, 45);">Feature-Policy 또는 Permissions-Policy 헤더가 설정되지 않음.</span>

#### 해결:

Apache 설정 파일에 다음을 추가:

```bash
Header always set Permissions-Policy "geolocation=(), camera=(), microphone=()"
```

- **Permissions-Policy**: 특정 브라우저 기능(API) 사용을 제한.
- 예: `geolocation`, `camera`, `microphone` 등.

> ### **Server**

#### 문제:

- <span style="color: rgb(224, 62, 45);">Server 헤더가 Apache로 설정되어 서버 정보가 노출됨.</span>

#### 해결:

Apache 설정 파일에 다음을 추가:

```bash
ServerTokens Prod
ServerSignature Off
Header unset Server
```

- **ServerTokens Prod**: 최소한의 정보만 노출.
- **ServerSignature Off**: 오류 페이지에서 Apache 정보 숨김.
- **Header unset Server**: Server 헤더를 제거.

> ### **Set-Cookie**

#### 문제:

- `<span style="color: rgb(224, 62, 45);">SameSite</span>`<span style="color: rgb(224, 62, 45);"> 및 `HttpOnly` 플래그가 없음.</span>

#### 해결:

Apache 설정 파일에 다음을 추가:

```
Header always edit Set-Cookie ^(.*)$ "$1; SameSite=Strict; HttpOnly; Secure"
```

- **SameSite=Strict**: 쿠키를 외부 요청에 전송하지 않음.
- **HttpOnly**: JavaScript에서 쿠키 접근을 차단.
- **Secure**: HTTPS 요청에서만 쿠키를 전송.

> ### **전체 설정시**

```bash
# X-Frame-Options 설정
Header always set X-Frame-Options "DENY"

# X-Content-Type-Options 설정
Header always set X-Content-Type-Options "nosniff"

# Referrer-Policy 설정
Header always set Referrer-Policy "no-referrer"

# Permissions-Policy 설정
Header always set Permissions-Policy "geolocation=(), camera=(), microphone=()"

# Server 정보 숨기기
ServerTokens Prod
ServerSignature Off
Header unset Server

# Set-Cookie 보안 설정
Header always edit Set-Cookie ^(.*)$ "$1; SameSite=Strict; HttpOnly; Secure"
```