CORS dalam AMP
Banyak ekstensi dan komponen AMP memanfaatkan endpoint jarak jauh dengan menggunakan permintaan Berbagi Sumber Daya Lintas Asal (CORS). Dokumen ini menjelaskan aspek-aspek kunci menggunakan CORS dalam AMP. Untuk mempelajari CORS sendiri, kunjungi Spek W3 CORS.
- Mengapa saya membutuhkan CORS untuk asal (origin) saya sendiri?
- Memanfaatkan cookie untuk permintaan CORS
-
Mengapa saya membutuhkan CORS untuk asal (origin) saya sendiri?
Anda mungkin bingung mengapa membutuhkan CORS untuk permintaan ke asal Anda sendiri, mari kita bahas.
Komponen AMP yang mengambil data dinamis (cth., amp-form, amp-list, dll.) membuat permintaan CORS ke endpoint jarak jauh untuk mengambil data. Jika halaman AMP Anda menyertakan komponen yang seperti itu, Anda perlu menangani CORS agar permintaan tersebut tidak gagal.
Mari kita gambarkan dengan contoh:
Anggap bahwa Anda mempunyai halaman AMP yang mencantumkan produk beserta harganya. Untuk memperbarui harga pada halaman tersebut, pengguna mengeklik sebuah tombol, dan ini akan mengambil harga terbaru dari endpoint JSON (dilakukan melalui komponen amp-list). JSON itu di domain Anda.
Baik, jadi halaman itu ada di domain saya dan JSON tersebut ada di domain saya . Saya tidak melihat ada masalah!
Ah, tetapi bagaimana pengguna Anda sampai ke halaman AMP Anda? Apakah karena halaman di cache yang mereka akses? Kemungkinan besar bahwa pengguna Anda tidak mengakses halaman AMP secara langsung, tetapi menemukan halaman Anda melalui platform lain. Contohnya: Google Search menggunakan Cache AMP Google untuk merender halaman AMP dengan cepat; ini adalah halaman yang disimpan di cache yang disajikan dari Cache AMP Google, dan ini adalah domain yang berbeda. Saat pengguna Anda mengeklik tombol untuk memperbarui harga pada halaman Anda, halaman AMP di dalam cache mengirimkan permintaan ke domain asal Anda untuk mendapatkan harga, dan ini adalah ketidakcocokan antara asal (cache -> domain asal). Untuk memungkinkan permintaan lintas asal seperti ini, Anda harus menangani CORS, jika tidak, permintaan akan gagal.
Baik, jadi saya harus bagaimana?
- Untuk halaman AMP yang mengambil data dinamis, pastikan Anda menguji versi cache halaman tersebut; jangan cuma uji di domain Anda sendiri. (Kunjungi bagian Menguji CORS dalam AMP di bawah ini)
- Ikuti instruksi di dalam dokumen ini untuk menangani tanggapan dan permintaan CORS.
Memanfaatkan cookie untuk permintaan CORS
Kebanyakan komponen AMP yang menggunakan permintaan CORS akan secara otomatis menetapkan mode kredensial atau mengizinkan penulis untuk memilih mengaktifkannya. Contohnya: komponen amp-list
mengambil konten dinamis dari endpoint JSON CORS, dan mengizinkan penulis untuk menetapkan mode kredensial melalui atribut credentials
.
Contoh: Termasuk konten yang dipersonalisasi di dalam amp-list melalui cookie
<amp-list credentials="include" src="<%host%>/json/product.json?clientId=CLIENT_ID(myCookieId)" > <template type="amp-mustache"> Your personal offer: ${{price}} </template> </amp-list>
Dengan menentukan mode kredensial, asal (origin) dapat menyertakan cookie di dalam permintaan CORS dan juga menempatkan cookie sebagai tanggapan (tergantung pembatasan cookie pihak ketiga).
Pembatasan cookie pihak ketiga
Pembatasan cookie pihak ketiga yang sama dengan yang ditentukan di browser juga berlaku pada permintaan CORS berkredensial di AMP. Pembatasan ini tergantung browser dan platform, namun bagi beberapa browser, asal hanya dapat menempatkan cookie jika pengguna sebelumnya telah mengunjungi asal di jendela (atas) pihak ke-1. Atau, dengan kata lain, hanya setelah pengguna telah langsung mengunjungi situs web asal tersebut. Oleh karena itu, layanan yang diakses melalui CORS tidak dapat menganggap akan dapat menempatkan cookie sebagai default.
Keamanan CORS dalam AMP
Untuk memastikan tanggapan dan permintaan yang valid dan aman untuk halaman AMP Anda, Anda harus:
Jika Anda menggunakan Nodus di backend, Anda dapat menggunakan
middleware CORS AMP, yang merupakan bagian dari Kotak Alat AMP.
Memverifikasi permintaan CORS
Saat endpoint Anda menerima permintaan CORS:
- Verifikasi bahwa tajuk
Origin
CORS adalah asal yang diizinkan (asal penayang + cache AMP). - Jika tidak ada tajuk Asal, periksa apakah permintaan tersebut mempunyai asal yang sama (melalui
AMP-Same-Origin
).
1) Mengizinkan permintaan untuk asal CORS yang spesifik
Endpoint CORS menerima asal peminta melalui tajuk HTTP Origin
. Endpoint hanya boleh mengizinkan permintaan dari: (1) asal penayang sendiri; dan (2) setiap asal
cacheDomain
yang tercantum di https://cdn.ampproject.org/caches.json.
Contohnya: endpoint harus mengizinkan permintaan dari:
- Google AMP Cache subdomain:
https://<publisher's domain>.cdn.ampproject.org
(for example,https://nytimes-com.cdn.ampproject.org
)
2) Mengizinkan permintaan dari asal yang sama
Untuk permintaan asal yang sama di mana tajuk Origin
tidak ada, AMP menetapkan tajuk kustom berikut ini:
AMP-Same-Origin: true
Tajuk kustom ini dikirimkan oleh Runtime AMP saat permintaan XHR dilakukan untuk asal yang sama (yaitu, dokumen yang disajikan dari URL non-cache). Izinkan permintaan yang mengandung tajuk AMP-Same-Origin:true
.
Mengirimkan tajuk tanggapan CORS
Setelah memverifikasi permintaan CORS, hasil tanggapan HTTP harus mengandung tajuk berikut ini:
Akses-Kontrol-Izinkan-Asal: <origin>
Tajuk ini adalah persyaratan Spek W3 CORS Spec, di mana origin
merujuk asal peminta yang diizinkan melalui tajuk permintaan CORS Origin
(contohnya, "https://<publisher's subdomain>.cdn.ampproject.org"
).
Walaupun spek W3 CORS mengizinkan nilai *
dihasilkan di dalam tanggapan, untuk keamanan yang lebih baik, Anda sebaiknya:
- Jika tajuk
Origin
ada, validasi dan cerminkan nilai tajukOrigin
.
Memproses permintaan perubahan status
Sebelum memproses permintaan yang dapat mengubah status sistem Anda (contohnya: pengguna yang berlangganan atau berhenti berlangganan dari daftar pengiriman surat), periksa yang berikut ini:
Jika tajuk Origin
sudah ditentukan:
- Jika asal tidak sesuai dengan salah satu dari nilai-nilai berikut ini, hentikan dan buat tanggapan eror:
<publisher's domain>.cdn.ampproject.org
- asal penayang (alias domain Anda)
di mana *
mewakili kecocokan karakter pengganti, dan bukan tanda bintang yang sesungguhnya ( * ).
- Jika tidak, proses permintaan tersebut.
Jika tajuk Origin
BELUM ditentukan:
- Verifikasi bahwa permintaan tersebut mengandung tajuk
AMP-Same-Origin: true
. Jika permintaan tidak mengandung tajuk ini, hentikan dan buat tanggapan eror. - Jika tidak, proses permintaan tersebut.
Uraian contoh: Menangani tanggapan dan permintaan CORS
Ada dua skenario yang harus diperhitungkan dalam permintaan CORS ke endpoint Anda:
- Permintaan dari asal yang sama.
- Permintaan dari asal di cache (dari Cache AMP).
Mari kita bahas kedua skenario ini disertai contoh. Di dalam contoh ini, kita mengelola situs example.com
yang menjadi host halaman AMP berjudul article-amp.html.
Halaman AMP tersebut berisi amp-list
untuk mengambil data dinamis dari berkas data.json
yang juga dikelola di example.com
. Kita ingin memproses permintaan ke berkas data.json
kita yang berasal dari halaman AMP kita. Permintaan ini bisa berasal dari halaman AMP pada asal yang sama (non-cache) atau dari halaman AMP di asal yang berbeda (di cache).
Asal yang diizinkan
Berdasarkan apa yang kita ketahui tentang CORS dan AMP (dari Memverifikasi permintaan CORS di atas), untuk contoh kita, kita akan mengizinkan permintaan dari domain berikut ini:
example.com
--- Domain penayangexample-com.cdn.ampproject.org
--- Subdomain Cache AMP Google
Tajuk tanggapan untuk permintaan yang diizinkan
Untuk permintaan dari asal yang diizinkan, tanggapan kita akan berisi tajuk berikut ini:
Access-Control-Allow-Origin: <origin>
Ini adalah tajuk tanggapan tambahan yang mungkin kita sertakan di dalam tanggapan CORS kita:
Access-Control-Allow-Credentials: true Content-Type: application/json Access-Control-Max-Age: <delta-seconds> Cache-Control: private, no-cache
Logika CORS semu
Logika kita untuk menangani tanggapan dan permintaan CORS dapat disederhanakan menjadi kode semu berikut ini:
IF CORS header present IF origin IN allowed-origins allow request & send response ELSE deny request ELSE IF "AMP-Same-Origin: true" allow request & send response ELSE deny request
Kode sampel CORS
Berikut ini adalah fungsi JavaScript sampel yang dapat kita gunakan untuk menangani tanggapan dan permintaan CORS:
function assertCors(req, res, opt_validMethods, opt_exposeHeaders) { var unauthorized = 'Unauthorized Request'; var origin; var allowedOrigins = [ 'https://example.com', 'https://example-com.cdn.ampproject.org', 'https://cdn.ampproject.org', ]; var allowedSourceOrigin = 'https://example.com'; //publisher's origin // If same origin if (req.headers['amp-same-origin'] == 'true') { origin = sourceOrigin; // If allowed CORS origin & allowed source origin } else if ( allowedOrigins.indexOf(req.headers.origin) != -1 && sourceOrigin == allowedSourceOrigin ) { origin = req.headers.origin; } else { res.statusCode = 403; res.end(JSON.stringify({message: unauthorized})); throw unauthorized; } res.setHeader('Access-Control-Allow-Credentials', 'true'); res.setHeader('Access-Control-Allow-Origin', origin); }
Catatan: : Untuk mengetahui sampel kode yang berhasil, kunjungi amp-cors.js.
Skenario ke-1: Mendapatkan permintaan dari halaman AMP pada asal yang sama
Di dalam skenario berikut ini, halaman article-amp.html
meminta berkas data.json
; asalnya sama.
Jika kita memeriksa permintaan ini, kita akan menemukan:
Request URL: https://example.com/data.json Request Method: GET AMP-Same-Origin: true
Karena permintaan ini dari asal yang sama, tidak ada tajuk Origin
, tetapi tajuk permintaan AMP kustom AMP-Same-Origin: true
ada. Kita dapat mengizinkan permintaan ini karena asalnya sama (https://example.com
).
Tajuk tanggapan kita akan berupa:
Access-Control-Allow-Credentials: true Access-Control-Allow-Origin: https://example.com
Skenario ke-2: Mendapatkan permintaan dari halaman AMP di cache
Di dalam skenario berikut ini, halaman article-amp.html
di Cache AMP Google meminta berkas data.json
; asalnya berbeda.
Jika kita memeriksa permintaan ini, kita akan menemukan:
Request URL: https://example.com/data.json Request Method: GET Origin: https://example-com.cdn.ampproject.org
Karena permintaan ini berisi tajuk Origin
, kita akan memverifikasi bahwa ini dari asal yang diizinkan. Kita dapat mengizinkan permintaan ini karena dari asal yang diizinkan.
Tajuk tanggapan kita akan berupa:
Access-Control-Allow-Credentials: true Access-Control-Allow-Origin: https://example-com.cdn.ampproject.org
Bekerja dengan font di cache
Cache AMP Google menyimpan, font, gambar, dan dokumen HTML untuk mengoptimalkan kecepatan halaman AMP. Walaupun membuat halaman AMP menjadi cepat, kita juga perlu berhati-hati dalam mengamankan sumber daya yang disimpan di cache. Kita akan melakukan perubahan tentang cara cache AMP menanggapi sumber daya yang disimpan di cache, umumnya untuk font, dengan memperhatikan nilai Access-Control-Allow-Origin
asal.
Perilaku sebelumnya (sebelum Oktober 2019)
Saat sebuah halaman AMP memuat atribut https://example.com/some/font.ttf
dari @font-face src
, Cache AMP akan menyimpan berkas font dan menyajikan sumber daya sebagaimana di bawah ini dengan memiliki karakter pengganti Access-Control-Allow-Origin
.
- URL
https://example-com.cdn.ampproject.org/r/s/example.com/some/font.tff
- Akses-Kontrol-Izinkan-Asal: *
Perilaku baru (Oktober 2019 dan setelahnya)
Walaupun penerapan saat ini diizinkan, namun ini dapat menyebabkan penggunaan yang tidak terduga atas font dari situs-situs lintas asal. Di dalam perubahan ini, Cache AMP akan mulai menanggapi dengan nilai Access-Control-Allow-Origin
yang persis sama dengan yang ditanggapi server asal. Agar dapat memuat font dari dokumen AMP di cache, Anda perlu menerima asal Cache AMP melalui tajuk.
Penerapan sampel akan berupa:
function assertFontCors(req, res, opt_validMethods, opt_exposeHeaders) { var unauthorized = 'Unauthorized Request'; var allowedOrigins = [ 'https://example.com', 'https://example-com.cdn.ampproject.org', ]; // If allowed CORS origin if (allowedOrigins.indexOf(req.headers.origin) != -1) { res.setHeader('Access-Control-Allow-Origin', req.headers.origin); } else { res.statusCode = 403; res.end(JSON.stringify({message: unauthorized})); throw unauthorized; } }
Sebagai contoh, jika Anda ingin memuat /some/font.ttf dalam https://example.com/amp.html
, server asal harus menanggapi dengan tajuk Akses-Kontrol-Izinkan-Asal (Access-Control-Allow-Origin) seperti di bawah ini.
Access-Control-Allow-Origin
, cache AMP juga akan memantulkan nilai tersebut, artinya akan menanggapinya dengan Access-Control-Allow-Origin: *
. Jika Anda sudah menerapkan pengaturan ini, tidak perlu mengubah apa pun. Kami berencana menerapkan perubahan ini pada sekitar pertengahan Oktober 2019 dan mengharapkan setiap penayang AMP menggunakan font yang dikelola sendiri untuk memeriksa apakah terkena pengaruhnya.
Rencana pelaksanaan
- 30-09-2019: rilis yang berisi kontrol yang lebih tepat tentang domain mana yang mendapatkan penerapan perubahan ini. Bentuk ini harus digulirkan sepanjang minggu ini.
- 07-10-2019: domain uji akan diaktifkan untuk pengujian manual.
- 14-10-2019: (tetapi tergantung bagaimana hasil pengujian): fitur akan digulirkan secara umum.
Ikuti masalah yang terkait di sini.
Menguji CORS dalam AMP
Saat Anda menguji halaman AMP Anda, pastikan untuk menyertakan uji dari versi cache halaman AMP Anda.
Memverifikasi halaman melalui URL cache
Untuk memastikan halaman AMP Anda di cache merender dan berfungsi dengan benar:
- Dari browser Anda, buka URL yang akan digunakan Cache AMP untuk mengakses halaman AMP Anda. Anda dapat menentukan format URL cache dari alat ini di AMP berdasarkan Contoh..
Contohnya:
- URL:
https://amp.dev/documentation/guides-and-tutorials/start/create/
- Format URL Cache AMP:
https://www-ampproject-org.cdn.ampproject.org/c/s/www.ampproject.org/docs/tutorials/create.html
- Buka alat pengembangan browser Anda dan pastikan bahwa tidak ada eror dan bahwa semua sumber daya telah dimuat dengan benar.
Memverifikasi tajuk tanggapan server Anda
Anda dapat menggunakan perintah curl
untuk memverifikasi bahwa server Anda mengirimkan tajuk tanggapan HTTP yang benar. Di dalam perintah curl
berikan URL permintaan dan tajuk kustom apa pun yang ingin Anda tambahkan.
Sintaks: curl <request-url> -H <custom-header> - I
Menguji permintaan dari asal yang sama
Di dalam permintaan dengan asal yang sama, sistem AMP menambahkan tajuk AMP-Same-Origin:true
kustom.
Ini adalah perintah curl kita untuk menguji permintaan dari berkas https://ampbyexample.com
untuk examples.json
(pada domain yang sama):
curl 'https://amp.dev/static/samples/json/examples.json' -H 'AMP-Same-Origin: true' -I
Hasil dari perintah ini memperlihatkan tajuk tanggapan yang benar (catatan: informasi ekstra telah dipangkas):
HTTP/2 200 access-control-allow-headers: Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token access-control-allow-credentials: true access-control-allow-origin: https://ampbyexample.com access-control-allow-methods: POST, GET, OPTIONS
Menguji permintaan dari halaman AMP di cache
Di dalam permintaan CORS yang bukan berasal dari domain yang sama (yaitu, cache), tajuk origin
merupakan bagian dari permintaan.
Berikut ini adalah perintah curl kita untuk menguji permintaan dari halaman AMP di cache pada Cache AMP Google untuk berkas examples.json
:
curl 'https://amp.dev/static/samples/json/examples.json' -H 'origin: https://ampbyexample-com.cdn.ampproject.org' -I
Hasil dari perintah ini memperlihatkan tajuk tanggapan yang benar:
HTTP/2 200
access-control-allow-headers: Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token
access-control-allow-credentials: true
access-control-allow-origin: https://ampbyexample-com.cdn.ampproject.org
access-control-allow-methods: POST, GET, OPTIONS