Расширение Chrome не отправляет файлы SameSite=Lax
У меня возникли проблемы при работе с файлами cookie через расширение chrome из всплывающего скрипта.
содержание popup.js:
document.addEventListener('DOMContentLoaded', () => {
function cookieinfo() {
chrome.cookies.getAll({url: 'http://localhost:8080'}, function(cookie) {
console.log('Found cookie: ', cookie)
if (cookie == null)
return;
fetch('http://localhost:8080', {credentials: 'include'}).then((response) => {
// do some stuff
return response;
});
});
}
window.onload=cookieinfo;
}, false);
Шаги, которые я выполняю:
- Войдите в мое приложение на localhost (так я получаю куки)
- Откройте всплывающее окно (чтобы исполнялся popup.js)
- Я вижу в журнале консоли, что хром нашел необходимые куки
- Сервер говорит, что во входящем запросе есть пустые куки
- Я обновляю страницу приложения localhost
- Я вышел из системы сейчас
Может кто знает, что я делаю не так?
Редактировать:
Кажется, причина в том, что мой cookie имеет параметры HttpOnly=true
а также SameSite=Lax
( ссылка по теме). Я вижу другие файлы cookie в журнале сервера. Но из-за этой темы все куки будут отправлены, если credentials
параметр установлен в include
Даже httpOnly куки. Также я попытался отправить его на 127.0.0.1 вместо localhost из-за этого ответа с тем же результатом.
Я не могу установить httpOnly
ложно. Это навязано рамками. Кто-нибудь знает, как это исправить?
Edit2:
Я наконец установил редактор Cookie и узнал, что SameSite=Lax
это причина. Если я установлю его на No Restriction
тогда я увижу это на стороне сервера. К сожалению, фреймворк, который я использую, позволяет только Lax
а также Strict
параметры (расширение Chrome не работает с обоими). Кто-нибудь знает, как отправлять куки Lax из расширения Chrome?
3 ответа
Это была проблема с расширениями в Chromium до версии 77. Когда для межсайтового файла cookie было установлено значение SameSite=Lax
или SameSite=Strict
, cookie не был отправлен с межсайтовым запросом.
Это было исправлено в версии 78 на всех платформах. Теперь расширение Chrome отправляет файлы cookie, когдаSameSite=Lax
или SameSite=Strict
.
Ссылки:
https://bugs.chromium.org/p/chromium/issues/detail?id=1007973
https://chromium-review.googlesource.com/c/chromium/src/+/1827503
https://bugs.chromium.org/p/chromium/issues/detail?id=617198
То, что я узнал, это печенье
path
является решающим. Любое несоответствие приводит к вводящему в заблуждение поведению.
Это моя установка:
- внутренний сервер, работающий на
- разрешение манифеста хрома имеет
"http://localhost:8081/"
- серверная часть возвращает cookie с
path=/
, напр. это образец заголовка ответаSet-Cookie: refresh_token=bar; Path=/; SameSite=Lax; HttpOnly
- Расширение Chrome может запросить файл cookie вручную:
chrome.cookies.get({ url: 'http://localhost:8081/', name: 'refresh_token' }...
- Расширение Chrome автоматически прикрепляет файл cookie при отправке на другие URL-адреса под
localhost:8081
, например:fetch('http://localhost:8081/v1/meh').then((response) => { console.log(response); })
refresh_token
печенье.
Подводя итог: файл cookie, установленный по пути
/a
не будет отправлено на URL-адрес по пути
/b
; файл cookie, установленный на пути
/
будут отправлены на все URL-адреса в одном домене.
Содержание скрипта является 100% решением.
В основном у вас есть два отдельных браузера, обычный браузер, а также всплывающий браузер с расширением. Но они совершенно разные и могут отправлять сообщения только туда и обратно. Так что вам нужно сделать, чтобы контекст расширения отправлял сообщение в контекст браузера, которое инструктирует некоторый код в этом контексте, чтобы получить document.cookies
и отправить их обратно в контекст расширения.
Вот пример того, как я получаю куки из каждого отдельного контекста браузера.
manifest.json
{
"manifest_version": 2,
"name": "Cookie Monster",
"description": "Nom nom nom nom",
"version": "1.0",
"browser_action": {
"default_popup": "html/extension.html",
"default_title":"Cookie Monster"
},
"permissions": [
"activeTab",
"tabs",
"http://*/*",
"https://*/*"
],
"content_scripts": [{
"js":["/js/client.js"],
"matches":["http://*/*","https://*/*"]
}]
}
extension.html
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<title>Cookies</title>
<style>
body {
display: block;
min-height: 250px;
width: 250px;
padding: 5px;
}
button {
display: block;
margin: 0 0 10px 0;
}
</style>
</head>
<body class="container">
<h1>Cookies</h1>
<button id="extension_cookies" type="button">Get PopUp Cookies</button>
<button id="browser_cookies" type="button">Get Browser Cookies</button>
<p id="result"></p>
<script src="/js/extension.js" type="text/javascript"></script>
</body>
</html>
extension.js
'use strict';
(function(){
// cache import DOM elements
const extension_btn = document.querySelector('#extension_cookies');
const browser_btn = document.querySelector('#browser_cookies');
const result = document.querySelector('#result');
// runs in the popup window of the extension,
// which is it's own browser context
// and has it's own set of cookies
extension_btn.addEventListener('click', () => {
if (document.cookie === ''){
result.innerText = 'No Cookies...';
} else {
result.innerText = document.cookie;
}
})
// send message to browser context
// message will inform browser client of what to do
// the browser then needs to pass data to the callback function
// then we can display results
browser_btn.addEventListener('click', () => {
chrome.tabs.query({active: true, currentWindow: true}, (tabs) => {
chrome.tabs.sendMessage(tabs[0].id, {message: 'GET_COOKIES'}, (data) => {
result.innerText = data.cookies
});
});
})
}());
client.js
'use strict';
(function(){
// receive a callback function so I can pass data to extension
// get document cookies, put into an object
// use callback to send response to extension
const get_browser_cookies = (sendResponse) => {
const cookies = document.cookie;
console.clear();
console.log(cookies);
sendResponse({ cookies: cookies });
}
// listen for messages from extension
// a switch statement can help run only the correct function
// must pass the function a reference to the sendResponse function
// so I can pass data back to extension
chrome.runtime.onMessage.addListener(function(data_from_extension, sender, sendResponse){
switch (data_from_extension.message){
case 'GET_COOKIES': {
get_browser_cookies(sendResponse);
break;
}
default: null;
}
});
}())