Code Monkey home page Code Monkey logo

amppackager's Introduction

AMP Packager

AMP Packager is a tool to improve AMP URLs by serving AMP using Signed Exchanges. By running it in a proper configuration, web publishers enable origin URLs to appear in AMP search results.

The AMP Packager works by creating Signed HTTP Exchanges (SXGs) containing AMP documents, signed with a certificate associated with the origin, with a maximum lifetime of 7 days. The Google AMP Cache will fetch, cache, and serve them, similar to what it does for normal AMP HTML documents. When a user loads such an SXG, Chrome validates the signature and then displays the certificate's domain in the URL bar instead of google.com, and treats the web page as though it were on that domain.

The packager is an HTTP server that sits behind a frontend server; it fetches and signs AMP documents as requested by the AMP Cache.

As an alternative to running the packager, you can sign up for one of the SXG service providers.

Packager/Signer

How to use

In all the instructions below, replace amppackageexample.com with a domain you own and can obtain certificates for.

Development server

Manual installation
  1. Install Go version 1.13 or higher.

  2. Get amppackager.

    git clone https://github.com/ampproject/amppackager.git my-amp-directory
    cd my-amp-directory
    make build
    
  3. Optionally, move the built amppkg wherever you like.

  4. Prepare a temporary certificate and private key pair to use for signing the exchange when testing your config. Follow WICG instructions to ensure compliance with the WICG certificate requirements.

  5. Create a file amppkg.toml. A minimal config looks like this:

    LocalOnly = true
    CertFile = 'path/to/fullchain.pem'
    KeyFile = 'path/to/privkey.pem'
    OCSPCache = '/tmp/amppkg-ocsp'
    
    [[URLSet]]
      [URLSet.Sign]
        Domain = "amppackageexample.com"
    

    More details can be found in amppkg.example.toml.

  6. amppkg -development

    If amppkg.toml is not in the current working directory, pass -config=/path/to/amppkg.toml.

Docker

Follow the instructions here on how to deploy a local Docker container.

Test your config

  1. Run Chrome with the following command line flags:
    alias chrome = [FULL PATH TO CHROME BINARY]
    PATH_TO_FULLCHAIN_PEM = [FULL PATH TO fullchain.pem]
    chrome --user-data-dir=/tmp/udd\
        --ignore-certificate-errors-spki-list=$(\
           openssl x509 -pubkey -noout -in $PATH_TO_FULLCHAIN_PEM |\
           openssl pkey -pubin -outform der |\
           openssl dgst -sha256 -binary | base64)\
        --enable-features=SignedHTTPExchange\
           'data:text/html,<a href="https://localhost:8080/priv/doc/https://amppackageexample.com/">click me'
    
  2. Open DevTools. Check 'Preserve log'.
  3. Click the click me link.
  4. Watch the URL transmogrify! Verify it came from an SXG by switching DevTools to the Network tab and looking in the Size column for (from signed-exchange) and in the Type column for signed-exchange. Click on that row and then click on the Preview tab, to see if there are any errors.

Demonstrate privacy-preserving prefetch

This step is optional; just to show how privacy-preserving prefetch works with SXGs.

  1. go get -u github.com/ampproject/amppackager/cmd/amppkg_dl_sxg.
  2. amppkg_dl_sxg https://localhost:8080/priv/doc/https://amppackageexample.com/
  3. Stop amppkg with Ctrl-C.
  4. go get -u github.com/ampproject/amppackager/cmd/amppkg_test_cache.
  5. amppkg_test_cache
  6. Open Chrome and DevTools, as above.
  7. Visit https://localhost:8000/. Observe the prefetch of /test.sxg.
  8. Click the link. Observe that the cached SXG is used.

Productionizing

For now, productionizing is a bit manual. The minimum steps are:

  1. Don't pass -development flag to amppkg. This causes it to serve HTTP rather than HTTPS, among other changes.

  2. Don't expose amppkg to the outside world; keep it on your internal network.

  3. Configure your TLS-serving frontend server to conditionally proxy to amppkg:

    1. If the URL starts with /amppkg/, forward the request unmodified.

    2. If the URL points to an AMP page and the AMP-Cache-Transform request header is present, rewrite the URL by prepending /priv/doc and forward the request.

      NOTE: If using nginx, prefer using proxy_pass with $request_uri, rather than using rewrite, as in this PR, to avoid percent-encoding issues.

    3. If at all possible, don't send URLs of non-AMP pages to amppkg; its transforms may break non-AMP HTML.

    4. DO NOT forward /priv/doc requests; these URLs are meant to be generated by the frontend server only.

  4. For HTTP compliance, ensure the Vary header set to AMP-Cache-Transform, Accept for all URLs that point to an AMP page, irrespective of whether the response is HTML or SXG. (SXG responses that come from amppkg will have the appropriate Vary header set, so it may only be necessary to explicitly set the Vary header for HTML responses.)

  5. Get an SXG cert from your CA. It must use an EC key with the prime256v1 algorithm, and it must have a CanSignHttpExchanges extension. One provider of SXG certs is DigiCert. You MUST use this in amppkg.toml, and MUST NOT use it in your frontend.

  6. Every 90 days or sooner, renew your SXG cert (per WICG/webpackage#383) and restart amppkg (per #93).

  7. Keep amppkg updated from releases (the default branch, so go get works) about every ~2 months. The wg-caching team will release a new version approximately this often. Soon after each release, Googlebot will increment the version it requests with AMP-Cache-Transform. Googlebot will only allow the latest 2-3 versions (details are still TBD), so an update is necessary but not immediately. If amppkg doesn't support the requested version range, it will fall back to serving unsigned AMP.

    To keep subscribed to releases, you can select "Releases only" from the "Watch" dropdown in GitHub, or use various tools to subscribe to the releases branch.

You may also want to:

  1. Launch amppkg as a restricted user.
  2. Save its stdout to a rotated log somewhere.
  3. Use the provided tools to verify that your published AMP documents are valid, for instance just before publication, or with a regular audit of a sample of documents. The transforms are designed to work on valid AMP pages, and may break invalid AMP in small ways.
  4. Setup monitoring of amppackager and related requests to AMP document server.

Once you've done the above, you should be able to test by launching Chrome without any command line flags. To test by visiting the packager URL directly, first add a Chrome extension to send an AMP-Cache-Transform: any request header. Otherwise, follow the above "Demonstrate privacy-preserving prefetch" instructions.

Security Considerations

Signed exchanges come with some security considerations that publishers should consider. A starting list of recommendations based on that:

  • Use different keys for the signed exchange cert and the TLS cert.
  • Only sign public content that's OK to be shared with crawlers.
  • Don't sign personalized content. (It's OK to sign content that includes static JS that adds personalization at runtime.)
  • Be careful when signing inline JS; if it includes a vulnerability, it may be possible for attackers to exploit it without intercepting the network path, for up to 7 days.

Testing productionization without a valid certificate

It is possible to test an otherwise fully production configuration without obtaining a certificate with the CanSignHttpExchanges extension. amppkg still needs to perform OCSP verification, so the Issuer CA must be valid (i.e. no self-signed certificates). e.g. You can use a certificate from Let's Encrypt.

Running amppkg with the -invalidcert flag will skip the check for CanSignHttpExchanges. This flag is not necessary when using the -development flag.

Chrome can be configured to allow these invalid certificates with the --ignore-certificate-errors-spki-list command line flag:

google-chrome --ignore-certificate-errors-spki-list=<hashes> --user-data-dir=<dir>

where <hashes> is a comma separated list of Base64-encoded SHA-256 SPKI Fingerprints and it is necessary to specify --user-data-dir with a valid or creatable directory <dir> when --ignore-certificate-errors-spki-list is used.

As an example, the hash for a PEM certificate can be obtained with OpenSSL:

openssl x509 -pubkey -noout -in mycert.crt | openssl pkey -pubin -outform der | openssl sha256 -binary | openssl base64

Redundancy

If you need to load balance across multiple instances of amppkg, you'll want your OCSPCache to be backed by a shared storage device (e.g. NFS). It doesn't need to be shared among all instances globally, but perhaps among all instances per datacenter. The reason for this is to reduce the number of OCSP requests amppkg needs to make, per OCSP stapling recommendations.

How will these web packages be discovered by Google?

Googlebot makes requests with an AMP-Cache-Transform header. Responses that are acceptable AMP SXGs will be eligible for display to SXG-supporting browsers, and the HTML payload will be extracted and eligible for use in the AMP viewer in other browsers.

Limitations

Currently, the packager will refuse to sign any AMP documents that hit the size limit of 4MB. You can monitor the size of your documents that have been signed, to see how close you are to the limit.

The packager refuses to sign any URL that results in a redirect. This is by design, as neither the original URL nor the final URL makes sense as the signed URL.

To account for possible clock skew in user agents, the packager back-dates packages by 24h, which means they effectively last only 6 days for most users.

This tool only packages AMP documents. To sign non-AMP documents, look at the commandline tools on which this was based, at https://github.com/WICG/webpackage/tree/master/go/signedexchange.

<amp-install-serviceworker> will fail inside of a signed exchange, due to a Chrome limitation. The recommendation is to ignore the console error, for now. This is because amp-install-serviceworker will still succeed in the unsigned AMP viewer case, and crawlers may reuse the contents of the signed exchange when displaying an AMP viewer to browser versions that don't support SXG.

<amp-script>

If you have any inline <amp-script>s (those with a script attribute), then the expiration of the SXG will be set based on the minimum max-age of those <amp-script>s, minus one day (due to backdating). If possible, prefer external <amp-script>s (those with a src attribute), which do not have this limitation.

If inline is necessary, you will need to weigh the security risks against the AMP Cache requirement for a minimum max-age of 345600 (4 days). For SXGs shorter than that, the Google AMP Cache will treat them as if unsigned (by showing an AMP Viewer).

How does amppackager process a document it cannot sign?

Packager will respond to every request with either a signed document, an unsigned document, or an error.

It will sign every document it can. It may, however, decide not to, for a number of reasons: the certificate may be invalid, the page may not be a valid AMP page, the page may not be an AMP page at all, the page may be 4MB or larger, etc.

If packager cannot sign the document but can fetch it, it will proxy the document unsigned.

If there was a problem with the gateway fetch request, or with the original request, packager will respond with an HTTP error, and log the problem to stdout.

You can monitor the packager's error rates, as well as the rates of signed vs unsigned documents, via the tools discussed in the next section.

Specifically, you can monitor the requests that resulted in a signed or an unsigned document via amppackager_signer_documents_total metric, and the ones that resulted in an error - via amppackager_http_duration_seconds_count metric.

Monitoring amppackager in production via its Prometheus endpoints

Once you've run the amppackager server in production, you may want to monitor its health and performance. You may also monitor the performance of the underlying requests to the AMP document server. You can monitor both servers via the Prometheus endpoints provided by amppackager. A few examples of questions you can answer:

  • Is amppackager up and running?
  • How many requests has it processed since it's been up?
  • What was the 0.9 percentile latency of handling those request?
  • How many of those requests have triggered a gateway request to the AMP document server?
  • For those gateway requests, what was the 0.9 percentile latency of the AMP document server?

You can perform one-off manual health inspections, visualize the real-time stats, set up alerts, and more. To learn what are all the things you can monitor, and how to do it, check the monitoring manual.

Local Transformer

The local transformer is a library within the AMP Packager that transforms AMP HTML for security and performance improvements. Ports of or alternatives to the AMP Packager will need to include these transforms.

More info here.

amppackager's People

Contributors

alin04 avatar amaltas avatar antiphoton avatar banaag avatar caoboxiao avatar ddlfg avatar gabbifish avatar gaul avatar gregable avatar honeybadgerdontcare avatar ithinkihaveacat avatar jridgewell avatar mattwomple avatar mdmower avatar michaelrybak avatar nainar avatar pierres avatar renovate[bot] avatar rsimha avatar shigeki avatar sisidovski avatar superq avatar tomokinat avatar twifkak 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

amppackager's Issues

Make it easier for new devs

  • Check in a self-signed cert/key pair and toml
  • Update CONTRIBUTING.md with instructions on running a dev server, lint/tests, dep ensure, etc.
  • Presubmit hook would be nice.

Add tests for parseUrls

Currently only tested indirectly in packager_test.go. This function should be tested directly, with a variety of urlSets and fetch/sign URLs, to cover all the combinations.

Figure out discovery

We need to decide how AMP packages should be discovered on the web. Options include <link rel=amppackage>, request headers, and sitemap.xml (or some combination).

Don't overwrite the Content-Type

If the packager happens to proxy invalid AMP, and an attacker captures such an SXG and serves it somewhere that doesn't valid, the page would have its charset misinterpreted.

Add support for validityUrl

Packager currently only provides a null validityUrl response for all signed exchanges. It would be nice to support validity updates, to save on network bandwidth when responding to intermediaries and to allow client-side reverification of signed exchanges as a downgrade mitigation.

Note that this will require a refetch of the document to get the message to sign, unless a cache is added. If a cache is added, it should obey the usual HTTP caching semantics re: freshness and validation.

Add nosniff header

Add X-Content-Type-Options: nosniff to the SXG outer response headers.

Add support for keyless signing

Add an option to use a remote signing oracle to sign messages, rather than needing filesystem access to the key. The Go Keyless client library will probably be of use, here.

Fix cert-url expiry

certcache.go should serve the cert-chain+cbor with a max-age corresponding to the OCSP midpoint.

Serve v=b1 signed exchanges

This is a tracking bug to make sure the AMP packager serves valid signed exchanges per the evolving v=b1 spec. Support for v=b0 would need to co-exist for a few months.

Spec changes being drafted here: WICG/webpackage#232

At present, these Chromium changes seem relevant:

(I may eventually split out bugs for larger subprojects, like OCSP stapling.)

See also http://b/92515679.

Error out if TOML includes any unknown fields

Currently, the toml parser just silently ignores any fields that don't match the struct. This means that typos are hard to diagnose, and backwards-incompatible changes to the config will require special care to notify existing users.

Don't follow redirects in fetchResp

If the fetch redirects to another URL, the packager will follow the redirect(s), but sign it with the original request URL. This has the following problems (at least):

  • relative URLs included in the payload of the final response may be broken
  • the final URL may not be one that's intended for a signed exchange (e.g. a login server on a different domain)

When the packager gets a 30x, it should simply respond with that instead of following it and signing the result.

usqp= in signed URLs in sign-only flow

When [URLSet.Fetch] is not configured, then fetch and sign are the same URL object, so the destructive modifications that fetchURL() does to the query end up affecting the signed URL, too.

Support multiple certificate pairs

It may be useful for a single packager instance to sign for multiple domains that are authenticated by different certs. (This should be an uncommon case, though, as it is very simple and possibly more secure to run different instances each with access to only one certificate.)

Automatically fetch SCT

https://github.com/WICG/webpackage/pull/267/files added some instructions on submitting a cert to CT and getting an SCT in return, in cases where the CA has not already attached it. This would be nice for the packager to support automatically, though not strictly necessary. At the very least, the documentation should be updated to include a reference to this.

Support signing over OCSP responses

WICG/webpackage#121 will change the SXG signed message to include the OCSP response attached to the cert-chain+cbor. This means that:

  1. Every ~3.5 days, the cert-url will change, to reflect the different OCSP response attached. (Or else old SXGs won't validate any more.)
  2. When signing a document, the packager must request the freshest cert-url from the certcache.

Support short-term cert expiry

Currently, amppkg only loads the cert file at startup. If it expires while the packager is running, the packager continues to sign with it and serve it. Instead, it should attempt to reload automatically starting a few days before expiry, and continuing at some regular interval until no longer imminently expiring. If the cert is expired, it should stop signing exchanges, and log a warning.

In addition, it should serve the cert-url with an http expiry no longer than the cert expiry (as a follow-up to #85).

Improve documentation

Rewrite the documentation to be action-oriented -- e.g. start with running the packager, and then move backwards up the chain to adding a FE and all that.

Strip javascript in golang transformer

Users of the packager may mistakenly transform and sign non-amp content. The AMP Cache will reject this, but for security we want some light protections against this content being usable. This issue tracks removing non-amp javascript from the document in a new transformer.

The steps we should take are:

For each <script> tag on the page, if any one of of the following is true:

  • It has a src attribute whose value is not prefixed by https://cdn.ampproject.org/ (case-insensitive match).
  • It has no src attribute and no type attribute (case-insensitive match).
  • It has a type attribute whose value is neither application/json nor application/ld+json (case-insensitive match on both name and value).

Then, remove the <script> tag and all descendant nodes of <script> tag, including text / cdata nodes.

For example:

  • <script async src="https://cdn.ampproject.org/v0.js"> should not be removed
  • <script async custom-element='amp-analytics' src='https://cdn.ampproject.org/v0/amp-analytics-0.1.js'> should not be removed.
  • <script src='http://example.com/example.js'> should be removed.
  • <script>foo</script> should be removed
  • <script type=application/javascript>foo</script> should be removed
  • <script type=application/json>foo</script>should not be removed
  • <script type=application/json src="https://cdn.ampproject.org/v0.js">

For every tag on the page, if the tag has an attribute with a case-insensitive prefix of on followed by another alphabetic character ([A-Za-z]), then remove that attribute. For example:

  • on should not be removed.
  • on-foo should not be removed
  • onfoo should be removed

rtv support

Periodically (hourly?) poll to get the latest rtv (and css url), store in memory.

Pass these values into the local transformer library for writing the correct rtv script and css.

Add advice re valid AMP

Amend the README to advise that publishers only package AMP documents, and that they audit those documents for validity offline (e.g. at publication time, or a weekly cronjob that audits a random 1%).

Automate best practices for production

This could be a collection of scripts, or packages of various formats (Docker, Flatpak, .deb, etc.). Broad coverage of most of the production environments probably necessitates multiple formats, though we should prefer a solution that covers as many as possible in as few variants as possible. This will reduce the cost of maintenance and the chance of error in one or more of them. Googlers, see go/amp-packager-deployment-requirements for more info.

Improve test coverage

At the very least, go over the code, figure out what tests need adding and file bugs for them.

Allow non-transformed AMP

Provide a config flag to allow non-transformed AMP to be served (i.e. not going through the AMP CDN). This is just for debugging.

Improve error messages

Improve the error messages such that they are actionable by people who don't know code. Currently, they're pretty cryptic and mostly useful for devs.

Add `Link: rel=preload`s

Add relevant preloads as determined based on the fetch response body. This is dependent on the implementation of the local transformer.

Return unsigned content on fetch validation error

If the fetchResp is not valid for packaging (either via validateFetch or because of stateful headers), instead of returning an error code, the packager should simply proxy the content unsigned. This is a friendlier error response.

Perform light AMP validation

Transforms may have unintended effects on invalid documents. There may be cases where the SXG is fetched and served by third parties without validation. Since full validation at serve time is too expensive, it should perform some light validation; at least to verify that the document intends to be AMP.

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.