Git Product home page Git Product logo

go-safeweb's Introduction

go-safeweb

DISCLAIMER: This is not an officially supported Google product.

go-safeweb is a collection of libraries for writing secure-by-default HTTP servers in Go.

Contributing

This project is in an early stage. We are currently not accepting any contributions.

Overview

The flexibility of Go’s net/http package allows users to quickly implement HTTP servers.

Responses are then written simply as slices of bytes, headers can be arbitrarily manipulated and so on. This approach offers much needed flexibility for these who really need it.

Unfortunately, this approach leaves great space for introducing security vulnerabilities and even experienced developers tend to do so.

This document aims to design an HTTP API that eliminates whole classes of bugs, like Cross-Site Scripting (XSS) or Cross-Site Request Forgery (XSRF). This can be achieved by an approach known at Google as safe coding. Learn more at Securing the Tangled Web (Chistoph Kern, 2014) or Preventing Security Bugs through Software Design (Christoph Kern, 2016).

Goals and Non-Goals

Goals

G1: Secure-by-default

Security mechanisms are applied by default (opt-out, not opt-in).

G2: Unsafe Usage is Easy to Review, Track and Restrict

All opt-outs from security mechanisms are explicit. Wherever possible, they’re contained inside a package or an option that’s easy to restrict.

G3: Designed for Evolving Security Requirements

Enforcing new security measures is feasible through AST manipulation. Existing users can be migrated using static analysis and/or runtime monitoring. Read more here.

G4: High Compatibility with Go’s Standard Library and Existing Open-Source Frameworks

Whenever possible, keep existing layouts, function signatures and other API parts the same as the Go’s standard library. High compatibility enables wide adoption.

Non Goals

NG1: Safe API Completeness

Creating safe APIs for all the corner cases might result in a bloated codebase. Our experience shows that this isn’t necessary.

NG2: Full Compatibility with Go’s Standard Library and Existing Open-Source Frameworks

Existing open-source frameworks or the Go standard library need to support each developer scenario. This would have left us with limited options of creating safe-by-default HTTP servers.

NG3: Features That Are Not Security Critical

Go Safe Web aims to help you create a secure-by-default Go HTTP server and nothing more. Features that are not security critical will not be added. Focusing solely on security allows us to maintain high compatibility with the standard library and makes adoption easier.

Security Vulnerabilities and Mitigations

On a high level, we plan to address, or provide the needed infrastructure to address, following issues (not an exhaustive list):

  • XSS (cross-site scripting) and XSSI (cross-site script inclusion) - e.g. by controlling how responses are generated
  • XSRF (cross-site request forgery) - e.g. by using Fetch Metadata policies, supporting token-based XSRF protection
  • CORS (cross-origin resource sharing) - e.g. by taking control of CORS response headers and handling CORS preflight requests
  • CSP (content security policy) - e.g. by automatically adding script nonces to HTML responses, adding relevant security headers
  • Transport Security - e.g. by enforcing HSTS support
  • IFraming - e.g. by setting relevant HTTP headers to restrict framing or providing server-side support for origin selection
  • Auth (access control) - e.g. by providing infrastructure for plugging in access control logic in an uniform, auditable way
  • HTTP Request Parsing Bugs - e.g. by implementing strict and well documented parsing behavior
  • Error responses - e.g. by providing infrastructure for uniform error handling (e.g. to prevent accidental leaks or XSS from error responses)
  • Enforcement of other security specific HTTP headers - here

Appendix

Evolving Security Requirements (example)

Imagine an API for configuring access control. It features three types of rules:

  • ALLOW(user) - allows a given user
  • DENY(user) - denies a given user (has priority over ALLOW)
  • REPORT(user) - reports that it has seen a request from a given user

Imagine now that at some point, security standards need to be increased and user = "frombulator" has been determined to not meet the desired bar.

How do we, for all the services running in our company, address this?

  1. For existing services, we add a LegacyFrombulatorAccess option like so: security.AccessControl(rules, unsafe.LegacyFrombulatorAccess()).
  2. We change the security.AccessControl() call to add by default a DENY("frombulator") rule. This rule is not added if unsafe.LegacyFrombulatorAccess is applied.
  3. Instead, unsafe.LegacyFrombulatorAccess adds a REPORT("frombulator") rule.

This way, we have:

  • Ensured that all new callers of security.AccessControl use the safe setting by default.
  • Can monitor existing services dependence on calls from the frombulator. After a period of observation (let’s say, 30 days):
    • If the service doesn’t receive requests from the frombulator: prune the unsafe.LegacyFrombulatorAccess option.
    • If the service does receive requests from the frombulator: inform the service owners and plan a fix.

Crucially, only the last case (dependence on unsafe configuration) requires engineering work per service. The rest can be automated.

This approach is possible due to careful API design. A missing DENY or REPORT rule, or a single sink in the form of security.AccessControl would make this infeasible.

Source Code Headers

Every file containing source code must include copyright and license information. This includes any JS/CSS files that you might be serving out to browsers. (This is to help well-intentioned people avoid accidental copying that doesn't comply with the license.)

Apache header:

Copyright 2020 Google LLC

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    https://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

go-safeweb's People

Contributors

al-pragliola avatar azraelsec avatar bsiegert avatar dependabot[bot] avatar dsnet avatar empijei avatar kele avatar mattiasgrenfeldt avatar mikue avatar mtrzos avatar testwill avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

go-safeweb's Issues

Add a reports collector

Features like CSP and COOP require a report collector to be installed on the server in order to collect reports.

Implement a handler that properly parses and collects reports, sets a 204 status and passes the parsed data to a user-provided implementation of a collector handler interface.

Add basic CSP functionality

The plugin should implement the following features:

  1. Have a configurable setup
  • Enforcement or Report-Only
  • Enable strict-dynamic (defaults to disabled)
  • Enable unsafe-eval (defaults to disabled)
  • Set a reporting endpoint or group (defaults to nothing for the time being, it will be a handler that the plugin installs later)
  • Set base-src (defaults to none)
  • Add a set of hashes (defaults to empty)
  1. Set a Content-Security-Policy header
    The policy should be a strict CSP and nonces should be generated in the Before phase. The plugin will be responsible of putting the nonce in the request context for later retrieval.

Handling boolean form values

Currently, we consider valid booleans to be only the strings "true" and "false", unlike strconv.ParseBool() which correctly converts "1", "t", "T", "true", "TRUE", "True", "0", "f", "F", "false", "FALSE", "False" into bool. We should discuss the implications of this and decide whether we want to use strconv.ParseBool() in the safehttp.Form implementation.

Add Fetch Metadata protection

The plugin should validate incoming requests against a FM policy and potentially decide to reject them.

Two policies should be supported: Resource Isolation and Navigation Isolation. It should be possible to selectively disable this plugin on CORS endpoints.

Add COOP functionality

Cross-Origin-Opener-Policy is a protection against cross-window side channels. It can assume 3 possible values and has 2 possible keys.

Keys: Cross-Origin-Opener-Policy, Cross-Origin-Opener-Policy-Report-Only
Values: same-origin, same-origin-allow-popups, none

We need a plugin that supports this functionality and installs a default policy of Cross-Origin-Opener-Policy: same-origin-allow-popups.

This is low priority since it is a stretch goal.

Add default security headers

The plugin should set some important security headers by default. The initial list should be:

X-Content-Type-Options: nosniff
X-XSS-Protection: 0

Add template nonce injection

The CSP and XSRF plugins currently put tokens in the request context.

  • There needs to be a part of the plugins that can, later on, provide that nonce for a template to render.
  • This should ideally work easily with different template implementations
  • This will likely happen in the Commit phase of both plugins

Add a CORS plugin

On CORS enabled endpoints this plugin should handle the incoming headers:

  • Origin
  • Access-Control-Request-Method
  • Access-Control-Request-Headers

And set the response headers accordingly:

  • Access-Control-Allow-Origin
  • Access-Control-Expose-Headers
  • Access-Control-Max-Age
  • Access-Control-Allow-Credentials
  • Access-Control-Allow-Methods
  • Access-Control-Allow-Headers

See https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS for more info

Add framing protection

Framing protection is done in two ways:

X-Frame-Options header, which should by default set to "sameorigin"
A frame-ancestors CSP directive set to "self". This part should somehow interact with the CSP plugin to set the additional directive.

Configuration should only be possible via some gated API that relaxes the framing protection on some endpoints. Note that on those endpoints XFO will be set to "allow" and CSP frame-ancestors to a specified list of allowed origins.

Implement accessor methods for getting a file passed in a multipart request

A POST, PATCH or PUT request with the header Content-Type:multipart/form-data allows users to send files as part of the request. This is currently not implemented in the safehttp.MultipartForm type. We need to investigate the behaviour of the current API, provided by net/http, and provide accessor methods for form files in the safehttp API

The dispatcher can write a response without providing a Content-Type header.

Currently the safehttp.Dispatcher can write a response without providing the Content-Type header. This could potentially lead to security issues. We therefore want to ensure that a Content-Type header is always written on each response.

This could be accomplished by creating a wrapper around the http.ResponseWriter such that the dispatcher needs to first specify a Content-Type before getting access to the responsewriter.

HSTS Plugin

A plugin to provide HSTS with safe default settings.

Document strange parsing behavior

To document the strange behavior we (@mattiasgrenfeldt and @mihalimara22) have found while testing the current behavior of net/http in #5 and #6 we should do the following: For each behavior we have observed that is strange or undesirable we should:

  • Create a separate test function that tests this behavior.
  • Create one subtest in the function that documents the current behavior.
  • Create one subtest in the function that documents the desired behavior. Use t.Skip() so that the tests pass CI.
  • Document the behavior using comments and explain why it is strange or undesirable.

(Issue created on @kele 's request.)

safehttp: Remove ExecuteTemplate from the Dispatcher signature

It is just a burden and adds complication and stuff to implement, not all servers will use templates and if we need to create a sugar to allow templates we can always create structs that wrap a template and its data in a safe response.

If we don't remove this function we would need to add a ExecuteTemplateName function to call ExecuteTemplate underneath instead of Execute.

HSTS Plugin documentation

There should be documentation for the HSTS plugin in /docs/. There should also be some document listing all plugins that are provided by the framework.

Add a way to uniformely and safely handle errors

The plugin should provide infrastructure for uniform error handling (e.g. to prevent accidental leaks or XSS from error responses).

Error responses should not surface internal details or code errors to the end users.

Add a safehttp.NotWritten Result

This needs to be well documented and requires to change all plugins to use it.

We should also think of a mechanism to prevent future code to use safehttp.Result{} instead.

Add a Server type

One important security feature is providing safe defaults for the Server type. For example there is a quite outdated post that explains some things that should be added to a Server type before exposing it to the internet.

We should provide a wrapper type that constructs servers with safe defaults.

@FiloSottile can probably help identify the stuff that needs updating from that original post.

Per-handler configuration for plugins

Plugins should be configurable per handler. This is especially important for plugins which use interceptors.

Examples:

  1. mux.Handler(..., csp.Disable()) -- CSP plugin is installed on the mux, but disabled for a given handler.
  2. mux.Handler(..., cors.Enable()) -- CORS plugin is installed on the mux, but by default it is not applied to any handlers, therefore we need to enable it.
  3. mux.Handler(..., auth.AllowAnonymous()) -- to change how access control is done.

This need stems from the design decision of not having per-handler plugins. The problems of having per-handler plugins (as opposed to mux-level plugins and per-plugin configurations):

  • what should be the order of interceptors execution?
  • overriding of plugins installed on handler level by the ones on mux level - how to remove a plugin?

Overall, having configurations seems like an easier option.

Come up with a better way of setting cookies.

Currently, to set cookies on a response you have to use the safehttp.Header.SetCookie method which takes a http.Cookie. All other ways to modify header values block the modification of the Set-Cookie header.

I suggest that we remove the safehttp.Header.SetCookie method, implement a safehttp.Cookie type with safe defaults and add a SetCookie method to safehttp.ResponseWriter.

XSRF Plugin

One of the plugins that are part of the go-safeweb will need to provide XSRF protection. This will also include a Fetch Metadata policy in case the browser used has Fetch Metadata support.

The test harness for testing net/http parsing is very slow, again

As of Go 1.15 #59 has been become a problem again. The solution we found in #63 doesn't work. But at least we know what is causing the slowdown.net/http.Server.Shutdowns polling interval for checking if all connections are finished is 0.5 s and we don't have time to shut everything down before the first sleep starts. Therefore we get punished by 0.5 s every time although closing our connections takes way less than 0.5 s.

Add support for Query parameters

The current implementation of safehttp.Form type also supports parsing query parameters as a Form object and returning any parsing errors that occurred. This follows the implementation of net/http and prevents users from calling URL.Query(), which silently discards parsing errors. We might want to consider separating the URL from the form type as future work.

Find a way to make plugins cooperate

Problem

Some plugins need to cooperate. For instance: framing plugin needs to cooperate with a csp plugin, cors would usually disable xsrf.

Proposed solution

To avoid the extra complexity of facilitating plugins (their interceptors) cooperation during execution time, we want to introduce orchestrators (name TBD).

At mux startup time, orchestrators would add other plugins to the respective handlers. Example:

mux.Handler(..., framing.Orchestrate(framing.UseCSP, framing.UseXFO))

The framing package would depend on the csp and the xfo packages in order to install and/or amend their configuration to support safe iframing.

Create a harness for HTTP request parsing tests

HTTP request parsing involves handling:

  • headers
  • form values
  • query parameters

Incorrect or non-deterministic handling of these might lead to security issues such as request smuggling.

The Tangled Web by Michał Zalewski (lcamtuf) (2011), specifically chapters I.2 It Starts with a URL and I.3 Hypertext Transfer Protocol, is a good resource for learning how complex and full of edge cases this task can be.

We need to create a testing harness where, as unit tests, we can send HTTP requests (built as arbitrary byte slices to cover attacks leveraging tricky encoding) and assert on what the http.Handler sees inside http.Request.

The assertions must not assume the client is written in Go.

This issue considers only building the needed infrastructure, not the test scenarios themselves. These are to be tracked in separate issues.

Retrieve form values consistently

In Go, accessing the form values associated to one key can be done using multiple functions, some with different return values. These can cause inconsistencies in the handlers' implementation of a server. We want to design and implement a way to mitigate this problem.

Remove the Response argument from ResponseWriter.ServerError until we come up with how to support default error responses

safehttp.ResponseWriter.ServerError currently has the following signature:

func (w *ResponseWriter) ServerError(code StatusCode, resp Response) Result

It takes a safehttp.Response as an argument, but there might be places where we want to respond with a server error without having the ability to create safe responses. For example if a plugin needs to interrupt the handling of an incoming request. We therefore need to reconsider the signature of ServerError so that it doesn't take a Response or so that it is possible to optionally call without a Response.

Conformance checks during mux startup

Create the ability of adding conformance checks that run after the mux has been set up. These would be able to:

  • list all the plugins registered for each handler, together with the method, path and all other information
  • ask plugins for their configuration

Conformance checks would need to cooperate with plugins, i.e. there is going to be no complex protocol for information exchange between a plugin and the conformance check. A simple func (p Plugin) Config() interface{} would be enough, as the conformance check needs to have full trust in the plugins anyway.

The test harness for testing net/http parsing is very slow

Running the tests in tests/headers, tests/formparams and tests/queryparams currently takes 30+ seconds. This is very slow. They all use the testing harness in internal/requesttesting/test_harness.go. @empijei suspects that this might be because something is not closed correctly which causes the test harness to have to wait for a timeout to finish on each test.

This needs to be investigated further. The cause of the slowdown needs to identified and fixed.

If it turns out that a response will be an error (4xx, 5xx) we want to be able to remove headers set by plugins.

Imagine that we have two plugins installed. The first one claims and sets a header in the Before phase. The other plugins Before phase runs and an error occurs, so the plugin writes an error response (4xx, 5xx). Now, what happens to the header that the first plugin set? Depending on the plugin this header should probably not be present on error responses. So how do we remove it?

One option would be that all error responses, 4xx and 5xx, automatically remove all headers and set their own ones. But this becomes a problem since we might want CSP on error responses. CSP is handled by a plugin.

Another solution is that all plugins are responsible for removing their headers in the commit phase if it sees that the response is an error.

This needs to be discussed further.

Don't assume client is Go in tests.

In tests/integration/safehtml/safehtml_test.go and in tests/integration/header/header_test.go (not merged yet as of writing this, see #21 ) the ResponseRecorder from net/http/httptest is used. After calling ResponseRecorder.Result() the response is parsed and a http.Response object is created. This should be removed since it assumes that the client in our tests is written in Go. Instead simpler comparisons should be used so that we don't rely on the implementation of ResponseRecorder.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.