Гісторыя з'яўлення Same-Origin Policy, CORS. Што такое JSONP. Простыя і складаныя запыты CORS. Перадзапыт (preflight).
У далёкія часы Netscape Navigator 2 з'явіўся JavaScript, DOM
і cookies.
Мова JavaScript, падобная сінтаксісам на Java, была створаная для працы з HTML
-дакументамі для дадання інтэрактыўнасці дакумента. DOM
- гэта API для доступу да HTML
-дакументу. Сookies - для адрознівання карыстальнікаў аднаго ад другога.
Гэта стала небяспечна, бо праз доступ да DOM
з'явілася магчымасць адрымаць доступ да розных HTML
-элементаў, з'яўляліся новыя і новыя HTML
-тэгі, якія дазвалялі зрабіць больш цікавым і рознабаковым інтэрфэйс сайта - img
, form
, frame
, video
, audio
і іншыя, якія маглі спампоўвацца, або неяк інакш ўзаемадзейнічаць з іншымі крыніцамі, cookies карыстальніка маглі патрапіць на іншы злаўмысны рэсурс.
Тады распрацоўшчыкі Netscape Navigator дадалі абмежаванне, якое вызначала адносіны паміж рознымі крыніцамі - Same Origin Policy.
SOP (Same-Origin Policy - палітыка адной крыніцы) - гэта механізм бяспекі браўзера, які абмяжоўвае ўзаемадзеянне дакумента або сцэнара, загружанага з адной крыніцы, з рэсурсам, загружанага з іншай крыніцы. Гэта накірована на прадухіленне атак з патэнцыйна небяспечных крыніц.
Рэсурсы будуць лічыцца загружанымі з іншых крыніц, калі яны адрозніваюцца:
- даменам
- портам
- пратаколам
То бок, калі крыніца будзе адрознівацца хоць адным элементам з гэтага спісу, яна будзе лічыцца іншай.
SOP
не забараняе цалкам атрымліваць рэсурсы з іншых крыніц і не забараняе звяртацца да іншых крыніц.
Пераважна правілы датычацца не ўстаўцы рэсурсаў з іншых крыніц, а чытанню з іх.
Асноўныя правілы SOP
:
CSS
- можна дадаць стылі з іншых крыніц, выкарыстоўвая тэг<link>
альбо@import
. Абавязкова трэба ўказваць загаловакContent-Type:text/css
.img
- убудаванне выяў з іншых крыніц і адлюстраванне іх карыстальнікам дазволена, але чытанне файла з дапамогай JS і даданне яго ў<canvas>
забаронена. Чаму так было зроблена, можна зразумець з наступнага прыклада:
<img src="img" onerror=alert(1);/>
iframes
- убудаванне залежыць ад ад загалоўкаX-Frame-Options
. Звычайна ўбудаванне дазволена. Чытанне з дапамогай JS забаронена.forms
- даныя можам адпраўляць на іншы рэсурс.fonts
- web fonts звычайна забароненыя для выкарыстоўвання з іншых рэсурсаў.audio
,video
- можам дадаваць з выкарыстойваннем адпаведных html-тэгаў.script
- не забаронена выкарыстоўваць html-элемент<script type="text/javascript" src="…">
для звяртання да іншага рэсурса.
Асноўнымі пагрозамі, звязанымі з выкарыстаннем уразлівасцяў з іншай крыніцы, з'яўляюцца:
- напады міжсайтавага скрыптынгу (XSS)
- падробкі міжсайтавых запытаў (CSRF)
- Clickjacking
Але ж развіццё web-а ішло хуткімі крокамі, і існавала патрэба ў звяртанні да іншых рэсурсаў дзеля атрымання даных з іншых рэсурсаў. Каб абыйсці абмежаванні SOP
, выкарыстоўваліся:
- Для адпраўкі даных -
<form>
(GET
/POST
-запыты) (у тым ліку і схаваныя для карыстальнікаў), выкарыстоўванне якіх не забаранялася пры адпраўцы даных на любы іншы рэсурс. - Для атрымання даных (
GET
-запыты) -JSONP
(JSON with Padding
).
Што сабой уяўляла атрыманне даных з выкарыстоўваннем JSONP
?
У аснову JSONP
быў пакладзены той факт, што палітыка бяспекі браўзера не забараняе выкарыстоўваць HTML-элемент <script type="text/javascript" src="…"/>
для звяртання да крыніц, адрозных ад той, з якой загружаная HTML-старонка з гэтым тэгам. То бок, замест XHR
выкарыстоўваўся HTML-тэг <script>
.
У кліенскім кодзе ствараецца функцыя, якая павінна быць даступна з глабальнага кантэкста:
function printTemperature({ temperature }) { document.getElementById("id").innerHTML = 'Вітаначкі! Сёння на вуліцы ' + temperature + ' градусаў'; }
Дадаем HTML-тэг <script>
да нашай старонкі. Для кожнага новага JSONP
-запыту браўзер павінен дадаць новы элемент <script>
або выкарыстоўваць наяўны.
script = document.createElement('script'); script.type = 'text/javascript'; script.src = 'http://www.anotherServer.com/weather?callback=printTemperature';
У выніку наша HTML-старонка будзе выглядаць неяк так:
<html> <head> </head> <body> <div id = "id"></div> <script> function printTemperature({ temperature }) { document.getElementById("id").innerHTML = 'Вітаначкі! Сёння на вуліцы ' + temperature + ' градусаў'; } </script> <script type="text/javascript" src="http://www.anotherServer.com/users?callback=printTemperature"></script> </body> </html>
У адказ павінны былі вярнуцца даныя JSON
, абгорнутыя ў callback
.
printTemperature({ "temperature": 26 })
Выкарыстоўванне JSONP
асноўваецца на даверы да іншай крыніцы.
Калі аддалёныя серверы ўразлівыя і дапушчаюць укараненне JavaScript, гэта дазваляе зламысніку выканаць адвольны JavaScript на вашай web-старонцы.
Усё больш значным станавілася патрабаванне аб змягчэнні і больш тонкай настройцы строгай палітыкі SOP
, не памяншая пры гэтым забяспячэння бяспекі. Так з'явіўся CORS
.
Cross-Origin Resource Sharing (CORS) - механізм бяспекі браўзера, які, з дапамогай http
-загалоўкаў, дазваляе агенту карыстальніка атрымаць доступ да рэсурсаў, адрозных ад таго, што сайт выкарыстоўвае ў дадзены момант.
Усе запыты былі падзеленыя на простыя і складаныя, а браўзер узяў на сабе ролю даверанага пасярэдніка.
К простым былі аднесеныя ўсе бяспечныя запыты, якія раней можна было зрабіць з выкарыстаннем <form>
і <script>
.
Былі дазволеныя 3 http-метада:
GET
HEAD
POST
І толькі з 4 загалоўкамі:
Accept
Accept-Language
Content-Language
Content-Type
(толькі са значэнняміapplication/x-www-form-urlencoded
,multipart/form-data
,text/plain
)
Пры адпраўцы такога запыту браўзер ад сабе дадае загаловак "Origin: https://bel-frontend.online
", які указвае на рэсурс (дамен, пратакол, порт). Яго можа ўстяляваць толькі браўзер. Падрабіць з дапамогай JS не атрымаецца, бо браўзер глядзіць на URL. Сервер павінен адказаць загалоўкам Access-Control-Allow-Origin
, дзе указвае, ці "Access-Control-Allow-Origin:*
", калі дазволена звяртацца з любога рэсурса, ці дакладны дазволены рэсурс "Access-Control-Allow-Origin: https://bel-frontend.online
". Браўзер праверае, ці супадае запытаны і дазволены рэсурсы і дазваляе / забараняе доступ да адказу сервера.
Усё, што не трапляе пад патрабаванні простых запытаў, адносіцца да складаных запытаў (насамрэч, такой назвы няма, але, каб скараціць апісанне, будзем лічыць, што яны называюцца так).
Напрыклад:
Content-Type: application/json
- запыт з аўтарызацыйнымі данымі
- http-метады
PUT
,PATCH
,DELETE
і гэтак далей
Чым простыя запыты адрозніваюцца ад складаных?
У выпадку складанага запыту перад асноўным запытам адпраўляецца перадзапыт (preflight
). Ён адпраўляеца браўзерам самастойна з выкарыстоўваннем http
-метада OPTIONS
. Запыт OPTIONS
адпраўляецца з 3 загалоўкамі:
Origin
(апісаны вышэй)Access-Control-Request-Method
(http
-метад, з якім будзе адпраўлены асноўны запыт)Access-Control-Request-Headers
(спісhttp
-загалоўкаў, якія будуць адпраўленыя ў асноўным запыце)
Калі сервер згодны адказаць на гэты запыт, ён вяртае адказ са статус-кодам (2**, звычайна 200 ці 204) за загалоўкамі:
Access-Control-Allow-Origin
- рэсурсы, якім дазволена звяртацца да сервера.Access-Control-Allow-Methods
- http-метады, якія разумее і згодны прыняць серверAccess-Control-Allow-Headers
- загалоўкі, якія чакае сервер
Гэты адказ можа кэшыравацца, калі сервер прыслаў загаловак Access-Control-Max-Age
з колькасцю секунд.
Браўзер правярае супадзенні, і калі ўсё добра, дае доступ да асноўных даных.
Важна! Браўзер не блакуе запыт, ён блакуе адказ. Асноўны запыт не блакуецца да адказу сервера на перадзапыт, а адпраўляецца адразу ўслед за ім. Адказ прыйдзе ў браўзер са статус-кодам 2**, але, у выпадку несупадзення загалоўкаў, браўзер блакуе атрыманыя з сервера даныя, у кансолі будзе памылка
CORS
, і карыстальнік іх не пабачыць на сваёй старонцы.
Падрабязней пра іншыя асаблівасці CORS можна пачытаць па спасылкам ніжэй.
Дадаткова:
Каментары
(Каб даслаць каментар залагуйцеся ў свой уліковы запіс)