
Implementing Secure Go Web Applications with Content Security Policy (CSP)
To effectively implement CSP in a Go web application, we will cover the following topics:
- Understanding CSP directives
- Setting up a basic Go web server
- Implementing CSP headers
- Testing and validating CSP
Understanding CSP Directives
CSP is defined using a set of directives that control the resources the user agent is allowed to load. Below is a summary of some of the most commonly used directives:
| Directive | Description |
|---|---|
default-src | Serves as a fallback for other directives if they are not specified. |
script-src | Defines valid sources for JavaScript. |
style-src | Defines valid sources for stylesheets. |
img-src | Defines valid sources for images. |
connect-src | Defines valid sources for fetching resources via XMLHttpRequest (AJAX). |
frame-src | Defines valid sources for nested browsing contexts (iframes). |
Setting Up a Basic Go Web Server
To demonstrate CSP implementation, we will first set up a simple Go web server. Below is a minimal example that serves a basic HTML page.
package main
import (
"net/http"
)
func handler(w http.ResponseWriter, r *http.Request) {
w.Write([]byte(`
<!DOCTYPE html>
<html>
<head>
<title>Secure Go Web App</title>
</head>
<body>
<h1>Hello, Secure World!</h1>
</body>
</html>
`))
}
func main() {
http.HandleFunc("/", handler)
http.ListenAndServe(":8080", nil)
}To run the server, save the code in a file named main.go, and execute it using the command:
go run main.goImplementing CSP Headers
Next, we will implement CSP headers in our Go web application. This is done by setting the Content-Security-Policy header in the HTTP response. Below is an updated version of the previous example, which includes a basic CSP.
package main
import (
"net/http"
)
func handler(w http.ResponseWriter, r *http.Request) {
// Set CSP header
w.Header().Set("Content-Security-Policy", "default-src 'self'; script-src 'self'; style-src 'self';")
w.Write([]byte(`
<!DOCTYPE html>
<html>
<head>
<title>Secure Go Web App</title>
</head>
<body>
<h1>Hello, Secure World!</h1>
</body>
</html>
`))
}
func main() {
http.HandleFunc("/", handler)
http.ListenAndServe(":8080", nil)
}In this example, the CSP header is set to allow resources only from the same origin ('self'). This is a good starting point for securing your application.
Testing and Validating CSP
After implementing CSP, it is essential to test and validate that it is working as intended. You can use browser developer tools to inspect the HTTP headers of your responses.
- Open your web browser and navigate to
http://localhost:8080. - Open the Developer Tools (usually F12 or right-click > Inspect).
- Go to the Network tab and refresh the page.
- Click on the request for your page and inspect the response headers.
You should see the Content-Security-Policy header listed in the response headers.
Debugging CSP Violations
If you want to debug CSP violations, you can add the report-uri directive to your CSP header, which specifies where to send violation reports. Below is an example:
w.Header().Set("Content-Security-Policy", "default-src 'self'; script-src 'self'; style-src 'self'; report-uri /csp-violation-report-endpoint;")You will need to implement an endpoint /csp-violation-report-endpoint to handle incoming reports. Here’s a simple example:
func cspViolationHandler(w http.ResponseWriter, r *http.Request) {
// Handle the CSP violation report
// Log or process the report as needed
w.WriteHeader(http.StatusNoContent)
}
func main() {
http.HandleFunc("/", handler)
http.HandleFunc("/csp-violation-report-endpoint", cspViolationHandler)
http.ListenAndServe(":8080", nil)
}Conclusion
Implementing Content Security Policy in Go web applications is a crucial step in enhancing security. By defining and enforcing CSP headers, you can significantly reduce the risk of XSS and other injection attacks. Always test and validate your CSP implementation to ensure it works as expected.
