javascripthttpgoogle-ads-apicontent-security-policy

Google Adwords CSP (content security policy) img-src


What domains/protocols in the img-src directive of the Content-Security-Policy header are required to allow Google AdWords conversion tracking?

From testing, when we call google_trackConversion, it looks like the browser creates an image with a src that follows a chain of 302 redirects between various domains...

www.googleadservices.com ->
googleads.g.doubleclick.net ->
www.google.com ->
www.google.co.uk

The final .co.uk looks suspicious to me. As we're testing from the UK, we're concerned that tracking called from other countries will redirect to other domains.

What is the complete list of domains that we need to open up in order for the tracking to work?


As requested in comments, an example path component of the first request is:

pagead/conversion/979383382/?random=1452934690748&cv=8&fst=1452934690748&num=1&fmt=3&label=jvoMCNP4umIQ1uiA0wM&guid=ON&u_h=1080&u_w=1920&u_ah=1033&u_aw=1920&u_cd=24&u_his=18&u_tz=0&u_java=false&u_nplug=5&u_nmime=7&frm=0&url=https%3A//beta.captevate.com/payment%3Flevel%3Da00&async=1

and repeating the conversion a second time, the path component of the first request is

pagead/conversion/979383382/?random=1452934959209&cv=8&fst=1452934959209&num=1&fmt=3&label=jvoMCNP4umIQ1uiA0wM&guid=ON&u_h=1080&u_w=1920&u_ah=1033&u_aw=1920&u_cd=24&u_his=26&u_tz=0&u_java=false&u_nplug=5&u_nmime=7&frm=0&url=https%3A//beta.captevate.com/payment%3Flevel%3Da00&async=1

I used a free VPN service to connect from a couple of countries (Netherlands and Singapore), and the last redirect doesn't occur: the final request to www.google.com is a 200. However, I obviously haven't tried connected from every country, so my original question stands.


Solution

  • Unfortunately, there aren't many ways around this. Resources require either whitelisting (in the case of remote resources, like this one) or inlining tricks (i.e. nonce or sha256-...) when CSP is active. At the end of the day, though, CSP can probably still make your site safer and protect most resources.

    Depending on what you are trying to do, though, you may still be able to achieve your goal.

    Here are some options:

    1. Whitelist all images.

      Of course, you could simply place a "*" in your img-src directive, but I imagine you already know that and are choosing not to because it defeats CSP's protection for images.

    2. Load the image via alternate means.

      If all you are after is specifically locking down images, and, say, don't care so much about XMLHttpRequest, you could load the pixel via POST or even via a <script> tag with a custom type (using the AdWords image tag tracking method). This takes advantage of the fact that Google only needs the browser to complete the HTTP request/response (and redirect) cycle for analytics purposes, and you don't really care about parsing or executing the resulting content, which is a 1x1 transparent pixel anyways. This allows you to lock down your img-src directive (if that is indeed your goal) while still allowing whatever domain Google would like to use for redirects.

      I know this only moves your problem, but it's useful if your main threat is malicious images.

    3. Place all Google domains in your img-src.

      As suggested below. Header lengths will be a problem (even if the specs say you're fine, implementors are not always so generous), and more importantly, you may encounter spurious failures as Google changes their list of domains, which is certainly not a public or easily noticeable action (besides your ad conversions not coming through!). Since I imagine your job isn't to update that list constantly, you probably don't want to go with this option.

    4. Report failures for a few months and then roll with it.

      Because CSP supports reporting URIs and the Content-Security-Policy-Report-Only variant, you can roll it out in report-only mode and wait for reports to come in. If you already have good data about your userbase (and it doesn't change much), this can be a good option - once you see those reports stabilize on a list of domains, seal it in a regular CSP header. Optionally, you can place a reporting URI on the final header to catch any additional failures. The downside of this strategy, of course, is that you don't get protection while in report-only mode, and when you switch to enforcing it, failures cause lost conversion data and you're playing catch up.

    5. Static pixel with reverse proxy

      Okay. Well, with the above options not being so great (I admit it), it's time to think outside the box. The problem here is that HTTP optimization techniques applied by Google (sharding/geo-pinning domains) are at odds with good security practice (i.e. CSP). The root cause of the domain ambiguity is the client's geographic location, so why not pin it yourself?

    Assuming you have advanced control of your own HTTP server, you could use the static pixel approach for tracking and proxy the request yourself, like so:

    User ---> GET http://your-page/
    
    User <--- <html>...
              pixel: http://your-page/pixel?some=params
    
    User ---> http://your-page/pixel?some=params
              ---> fetch http://googleads.g.doubleclick.net/pagead/viewthroughconversion/12345/?some=params
              <--- redirect to http://google.com, or http://google.co.uk
    User <--- return redirect
    

    Using a static pixel (like approach #2) and putting your proxy, say, in the US or UK should ensure that the source IP is geographically pinned there, and Google's anycast frontend should route you to a stable endpoint. Placing a proxy in between the user and Google also gives you a chance to force-rewrite the redirect if you want to.

    To simplify proxy setup (and add some performance spice), you could opt for something like Fastly with Origin Shielding instead of building it yourself. If you add the DoubleClick backend and proxy from there, you can pin the originating requests from the CDN to come only from a certain geographic region. Either way, your user should see a stable set of redirects, and you can trim down that list of Google domains to just img-src 'self' *.google.com *.doubleclick.net *.googleadservices.net.

    Edit: It is also worth noting that Fastly (and a growing list of other CDN providers) peer directly with Google Cloud at a few of their Points-of-Presence, offering an optimized path into Google's networks for your proxied traffic.