Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(gnoweb): add secure headers by default & timeout configuration #3619

Open
wants to merge 4 commits into
base: master
Choose a base branch
from

Conversation

gfanton
Copy link
Member

@gfanton gfanton commented Jan 28, 2025

This PR adds the following secure headers by default strict=true to gnoweb:

func SecureHeadersMiddleware(next http.Handler, strict bool) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		// Prevent MIME type sniffing by browsers. This ensures that the browser
		// does not interpret files as a different MIME type than declared.
		w.Header().Set("X-Content-Type-Options", "nosniff")

		// Prevent the page from being embedded in an iframe. This mitigates
		// clickjacking attacks by ensuring the page cannot be loaded in a frame.
		w.Header().Set("X-Frame-Options", "DENY")

		// Control the amount of referrer information sent in the Referer header.
		// 'no-referrer' ensures that no referrer information is sent, which
		// enhances privacy and prevents leakage of sensitive URLs.
		w.Header().Set("Referrer-Policy", "no-referrer")

		// In `strict` mode, prevent cross-site resource forgery and enforce https
		if strict {
			// Define a Content Security Policy (CSP) to restrict the sources of
			// scripts, styles, images, and other resources. This helps prevent
			// cross-site scripting (XSS) and other code injection attacks.
			// - 'self' allows resources from the same origin.
			// - '*' allows images from any external source.
			// - data: is not included to prevent inline images (e.g., base64-encoded images).
			w.Header().Set("Content-Security-Policy", "default-src 'self'; script-src 'self'; style-src 'self'; img-src 'self' *; font-src 'self'")

			// Enforce HTTPS by telling browsers to only access the site over HTTPS
			// for a specified duration (1 year in this case). This also applies to
			// subdomains and allows preloading into the browser's HSTS list.
			w.Header().Set("Strict-Transport-Security", "max-age=31536000; includeSubDomains; preload")
		}

		next.ServeHTTP(w, r)
	})
}

I've also enforced a timeout on read/write/idle (default to 1 minute).

cc @kristovatlas

Signed-off-by: gfanton <8671905+gfanton@users.noreply.github.com>
Signed-off-by: gfanton <8671905+gfanton@users.noreply.github.com>
@github-actions github-actions bot added the 📦 ⛰️ gno.land Issues or PRs gno.land package related label Jan 28, 2025
@Gno2D2
Copy link
Collaborator

Gno2D2 commented Jan 28, 2025

🛠 PR Checks Summary

🔴 Must not contain the "don't merge" label

Manual Checks (for Reviewers):
  • IGNORE the bot requirements for this PR (force green CI check)
Read More

🤖 This bot helps streamline PR reviews by verifying automated checks and providing guidance for contributors and reviewers.

✅ Automated Checks (for Contributors):

🟢 Maintainers must be able to edit this pull request (more info)
🔴 Must not contain the "don't merge" label

☑️ Contributor Actions:
  1. Fix any issues flagged by automated checks.
  2. Follow the Contributor Checklist to ensure your PR is ready for review.
    • Add new tests, or document why they are unnecessary.
    • Provide clear examples/screenshots, if necessary.
    • Update documentation, if required.
    • Ensure no breaking changes, or include BREAKING CHANGE notes.
    • Link related issues/PRs, where applicable.
☑️ Reviewer Actions:
  1. Complete manual checks for the PR, including the guidelines and additional checks if applicable.
📚 Resources:
Debug
Automated Checks
Maintainers must be able to edit this pull request (more info)

If

🟢 Condition met
└── 🟢 The pull request was created from a fork (head branch repo: gfanton/gno)

Then

🟢 Requirement satisfied
└── 🟢 Maintainer can modify this pull request

Must not contain the "don't merge" label

If

🟢 Condition met
└── 🟢 A label matches this pattern: don't merge (label: don't merge)

Then

🔴 Requirement not satisfied
└── 🔴 On no pull request

Manual Checks
**IGNORE** the bot requirements for this PR (force green CI check)

If

🟢 Condition met
└── 🟢 On every pull request

Can be checked by

  • Any user with comment edit permission

Signed-off-by: gfanton <8671905+gfanton@users.noreply.github.com>
Copy link

codecov bot commented Jan 28, 2025

Codecov Report

Attention: Patch coverage is 16.98113% with 44 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
gno.land/cmd/gnoweb/main.go 16.98% 43 Missing and 1 partial ⚠️

📢 Thoughts on this report? Let us know!

Copy link
Contributor

@aeddi aeddi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall LGTM 👍 I just asked a question bellow about your strict mode

// cross-site scripting (XSS) and other code injection attacks.
// - 'self' allows resources from the same origin.
// - 'data:' allows inline images (e.g., base64-encoded images).
w.Header().Set("Content-Security-Policy", "default-src 'self'; script-src 'self'; style-src 'self'; img-src 'self' data:; font-src 'self'")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So I haven't tested it locally yet, but is there a way to host images (for example) on Gnoweb? Because if we restrict access to "img-src" to "self" and there are no tricks for hosting them on Gnoweb, it will force user to hardcode base64 in their markdown.

And I have a feeling that hardcoding binary data into source code is not a great idea. We might need an equivalent to git-lfs. Or a way to host photos on the gno.land domain that relies on simple object storage and is not tied to the blockchain.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's a really good point. Discussing a bit with @moul, the plan is to have a whitelist of authorized hosts for images. We can keep allowing any external source for now (for images only) until we implement this whitelist system. I think we also want to deny any embed data: to prevent people from storing raw images on gnoland, but I'm unsure of applying this in this PR.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay, got it. Looks good 👍

gno.land/cmd/gnoweb/main.go Outdated Show resolved Hide resolved
Co-authored-by: Antoine Eddi <5222525+aeddi@users.noreply.github.com>
@gfanton gfanton added the don't merge Please don't merge this functionality temporarily label Jan 28, 2025
@kristovatlas
Copy link
Contributor

Can a user upload a .js file as part of their realm and use this to bypass CSP projection due to script-src 'self' ?

@kristovatlas
Copy link
Contributor

This is a good resource for security headers:
https://cheatsheetseries.owasp.org/cheatsheets/HTTP_Headers_Cheat_Sheet.html

Notwithstanding my above query, the other headers set look good.

Another header we might want to consider:

Permissions-Policy: geolocation=(), camera=(), microphone=()

Once this is deployed somewhere we should double check headers with https://securityheaders.com/

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
don't merge Please don't merge this functionality temporarily 📦 ⛰️ gno.land Issues or PRs gno.land package related
Projects
Status: Triage
Development

Successfully merging this pull request may close these issues.

4 participants