-
Notifications
You must be signed in to change notification settings - Fork 213
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: Added security headers docs (#266)
- Loading branch information
KostLinux
authored
Apr 18, 2024
1 parent
0e864f3
commit 78dafed
Showing
9 changed files
with
676 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
--- | ||
title: "Security Headers" | ||
draft: false | ||
--- | ||
|
||
It's important to use security headers to protect your web application from common security vulnerabilities. This example shows you how to add security headers to your Gin application and also how to avoid Host Header Injection related attacks (SSRF, Open Redirection). | ||
|
||
```go | ||
package main | ||
|
||
import ( | ||
"net/http" | ||
|
||
"github.com/gin-gonic/gin" | ||
) | ||
|
||
func main() { | ||
r := gin.Default() | ||
|
||
expectedHost := "localhost:8080" | ||
|
||
// Setup Security Headers | ||
r.Use(func(c *gin.Context) { | ||
if c.Request.Host != expectedHost { | ||
c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"error": "Invalid host header"}) | ||
return | ||
} | ||
c.Header("X-Frame-Options", "DENY") | ||
c.Header("Content-Security-Policy", "default-src 'self'; connect-src *; font-src *; script-src-elem * 'unsafe-inline'; img-src * data:; style-src * 'unsafe-inline';") | ||
c.Header("X-XSS-Protection", "1; mode=block") | ||
c.Header("Strict-Transport-Security", "max-age=31536000; includeSubDomains; preload") | ||
c.Header("Referrer-Policy", "strict-origin") | ||
c.Header("X-Content-Type-Options", "nosniff") | ||
c.Header("Permissions-Policy", "geolocation=(),midi=(),sync-xhr=(),microphone=(),camera=(),magnetometer=(),gyroscope=(),fullscreen=(self),payment=()") | ||
c.Next() | ||
}) | ||
|
||
r.GET("/ping", func(c *gin.Context) { | ||
c.JSON(200, gin.H{ | ||
"message": "pong", | ||
}) | ||
}) | ||
|
||
r.Run() // listen and serve on 0.0.0.0:8080 | ||
} | ||
``` | ||
|
||
You can test it via `curl`: | ||
|
||
```bash | ||
// Check Headers | ||
|
||
curl localhost:8080/ping -I | ||
|
||
HTTP/1.1 404 Not Found | ||
Content-Security-Policy: default-src 'self'; connect-src *; font-src *; script-src-elem * 'unsafe-inline'; img-src * data:; style-src * 'unsafe-inline'; | ||
Content-Type: text/plain | ||
Permissions-Policy: geolocation=(),midi=(),sync-xhr=(),microphone=(),camera=(),magnetometer=(),gyroscope=(),fullscreen=(self),payment=() | ||
Referrer-Policy: strict-origin | ||
Strict-Transport-Security: max-age=31536000; includeSubDomains; preload | ||
X-Content-Type-Options: nosniff | ||
X-Frame-Options: DENY | ||
X-Xss-Protection: 1; mode=block | ||
Date: Sat, 30 Mar 2024 08:20:44 GMT | ||
Content-Length: 18 | ||
|
||
// Check Host Header Injection | ||
|
||
curl localhost:8080/ping -I -H "Host:neti.ee" | ||
|
||
HTTP/1.1 400 Bad Request | ||
Content-Type: application/json; charset=utf-8 | ||
Date: Sat, 30 Mar 2024 08:21:09 GMT | ||
Content-Length: 31 | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
--- | ||
title: "Encabezados de seguridad" | ||
draft: false | ||
--- | ||
Es importante utilizar cabeceras de seguridad para proteger su aplicación web de vulnerabilidades de seguridad comunes. Este ejemplo le muestra cómo añadir cabeceras de seguridad a su aplicación Gin y también cómo evitar ataques relacionados con Host Header Injection (SSRF, Open Redirection). | ||
|
||
```go | ||
package main | ||
|
||
import ( | ||
"net/http" | ||
|
||
"github.com/gin-gonic/gin" | ||
) | ||
|
||
func main() { | ||
r := gin.Default() | ||
|
||
expectedHost := "localhost:8080" | ||
|
||
// Setup Security Headers | ||
r.Use(func(c *gin.Context) { | ||
if c.Request.Host != expectedHost { | ||
c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"error": "Invalid host header"}) | ||
return | ||
} | ||
c.Header("X-Frame-Options", "DENY") | ||
c.Header("Content-Security-Policy", "default-src 'self'; connect-src *; font-src *; script-src-elem * 'unsafe-inline'; img-src * data:; style-src * 'unsafe-inline';") | ||
c.Header("X-XSS-Protection", "1; mode=block") | ||
c.Header("Strict-Transport-Security", "max-age=31536000; includeSubDomains; preload") | ||
c.Header("Referrer-Policy", "strict-origin") | ||
c.Header("X-Content-Type-Options", "nosniff") | ||
c.Header("Permissions-Policy", "geolocation=(),midi=(),sync-xhr=(),microphone=(),camera=(),magnetometer=(),gyroscope=(),fullscreen=(self),payment=()") | ||
c.Next() | ||
}) | ||
|
||
r.GET("/ping", func(c *gin.Context) { | ||
c.JSON(200, gin.H{ | ||
"message": "pong", | ||
}) | ||
}) | ||
|
||
r.Run() // listen and serve on 0.0.0.0:8080 | ||
} | ||
``` | ||
|
||
Puede probarlo mediante `curl`: | ||
|
||
```bash | ||
// ヘッダーのチェック | ||
|
||
curl localhost:8080/ping -I | ||
|
||
HTTP/1.1 404 Not Found | ||
Content-Security-Policy: default-src 'self'; connect-src *; font-src *; script-src-elem * 'unsafe-inline'; img-src * data:; style-src * 'unsafe-inline'; | ||
Content-Type: text/plain | ||
Permissions-Policy: geolocation=(),midi=(),sync-xhr=(),microphone=(),camera=(),magnetometer=(),gyroscope=(),fullscreen=(self),payment=() | ||
Referrer-Policy: strict-origin | ||
Strict-Transport-Security: max-age=31536000; includeSubDomains; preload | ||
X-Content-Type-Options: nosniff | ||
X-Frame-Options: DENY | ||
X-Xss-Protection: 1; mode=block | ||
Date: Sat, 30 Mar 2024 08:20:44 GMT | ||
Content-Length: 18 | ||
|
||
// ホスト・ヘッダー・インジェクションのチェック | ||
|
||
curl localhost:8080/ping -I -H "Host:neti.ee" | ||
|
||
HTTP/1.1 400 Bad Request | ||
Content-Type: application/json; charset=utf-8 | ||
Date: Sat, 30 Mar 2024 08:21:09 GMT | ||
Content-Length: 31 | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
--- | ||
title: "Security Headers" | ||
draft: false | ||
--- | ||
|
||
It's important to use security headers to protect your web application from common security vulnerabilities. This example shows you how to add security headers to your Gin application and also how to avoid Host Header Injection related attacks (SSRF, Open Redirection). | ||
|
||
```go | ||
package main | ||
|
||
import ( | ||
"net/http" | ||
|
||
"github.com/gin-gonic/gin" | ||
) | ||
|
||
func main() { | ||
r := gin.Default() | ||
|
||
expectedHost := "localhost:8080" | ||
|
||
// Setup Security Headers | ||
r.Use(func(c *gin.Context) { | ||
if c.Request.Host != expectedHost { | ||
c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"error": "Invalid host header"}) | ||
return | ||
} | ||
c.Header("X-Frame-Options", "DENY") | ||
c.Header("Content-Security-Policy", "default-src 'self'; connect-src *; font-src *; script-src-elem * 'unsafe-inline'; img-src * data:; style-src * 'unsafe-inline';") | ||
c.Header("X-XSS-Protection", "1; mode=block") | ||
c.Header("Strict-Transport-Security", "max-age=31536000; includeSubDomains; preload") | ||
c.Header("Referrer-Policy", "strict-origin") | ||
c.Header("X-Content-Type-Options", "nosniff") | ||
c.Header("Permissions-Policy", "geolocation=(),midi=(),sync-xhr=(),microphone=(),camera=(),magnetometer=(),gyroscope=(),fullscreen=(self),payment=()") | ||
c.Next() | ||
}) | ||
|
||
r.GET("/ping", func(c *gin.Context) { | ||
c.JSON(200, gin.H{ | ||
"message": "pong", | ||
}) | ||
}) | ||
|
||
r.Run() // listen and serve on 0.0.0.0:8080 | ||
} | ||
``` | ||
|
||
You can test it via `curl`: | ||
|
||
```bash | ||
// Check Headers | ||
|
||
curl localhost:8080/ping -I | ||
|
||
HTTP/1.1 404 Not Found | ||
Content-Security-Policy: default-src 'self'; connect-src *; font-src *; script-src-elem * 'unsafe-inline'; img-src * data:; style-src * 'unsafe-inline'; | ||
Content-Type: text/plain | ||
Permissions-Policy: geolocation=(),midi=(),sync-xhr=(),microphone=(),camera=(),magnetometer=(),gyroscope=(),fullscreen=(self),payment=() | ||
Referrer-Policy: strict-origin | ||
Strict-Transport-Security: max-age=31536000; includeSubDomains; preload | ||
X-Content-Type-Options: nosniff | ||
X-Frame-Options: DENY | ||
X-Xss-Protection: 1; mode=block | ||
Date: Sat, 30 Mar 2024 08:20:44 GMT | ||
Content-Length: 18 | ||
|
||
// Check Host Header Injection | ||
|
||
curl localhost:8080/ping -I -H "Host:neti.ee" | ||
|
||
HTTP/1.1 400 Bad Request | ||
Content-Type: application/json; charset=utf-8 | ||
Date: Sat, 30 Mar 2024 08:21:09 GMT | ||
Content-Length: 31 | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
--- | ||
title: "セキュリティ・ヘッダ" | ||
draft: false | ||
--- | ||
|
||
セキュリティヘッダの使用は、一般的なセキュリティの脆弱性からウェブアプリケーションを守るために重要です。この例では、Gin アプリケーションにセキュリティヘッダーを追加する方法と、ホストヘッダーインジェクションに関連する攻撃(SSRF、Open Redirection)を回避する方法を示します。 | ||
|
||
```go | ||
package main | ||
|
||
import ( | ||
"net/http" | ||
|
||
"github.com/gin-gonic/gin" | ||
) | ||
|
||
func main() { | ||
r := gin.Default() | ||
|
||
expectedHost := "localhost:8080" | ||
|
||
// Setup Security Headers | ||
r.Use(func(c *gin.Context) { | ||
if c.Request.Host != expectedHost { | ||
c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"error": "Invalid host header"}) | ||
return | ||
} | ||
c.Header("X-Frame-Options", "DENY") | ||
c.Header("Content-Security-Policy", "default-src 'self'; connect-src *; font-src *; script-src-elem * 'unsafe-inline'; img-src * data:; style-src * 'unsafe-inline';") | ||
c.Header("X-XSS-Protection", "1; mode=block") | ||
c.Header("Strict-Transport-Security", "max-age=31536000; includeSubDomains; preload") | ||
c.Header("Referrer-Policy", "strict-origin") | ||
c.Header("X-Content-Type-Options", "nosniff") | ||
c.Header("Permissions-Policy", "geolocation=(),midi=(),sync-xhr=(),microphone=(),camera=(),magnetometer=(),gyroscope=(),fullscreen=(self),payment=()") | ||
c.Next() | ||
}) | ||
|
||
r.GET("/ping", func(c *gin.Context) { | ||
c.JSON(200, gin.H{ | ||
"message": "pong", | ||
}) | ||
}) | ||
|
||
r.Run() // listen and serve on 0.0.0.0:8080 | ||
} | ||
``` | ||
|
||
`curl`でテストできます: | ||
|
||
|
||
```bash | ||
// ヘッダーのチェック | ||
|
||
curl localhost:8080/ping -I | ||
|
||
HTTP/1.1 404 Not Found | ||
Content-Security-Policy: default-src 'self'; connect-src *; font-src *; script-src-elem * 'unsafe-inline'; img-src * data:; style-src * 'unsafe-inline'; | ||
Content-Type: text/plain | ||
Permissions-Policy: geolocation=(),midi=(),sync-xhr=(),microphone=(),camera=(),magnetometer=(),gyroscope=(),fullscreen=(self),payment=() | ||
Referrer-Policy: strict-origin | ||
Strict-Transport-Security: max-age=31536000; includeSubDomains; preload | ||
X-Content-Type-Options: nosniff | ||
X-Frame-Options: DENY | ||
X-Xss-Protection: 1; mode=block | ||
Date: Sat, 30 Mar 2024 08:20:44 GMT | ||
Content-Length: 18 | ||
|
||
// ホスト・ヘッダー・インジェクションのチェック | ||
|
||
curl localhost:8080/ping -I -H "Host:neti.ee" | ||
|
||
HTTP/1.1 400 Bad Request | ||
Content-Type: application/json; charset=utf-8 | ||
Date: Sat, 30 Mar 2024 08:21:09 GMT | ||
Content-Length: 31 | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
--- | ||
title: "보안 헤더" | ||
draft: false | ||
--- | ||
|
||
일반적인 보안 취약점으로부터 웹 애플리케이션을 보호하려면 보안 헤더를 사용하는 것이 중요합니다. 이 예에서는 Gin 애플리케이션에 보안 헤더를 추가하는 방법과 호스트 헤더 인젝션 관련 공격(SSRF, 오픈 리디렉션)을 방지하는 방법을 설명합니다. | ||
|
||
```go | ||
package main | ||
|
||
import ( | ||
"net/http" | ||
|
||
"github.com/gin-gonic/gin" | ||
) | ||
|
||
func main() { | ||
r := gin.Default() | ||
|
||
expectedHost := "localhost:8080" | ||
|
||
// Setup Security Headers | ||
r.Use(func(c *gin.Context) { | ||
if c.Request.Host != expectedHost { | ||
c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"error": "Invalid host header"}) | ||
return | ||
} | ||
c.Header("X-Frame-Options", "DENY") | ||
c.Header("Content-Security-Policy", "default-src 'self'; connect-src *; font-src *; script-src-elem * 'unsafe-inline'; img-src * data:; style-src * 'unsafe-inline';") | ||
c.Header("X-XSS-Protection", "1; mode=block") | ||
c.Header("Strict-Transport-Security", "max-age=31536000; includeSubDomains; preload") | ||
c.Header("Referrer-Policy", "strict-origin") | ||
c.Header("X-Content-Type-Options", "nosniff") | ||
c.Header("Permissions-Policy", "geolocation=(),midi=(),sync-xhr=(),microphone=(),camera=(),magnetometer=(),gyroscope=(),fullscreen=(self),payment=()") | ||
c.Next() | ||
}) | ||
|
||
r.GET("/ping", func(c *gin.Context) { | ||
c.JSON(200, gin.H{ | ||
"message": "pong", | ||
}) | ||
}) | ||
|
||
r.Run() // listen and serve on 0.0.0.0:8080 | ||
} | ||
``` | ||
|
||
`curl` 로 테스트할 수 있습니다: | ||
|
||
|
||
```bash | ||
// 헤더 확인 | ||
|
||
curl localhost:8080/ping -I | ||
|
||
HTTP/1.1 404 Not Found | ||
Content-Security-Policy: default-src 'self'; connect-src *; font-src *; script-src-elem * 'unsafe-inline'; img-src * data:; style-src * 'unsafe-inline'; | ||
Content-Type: text/plain | ||
Permissions-Policy: geolocation=(),midi=(),sync-xhr=(),microphone=(),camera=(),magnetometer=(),gyroscope=(),fullscreen=(self),payment=() | ||
Referrer-Policy: strict-origin | ||
Strict-Transport-Security: max-age=31536000; includeSubDomains; preload | ||
X-Content-Type-Options: nosniff | ||
X-Frame-Options: DENY | ||
X-Xss-Protection: 1; mode=block | ||
Date: Sat, 30 Mar 2024 08:20:44 GMT | ||
Content-Length: 18 | ||
|
||
// 호스트 헤더 주입 확인 | ||
|
||
curl localhost:8080/ping -I -H "Host:neti.ee" | ||
|
||
HTTP/1.1 400 Bad Request | ||
Content-Type: application/json; charset=utf-8 | ||
Date: Sat, 30 Mar 2024 08:21:09 GMT | ||
Content-Length: 31 | ||
``` |
Oops, something went wrong.