Делаю главную страницу для форума, который расположен на субдомене. Нужно выцепить его сессию, для этого в движке есть такая страница: http://forum.discourse.su/session/current.json Она выводит json с информацией о текущей сессии. Получить ответ отсюда у меня получилось только одним способом - AJAX. Но крутить полученное мне нужно серверным языком, чтобы вывести юзеру на главной странице набор инструментов в соотвествии с его правами. Понятно, что JS это полная фигня, его сразу поломают, если я буду делать что-то типа - получил сессию в JS, передал в PHP. Так как можно отправить CORS-запрос средствами PHP? Я пробовал тупо file_get_contents - возвращает HTTP/1.1 404 Not Found: Код (PHP): $json = file_get_contents('http://forum.discourse.su/session/current.json'); echo '<pre>'; var_export($json); echo '</pre>'; // отладка echo '<pre>'; var_export($http_response_header); echo '</pre>'; // отладка cURL тоже не помогает, пробовал эти решения: http://stackoverflow.com/questions/8540800/php-how-can-use- ... t-contents http://stackoverflow.com/questions/6595041/equivalent-of-fi ... -with-curl А вот работающий AJAX-запрос, он работает только с директивой withCredentials, иначе тоже выдаёт 404: Код (Text): $.ajax({ type: 'GET', cache: false, url: 'http://forum.red-squadron.ru/session/current.json', dataType: 'json', xhrFields: { 'withCredentials': true }, success: function(result){ console.log(result.current_user.username); }, error: function(result){ console.log('Error: '+result['status']+': '+result['statusText']+' '+result['responseText']); } });
ты уже сам себе на вопрос ответил. тебе надо делать запрос с указанием нужного поля. естественно file_get_contents с контекстом или cURL это вполне умеют.
Не знал что file_get_contents такое умеет, ништяк. Уже прочитал как, но всё-равно не понятно какие хидеры я должен отправлять. Что отсылает jQuery, когда указываешь параметр withCredentials? В документации этого не вижу. Проверить на стороне сервера что приходит тоже не могу, там вообще не PHP и в исходниках попробуй найди это.
Так а в чём проблема посмотреть заголовки, которые отправляет браузер со страницы? Создайте файл php на поддомене, отправляйте запрос с той страницы на этот файл, а в файле уже смотрите, какие заголовки приходят.
Да уже допёрло, что можно посмотреть в браузере.)) Туплю, последние 4 часа раздуплял серверную часть, до этого вообще с CORS не имел дело, так что идёт туго. Собссна, отправляется это: Осталось разобраться как куки пережать в такой формат.
В смысле пережать? А в каком виде они у вас тогда хранятся в браузере? Вам их просто отправить надо и всё.
Ну а PHP же их выдаёт в виде массива. Если они просто через точку с запятой + пробел отправляются, то проблем нет - implode, да и всё. В общем, завтра буду тестить.
В $_SERVER['HTTP_COOKIE'] есть не все куки, которые передаются в AJAX. PHP не видит куки субдомена. Для наглядности вывел массивами - первое это то что отдаёт AJAX-запрос, а второе это содержимое $_SERVER['HTTP_COOKIE']. Надеюсь, в PHP можно получить куки субдомена forum.example.com, если скрипт находится на домене example.com?
Что значит пхп не видит? Браузеры никогда не передают чужие куки. Это же пипец как опасно! Чтобы получить куки другого домена, надо ломануть браузер эксплоитом. Единственный вариант это если субдомен в момент установки кукк, укажет в качестве домена для кук основной домен с поддоменами типа так ".domain.com" это пятый аргумент функции setcookie().
А как JS тогда видит эти куки? Я ж посмотрел в свойствах страницы, эти куки точно лежат на субдомене. И AJAX запрос выше их отправляет, вот: http://dl1.joxi.net/drive/0001/2051/108547/150414/cbbe8ebc15.png
JS-у не надо их видеть. Он не создает сокетов и не соединяется с сервером. AJAX-запрос производится средствами браузера, поэтому в нем содержатся соответствующие куки. Добавлено спустя 2 минуты 25 секунд: JS-у доступен только document.cookie и в нем куки, соотвествтующие текущему домену only
Ясно, значит параметр withCredentials берёт куки напрямую из браузера в обход document.cookie. Я посмотрел содержимое document.cookie сейчас - там тоже самое что в $_SESSION. Если убрать параметр withCredentials из AJAX-запроса, то куки никакие не отправляются и end-point возвращает 404: Короче, ясно, понятно - PHP этого не умеет. Ну и какой тогда прок от этого CORS вообще, если я не могу обратиться к нему напрямую с сервера? Я конечно могу сделать вот так, но разве это безопасно? Тут первый AJAX-запрос получает ID юзера, второй отправляет этот ID скрипту get_chat.php. Соответственно, подменяем этот ID в JS на ID админа и get_chat.php вернёт чат с админскими кнопками.
Да, такая вот ситуация. Можно послать куки, но нельзя никак узнать, что в них. Если одно обладание админскими кнопками в интерфейсе дает право админить, то это пипец как опасно. Почему нельзя использовать накатаные схемы кросдоменной авторизации?
Это какие такие схемы? Тут есть только SSO (тоже не до конца понятно что это такое) и вот этот CORS-костыль. Спрашивается, как я должен делать проверки у себя на странице? Вот нажал чувак на какую-то админскую кнопку, которая появилась на его странице по щучьему веленью, и мне получается проверять его сессию отдельным AJAX-запросом? Трындец какой-то, пойду ругаться на разрабов этой софтины.
Ну к примеру гугл авторизируется (или до недавнего времени) на ютубе (при логине в gmail например) с помощью редиректа по особому урлу (в урле - одноразовый токен). Редирект на ютюб, он в свою очередь коннектится к общей базе и проверяет токен на годность, по нему идентифицирует пользователя и ставит свои куки. И посылает клиенту Location обратно на gmail. Кроссдоменная авторизация предполагает общий сервер авторизации или общую базу данных.
Общая база данных есть, но толку от неё нет, потому что этот CORS не присылает id сессии пользователя, который можно было бы сравнить с id пользователя. Или вообще вытащить id пользователя по id сессии на серверной стороне - было бы идеально. Увы, оно присылает только бесполезную информацию типа вот этого: Код (Text): id: 2 username: Maestro uploaded_avatar_id: 5 avatar_template: /user_avatar/forum.red-squadron.ru/maestro/{size}/5.png name: the Barbarian total_unread_notifications: 0 unread_notifications: 0 unread_private_messages: 0 admin: true notification_channel_position: null site_flagged_posts_count: 0 moderator: true staff: true title: null reply_count: 867 topic_count: 875 enable_quoting: true external_links_in_new_tab: true dynamic_favicon: false trust_level: 4 can_edit: true can_invite_to_forum: true should_be_redirected_to_top: false disable_jump_reply: false custom_fields: [object Object] muted_category_ids: dismissed_banner_key: 5959 is_anonymous: false
Тогда всё просто. Надо в ней хранить соответствие id пользователей и id их текущий сессий. AJAX-запросом извлекать id сессии текущего пользователя и передавать php-скрипту на текущем доменем. Он полезет в общую базу, по sid найдет id и Добавлено спустя 2 минуты 44 секунды: По сути тебе надо у удаленного сервера спросить идентификатор, который уже есть в браузере. Выглядит тупо, но это единственный путь. Вместо собственно идентификатора сессии, можно завести собственный рандомный токен для каждой авторизации. Добавлено спустя 41 секунду: Вся защищенность сессий на том и стоит, что подобрать ид сессии почти невозможно. Так что это путь! Добавлено спустя 2 минуты 56 секунд: Ну и в конце концов, раз у тебя поддомен, то почему бы не сделать просто
Предлагаешь вообще забыть нафиг про эту ссылку и написать свой end-point с властелином колец и световыми палками? http://forum.discourse.su/session/current.json Я думаю, эта штука уже есть где-то. Должна быть, по крайней мере, иначе как эта софтина запоминает сессию? Действительно, запилить свою серверную часть для CORS будет проще наверно. А вот тут не особо понял. Фишка в чём - в корне домена example.com у меня PHP. А на forum.example.com крутится софтина, написанная на Ruby on Rails. Так что, внести в неё какие-либо изменения, или применить настройки php.ini я не могу.) Но зато могу зайти в её БД с корневого домена.
Похоже, я раскатал губу. Сделал свой скрипт ответа на корневом домене. Вот он: Код (PHP): header("Access-Control-Allow-Origin: http://red-squadron.ru"); header('Access-Control-Allow-Credentials: true'); header('Access-Control: no-cache'); header("Access-Control-Allow-Headers: Content-Type, *"); header("Access-Control-Allow-Methods: GET, OPTIONS"); echo '<pre>$_GET: <br>'; var_export($_GET); echo '</pre>'; // отладка echo '<pre>$_SERVER: <br>'; var_export($_SERVER); echo '</pre>'; // отладка В ответе от него нет кук с субдомена forum. Я правильно понимаю, что чтобы получить куки субдомена, я должен обращаться к скрипту, расположенному на этом субдомене?
Абсолютно верно. А возможности внести изменения в прогу но Ruby совсем нет? Там куки ставятся подобным образом и тоже можно задать домен.
Возможность есть, но это геморрой размером с грецкий орех. Или плагин написать, что я не умею. =( Чисто гипотетически, отправка через CORS айди сессии может быть перехвачена сниффингом? Я сейчас просматриваю офф-форум, и тут кажись при просмотре бегает айди сессии туда-сюда. Так что, походу, в плане безопасности я ещё больше дыр не наделаю.
Айди сессии не секретен. Он передается в куках или иногда прямо в урле. Защита сессии обсепечивается длиной, случайностью и ограниченным сроком действия идентификатора.
Вот и я тоже самое разрабам написал, а они галдят своё - передавать так id сессии это не безопасно. =\ Ладно, не важно. Нашёл плагин, который переносит скрипт авторизации на заданный прокси. Так что, буду ловить сессию другим способом.