Skip to content

Commit e6f1806

Browse files
committed
Add a CSP example
1 parent 514f845 commit e6f1806

File tree

2 files changed

+158
-0
lines changed

2 files changed

+158
-0
lines changed

examples/index.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,11 @@
5757
<li><a href="/recaptcha-v3-request-scores.php">Request scores</a></li>
5858
</ul>
5959
</li>
60+
<li><h2>General</h2>
61+
<ul>
62+
<li><a href="/recaptcha-content-security-policy.php">Content Security Policy</a></li>
63+
</ul>
64+
</li>
6065
</ul>
6166
</main>
6267

Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
<?php
2+
/**
3+
* @copyright Copyright (c) 2015, Google Inc.
4+
* @link https://www.google.com/recaptcha
5+
*
6+
* Permission is hereby granted, free of charge, to any person obtaining a copy
7+
* of this software and associated documentation files (the "Software"), to deal
8+
* in the Software without restriction, including without limitation the rights
9+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10+
* copies of the Software, and to permit persons to whom the Software is
11+
* furnished to do so, subject to the following conditions:
12+
*
13+
* The above copyright notice and this permission notice shall be included in
14+
* all copies or substantial portions of the Software.
15+
*
16+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22+
* THE SOFTWARE.
23+
*/
24+
require __DIR__ . '/appengine-https.php';
25+
26+
// Initiate the autoloader. The file should be generated by Composer.
27+
// You will provide your own autoloader or require the files directly if you did
28+
// not install via Composer.
29+
require_once __DIR__ . '/../vendor/autoload.php';
30+
31+
// This example shows the use of a Content Security Policy
32+
// https://developers.google.com/web/fundamentals/security/csp/
33+
34+
// First we generate a pseudorandom nonce for each included or inline script
35+
// Nonce for including the reCAPTCHA library
36+
$recaptchaNonce = base64_encode(openssl_random_pseudo_bytes(16));
37+
// Nonce for our inline code
38+
$inlineNonce = base64_encode(openssl_random_pseudo_bytes(16));
39+
40+
// Note: this is not related to reCAPTCHA, but if you enable a CSP like this
41+
// you either need to include either a nonce or appropriate domain for any
42+
// scripts on the page.
43+
// Nonce for including Google Analytics library.
44+
$gaIncNonce = base64_encode(openssl_random_pseudo_bytes(16));
45+
// Nonce for firing the Google Analytics call
46+
$gaCfgNonce = base64_encode(openssl_random_pseudo_bytes(16));
47+
48+
// Send the CSP header
49+
// Try commenting out the various lines to see what effect it has
50+
51+
// NOTE: Always test your policy Content-Security-Policy-Report-Only first to
52+
// ensure you're not blocking any critical functionality. CSP is an important
53+
// security feature but you can break entire sections of your site if you
54+
// implement it incorrectly.
55+
header(
56+
"Content-Security-Policy: "
57+
."default-src 'none'; " // By default we will deny everything
58+
59+
."script-src "
60+
." 'nonce-".$recaptchaNonce."' " // nonce allowing the reCAPTCHA library to be included
61+
." 'nonce-".$inlineNonce."' " // nonce for inline page code
62+
." 'nonce-".$gaIncNonce."' 'nonce-".$gaCfgNonce."'; " // nonces for other scripts
63+
64+
."img-src https://www.gstatic.com/recaptcha/ https://www.google-analytics.com; " // allow images from these URLS
65+
."frame-src https://www.google.com/; " // allow frames from this URL
66+
67+
."style-src 'self'; " // allow style from our own origin
68+
."connect-src 'self'; " // allow the fetch calls to our own origin
69+
);
70+
71+
// Register API keys at https://www.google.com/recaptcha/admin
72+
$siteKey = '';
73+
$secret = '';
74+
75+
// Copy the config.php.dist file to config.php and update it with your keys to run the examples
76+
if ($siteKey == '' && is_readable(__DIR__ . '/config.php')) {
77+
$config = include __DIR__ . '/config.php';
78+
$siteKey = $config['v3']['site'];
79+
$secret = $config['v3']['secret'];
80+
}
81+
82+
// reCAPTCHA supports 40+ languages listed here: https://developers.google.com/recaptcha/docs/language
83+
$lang = 'en';
84+
85+
?>
86+
<!DOCTYPE html>
87+
<html lang="en">
88+
<meta charset="UTF-8">
89+
<meta name="viewport" content="width=device-width,height=device-height,minimum-scale=1">
90+
<link rel="shortcut icon" href="https://www.gstatic.com/recaptcha/admin/favicon.ico" type="image/x-icon"/>
91+
<link rel="canonical" href="https://recaptcha-demo.appspot.com/recaptcha-content-security-policy.php">
92+
<script type="application/ld+json">{ "@context": "http://schema.org", "@type": "WebSite", "name": "reCAPTCHA demo - Content Security Policy", "url": "https://recaptcha-demo.appspot.com/recaptcha-content-security-policy.php" }</script>
93+
<meta name="description" content="reCAPTCHA demo - Content Security Policy" />
94+
<meta property="og:url" content="https://recaptcha-demo.appspot.com/recaptcha-content-security-policy.php" />
95+
<meta property="og:type" content="website" />
96+
<meta property="og:title" content="reCAPTCHA demo - Content Security Policy" />
97+
<meta property="og:description" content="reCAPTCHA demo - Content Security Policy" />
98+
<link rel="stylesheet" type="text/css" href="/examples.css">
99+
<title>reCAPTCHA demo - Content Security Policy</title>
100+
<header>
101+
<h1>reCAPTCHA demo</h1><h2>Content Security Policy</h2>
102+
<p><a href="/">↤ Home</a></p>
103+
</header>
104+
<main>
105+
<?php
106+
if ($siteKey === '' || $secret === ''):
107+
?>
108+
<h2>Add your keys</h2>
109+
<p>If you do not have keys already then visit <kbd> <a href = "https://www.google.com/recaptcha/admin">https://www.google.com/recaptcha/admin</a></kbd> to generate them. Edit this file and set the respective keys in <kbd>$siteKey</kbd> and <kbd>$secret</kbd>. Reload the page after this.</p>
110+
<?php
111+
else:
112+
?>
113+
<p>This example is sending the <kbd>Content-Security-Policy</kbd> header. Look at the source and inspect the network tab for this request to see what's happening. The reCAPTCHA v3 API is being called here, however you can use the same approach for the v2 API calls as well.</p>
114+
<p><strong>NOTE:</strong>This is a sample implementation, the score returned here is not a reflection on your Google account or type of traffic. In production, refer to the distribution of scores shown in <a href="https://www.google.com/recaptcha/admin" target="_blank">your admin interface</a> and adjust your own threshold accordingly. <strong>Do not raise issues regarding the score you see here.</strong></p>
115+
<ol id="recaptcha-steps">
116+
<li class="step0">reCAPTCHA script loading</li>
117+
<li class="step1 hidden"><kbd>grecaptcha.ready()</kbd> fired, calling <pre>grecaptcha.execute('<?php echo $siteKey; ?>', {action: 'examples/csp'})'</pre></li>
118+
<li class="step2 hidden">Received token from reCAPTCHA service, sending to our backend with:
119+
<pre class="token">fetch('/recaptcha-v3-verify.php?token=abc123</pre></li>
120+
<li class="step3 hidden">Received response from our backend: <pre class="response">{"json": "from-backend"}</pre></li>
121+
</ol>
122+
<p><a href="/recaptcha-content-security-policy.php">⟳ Try again</a></p>
123+
124+
<!-- Add the nonce for our inline script to this tag -->
125+
<script nonce="<?php echo $inlineNonce; ?>">
126+
var onloadCallback = function() {
127+
const steps = document.getElementById('recaptcha-steps');
128+
grecaptcha.ready(function() {
129+
document.querySelector('.step1').classList.remove('hidden');
130+
grecaptcha.execute('<?php echo $siteKey; ?>', {action: 'examples/csp'}).then(function(token) {
131+
document.querySelector('.token').innerHTML = 'fetch(\'/recaptcha-v3-verify.php?action=examples/csp&token=\'' + token;
132+
document.querySelector('.step2').classList.remove('hidden');
133+
134+
fetch('/recaptcha-v3-verify.php?action=examples/csp&token='+token).then(function(response) {
135+
response.json().then(function(data) {
136+
document.querySelector('.response').innerHTML = JSON.stringify(data, null, 2);
137+
document.querySelector('.step3').classList.remove('hidden');
138+
});
139+
});
140+
});
141+
});
142+
};
143+
</script>
144+
<!-- Add the nonce value for the reCAPTCHA library to its script tag -->
145+
<script async defer src="https://www.google.com/recaptcha/api.js?render=<?php echo $siteKey; ?>&onload=onloadCallback" nonce="<?php echo $recaptchaNonce; ?>"></script>
146+
147+
<?php
148+
endif;?>
149+
</main>
150+
151+
<!-- Google Analytics - adding both nonces here for the library and the inline code -->
152+
<script async defer src="https://www.googletagmanager.com/gtag/js?id=UA-123057962-1" nonce="<?php echo $gaIncNonce; ?>"></script>
153+
<script async nonce="<?php echo $gaCfgNonce; ?>">window.dataLayer = window.dataLayer || []; function gtag(){dataLayer.push(arguments);} gtag('js', new Date()); gtag('config', 'UA-123057962-1');</script>

0 commit comments

Comments
 (0)