## 前言
某些情況,大家的系統會被掃描出低危漏洞,描述如下:
```
1.未設置Content-Security-Policy或X-Content-Security-Policy響應頭.
2.未設置Strict-Transport-Security響應頭.
3.Set-Cookie未設置Secure標識.
4.Set-Cookie未設置HttpOnly標識.
```
處理方式也很簡單,有Nginx和Java兩種方式,我們更推薦從Nginx進行配置。
<br>
## 一、Nginx配置(推薦,性能更高,可靈活變動,不影響系統運行)
### 1. 在 Nginx 中添加安全 HTTP 響應頭
可以通過 `add_header` 指令在 Nginx 配置中全局添加所需的 HTTP 響應頭。
#### 示例 Nginx 配置:
```nginx
server {
listen 443 ssl;
server_name yourdomain.com;
# SSL 證書配置
ssl_certificate /path/to/your/certificate.crt;
ssl_certificate_key /path/to/your/private.key;
# 確保客戶端只能通過 HTTPS 訪問
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
# 添加 Content-Security-Policy 頭,限制資源加載來源
add_header Content-Security-Policy "default-src 'self';" always;
# 添加 X-Content-Type-Options 頭,防止 MIME 類型嗅探
add_header X-Content-Type-Options "nosniff" always;
# 添加 X-Frame-Options 頭,防止點擊劫持,使用 SAMEORIGIN 來允許同源訪問
add_header X-Frame-Options "SAMEORIGIN" always;
# 添加 X-XSS-Protection 頭,防止 XSS 攻擊
add_header X-XSS-Protection "1; mode=block" always;
# 添加 X-Permitted-Cross-Domain-Policies 頭,阻止跨域策略文件被加載
add_header X-Permitted-Cross-Domain-Policies "none" always;
# 添加 X-Download-Options 頭,防止文件被下載時自動打開
add_header X-Download-Options "noopen" always;
# 添加 Referrer-Policy 頭,限制引薦來源的披露
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
# 處理反向代理請求
location / {
proxy_pass http://your_backend_server;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
```
### 2. 全局設置 `Set-Cookie` 的 `Secure` 和 `HttpOnly` 標識
對于 `Set-Cookie` 頭,你可以使用 `proxy_cookie_path` 和 `proxy_cookie_flags` 指令來修改 `Set-Cookie` 頭,添加 `Secure` 和 `HttpOnly` 標識。
#### 示例 Nginx 配置:
```nginx
server {
listen 443 ssl;
server_name yourdomain.com;
# SSL 證書配置
ssl_certificate /path/to/your/certificate.crt;
ssl_certificate_key /path/to/your/private.key;
# 確保客戶端只能通過 HTTPS 訪問
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
# 添加 Content-Security-Policy 頭,限制資源加載來源
add_header Content-Security-Policy "default-src 'self';" always;
# 添加 X-Content-Type-Options 頭,防止 MIME 類型嗅探
add_header X-Content-Type-Options "nosniff" always;
# 添加 X-Frame-Options 頭,防止點擊劫持,使用 SAMEORIGIN 來允許同源訪問
add_header X-Frame-Options "SAMEORIGIN" always;
# 添加 X-XSS-Protection 頭,防止 XSS 攻擊
add_header X-XSS-Protection "1; mode=block" always;
# 添加 X-Permitted-Cross-Domain-Policies 頭,阻止跨域策略文件被加載
add_header X-Permitted-Cross-Domain-Policies "none" always;
# 添加 X-Download-Options 頭,防止文件被下載時自動打開
add_header X-Download-Options "noopen" always;
# 添加 Referrer-Policy 頭,限制引薦來源的披露
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
# 為所有 Set-Cookie 頭添加 Secure 標識(需要 HTTPS)
proxy_cookie_flags ~ Secure;
# 為所有 Set-Cookie 頭添加 HttpOnly 標識
proxy_cookie_flags ~ HttpOnly;
# 處理反向代理請求
location / {
proxy_pass http://your_backend_server;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
```
### 3. 配置說明
- **`add_header`**:用于在 HTTP 響應中添加自定義頭。`always` 參數確保即使返回 4xx 或 5xx 錯誤代碼時也會添加這些頭。
- `Strict-Transport-Security`: 強制瀏覽器通過 HTTPS 訪問,避免中間人攻擊。
- `Content-Security-Policy`: 限制資源加載的來源,防止 XSS 攻擊。
- `X-Content-Type-Options`: 防止 MIME 類型嗅探,避免瀏覽器解析錯誤的文件類型。
- `X-Frame-Options`: 防止點擊劫持攻擊。
- `X-XSS-Protection`: 啟用瀏覽器的 XSS 過濾器,防止 XSS 攻擊。
- **`proxy_cookie_flags`**:用于修改 `Set-Cookie` 頭的標識。`~` 匹配所有 Cookie。
- `Secure`: 僅在 HTTPS 連接下發送 Cookie,避免 Cookie 在明文 HTTP 傳輸中被竊取。
- `HttpOnly`: 防止 JavaScript 訪問 Cookie,減少 XSS 攻擊的風險。
### 4. 其他安全頭
你還可以根據需要添加其他安全頭,例如:
- **Referrer-Policy**: 控制瀏覽器在發送 HTTP 請求時如何處理 `Referer` 頭。
```nginx
add_header Referrer-Policy "no-referrer" always;
```
- **Permissions-Policy**: 控制瀏覽器的某些特性(如攝像頭、麥克風等)的使用權限。
```nginx
add_header Permissions-Policy "geolocation=(), microphone=(), camera=()" always;
```
### 5. 總結
通過在 Nginx 中配置這些安全頭和 `Set-Cookie` 標識,你可以確保所有的請求和響應都符合安全要求,而不需要修改應用程序的代碼。這樣可以集中管理安全策略,并且對所有后端服務生效。
#### 要點:
- 使用 `add_header` 指令為響應添加安全頭。
- 使用 `proxy_cookie_flags` 指令為所有 `Set-Cookie` 頭添加 `Secure` 和 `HttpOnly` 標識。
- 確保 Nginx 配置文件正確無誤后,重新加載 Nginx 配置。
通過這種方式,可以在 Nginx 層面上解決安全問題。
<br>
## 二、Java配置(不推薦,影響系統性能,不可靈活配置)
1. java可以用一個filter解決所有請求頭、響應頭的安全問題,具體范例如下:
```java
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Collection;
import java.util.stream.Collectors;
import org.springframework.stereotype.Component;
@Component
public class SecurityHeadersFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
// 初始化方法,可選
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
HttpServletResponse httpServletResponse = (HttpServletResponse) response;
// 設置Content-Security-Policy響應頭
httpServletResponse.setHeader("Content-Security-Policy", "default-src 'self'");
// 設置Strict-Transport-Security響應頭
httpServletResponse.setHeader("Strict-Transport-Security", "max-age=31536000; includeSubDomains");
// 繼續處理請求
chain.doFilter(request, response);
// 攔截響應中的Set-Cookie頭,添加Secure和HttpOnly標識
Collection<String> setCookieHeaders = httpServletResponse.getHeaders("Set-Cookie");
if (setCookieHeaders != null) {
// 將現有的Set-Cookie頭處理并重新設置
Collection<String> modifiedCookies = setCookieHeaders.stream()
.map(cookie -> {
if (!cookie.toLowerCase().contains("secure")) {
cookie += "; Secure";
}
if (!cookie.toLowerCase().contains("httponly")) {
cookie += "; HttpOnly";
}
return cookie;
})
.collect(Collectors.toList());
// 先移除原有的Set-Cookie頭
httpServletResponse.setHeader("Set-Cookie", null);
// 重新添加修改后的Set-Cookie頭
for (String modifiedCookie : modifiedCookies) {
httpServletResponse.addHeader("Set-Cookie", modifiedCookie);
}
}
}
@Override
public void destroy() {
// 銷毀方法,可選
}
}
```
2. 在 Spring Boot 中,過濾器會自動注冊,但也可以通過 `@Bean` 顯式注冊過濾器。
```java
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class FilterConfig {
@Bean
public FilterRegistrationBean<SecurityHeadersFilter> securityHeadersFilter() {
FilterRegistrationBean<SecurityHeadersFilter> registrationBean = new FilterRegistrationBean<>();
registrationBean.setFilter(new SecurityHeadersFilter());
registrationBean.addUrlPatterns("/*"); // 對所有請求生效
return registrationBean;
}
}
```
3. **`doFilter` 方法中的邏輯**:
* 首先,設置需要的安全響應頭(如`Content-Security-Policy`和`Strict-Transport-Security`)。
* 然后,調用`chain.doFilter(request, response)`繼續處理請求,這樣后續的邏輯可以正常執行,并生成響應。
* 當響應生成后,我們獲取所有的`Set-Cookie`頭。
* 對每個`Set-Cookie`頭進行處理,檢查是否已經包含`Secure`和`HttpOnly`標識。如果沒有,則自動添加這些標識。
* 最后,重新設置修改后的`Set-Cookie`頭。
4. **處理流程**:
* 過濾器會在每個請求的響應階段執行,確保所有的`Set-Cookie`頭都被檢查和修改(如果需要)。
* 這樣,你就不需要在每次設置`Cookie`時手動處理`Secure`和`HttpOnly`標識了。
5. **注意事項**
* **HTTPS**:`Secure`標識僅在 HTTPS 連接下有效。如果你在本地開發時使用的是 HTTP,則`Secure`標識不會生效,只有在 HTTPS 環境下才會生效。
* **HttpOnly**:這個標識會阻止 JavaScript 訪問`Cookie`,因此確保你不需要通過 JavaScript 訪問這些`Cookie`。