За последние 24 часа нас посетили 24464 программиста и 1656 роботов. Сейчас ищут 922 программиста ...

CORS-запрос средствами PHP?

Тема в разделе "Прочие вопросы по PHP", создана пользователем Freakmeister, 14 апр 2015.

  1. Freakmeister

    Freakmeister Активный пользователь

    С нами с:
    20 дек 2009
    Сообщения:
    888
    Симпатии:
    5
    Делаю главную страницу для форума, который расположен на субдомене. Нужно выцепить его сессию, для этого в движке есть такая страница:
    http://forum.discourse.su/session/current.json
    Она выводит json с информацией о текущей сессии. Получить ответ отсюда у меня получилось только одним способом - AJAX. Но крутить полученное мне нужно серверным языком, чтобы вывести юзеру на главной странице набор инструментов в соотвествии с его правами. Понятно, что JS это полная фигня, его сразу поломают, если я буду делать что-то типа - получил сессию в JS, передал в PHP. Так как можно отправить CORS-запрос средствами PHP?

    Я пробовал тупо file_get_contents - возвращает HTTP/1.1 404 Not Found:

    Код (PHP):
    1. $json = file_get_contents('http://forum.discourse.su/session/current.json');
    2. echo '<pre>'; var_export($json); echo '</pre>'; // отладка
    3. 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):
    1. $.ajax({
    2.     type: 'GET',
    3.     cache: false,
    4.     url: 'http://forum.red-squadron.ru/session/current.json',
    5.     dataType: 'json',
    6.     xhrFields: {
    7.         'withCredentials': true
    8.     },
    9.     success: function(result){
    10.         console.log(result.current_user.username);
    11.     },
    12.     error: function(result){
    13.         console.log('Error: '+result['status']+': '+result['statusText']+' '+result['responseText']);
    14.     }
    15. });
     
  2. mr.akv

    mr.akv Активный пользователь

    С нами с:
    31 мар 2015
    Сообщения:
    1.604
    Симпатии:
    206
    Возможно, с помощью cURL можно такое сделать, если передавать куки и http-авторизацию
     
  3. Ganzal

    Ganzal Суперстар
    Команда форума Модератор

    С нами с:
    15 мар 2007
    Сообщения:
    9.893
    Симпатии:
    965
    ты уже сам себе на вопрос ответил. тебе надо делать запрос с указанием нужного поля. естественно file_get_contents с контекстом или cURL это вполне умеют.
     
  4. Freakmeister

    Freakmeister Активный пользователь

    С нами с:
    20 дек 2009
    Сообщения:
    888
    Симпатии:
    5
    Не знал что file_get_contents такое умеет, ништяк. Уже прочитал как, но всё-равно не понятно какие хидеры я должен отправлять. Что отсылает jQuery, когда указываешь параметр withCredentials? В документации этого не вижу. Проверить на стороне сервера что приходит тоже не могу, там вообще не PHP и в исходниках попробуй найди это.
     
  5. mr.akv

    mr.akv Активный пользователь

    С нами с:
    31 мар 2015
    Сообщения:
    1.604
    Симпатии:
    206
    Так а в чём проблема посмотреть заголовки, которые отправляет браузер со страницы? Создайте файл php на поддомене, отправляйте запрос с той страницы на этот файл, а в файле уже смотрите, какие заголовки приходят.
     
  6. Freakmeister

    Freakmeister Активный пользователь

    С нами с:
    20 дек 2009
    Сообщения:
    888
    Симпатии:
    5
    Да уже допёрло, что можно посмотреть в браузере.)) Туплю, последние 4 часа раздуплял серверную часть, до этого вообще с CORS не имел дело, так что идёт туго. Собссна, отправляется это:

    [​IMG]

    Осталось разобраться как куки пережать в такой формат.
     
  7. mr.akv

    mr.akv Активный пользователь

    С нами с:
    31 мар 2015
    Сообщения:
    1.604
    Симпатии:
    206
    В смысле пережать? А в каком виде они у вас тогда хранятся в браузере?
    Вам их просто отправить надо и всё.
     
  8. Freakmeister

    Freakmeister Активный пользователь

    С нами с:
    20 дек 2009
    Сообщения:
    888
    Симпатии:
    5
    Ну а PHP же их выдаёт в виде массива. Если они просто через точку с запятой + пробел отправляются, то проблем нет - implode, да и всё. В общем, завтра буду тестить.
     
  9. Freakmeister

    Freakmeister Активный пользователь

    С нами с:
    20 дек 2009
    Сообщения:
    888
    Симпатии:
    5
    В $_SERVER['HTTP_COOKIE'] есть не все куки, которые передаются в AJAX. PHP не видит куки субдомена. Для наглядности вывел массивами - первое это то что отдаёт AJAX-запрос, а второе это содержимое $_SERVER['HTTP_COOKIE']. Надеюсь, в PHP можно получить куки субдомена forum.example.com, если скрипт находится на домене example.com?

    [​IMG]
     
  10. [vs]

    [vs] Суперстар
    Команда форума Модератор

    С нами с:
    27 сен 2007
    Сообщения:
    10.559
    Симпатии:
    632
    Что значит пхп не видит? Браузеры никогда не передают чужие куки. Это же пипец как опасно! Чтобы получить куки другого домена, надо ломануть браузер эксплоитом.
    Единственный вариант это если субдомен в момент установки кукк, укажет в качестве домена для кук основной домен с поддоменами типа так
    ".domain.com" это пятый аргумент функции setcookie().
     
  11. Freakmeister

    Freakmeister Активный пользователь

    С нами с:
    20 дек 2009
    Сообщения:
    888
    Симпатии:
    5
  12. [vs]

    [vs] Суперстар
    Команда форума Модератор

    С нами с:
    27 сен 2007
    Сообщения:
    10.559
    Симпатии:
    632
    JS-у не надо их видеть. Он не создает сокетов и не соединяется с сервером. AJAX-запрос производится средствами браузера, поэтому в нем содержатся соответствующие куки.

    Добавлено спустя 2 минуты 25 секунд:
    JS-у доступен только document.cookie и в нем куки, соотвествтующие текущему домену only
     
  13. Freakmeister

    Freakmeister Активный пользователь

    С нами с:
    20 дек 2009
    Сообщения:
    888
    Симпатии:
    5
    Ясно, значит параметр withCredentials берёт куки напрямую из браузера в обход document.cookie. Я посмотрел содержимое document.cookie сейчас - там тоже самое что в $_SESSION. Если убрать параметр withCredentials из AJAX-запроса, то куки никакие не отправляются и end-point возвращает 404:

    [​IMG]

    Короче, ясно, понятно - PHP этого не умеет. Ну и какой тогда прок от этого CORS вообще, если я не могу обратиться к нему напрямую с сервера? Я конечно могу сделать вот так, но разве это безопасно?

    [​IMG]

    Тут первый AJAX-запрос получает ID юзера, второй отправляет этот ID скрипту get_chat.php. Соответственно, подменяем этот ID в JS на ID админа и get_chat.php вернёт чат с админскими кнопками.
     
  14. [vs]

    [vs] Суперстар
    Команда форума Модератор

    С нами с:
    27 сен 2007
    Сообщения:
    10.559
    Симпатии:
    632
    Да, такая вот ситуация. Можно послать куки, но нельзя никак узнать, что в них.

    Если одно обладание админскими кнопками в интерфейсе дает право админить, то это пипец как опасно.

    Почему нельзя использовать накатаные схемы кросдоменной авторизации?
     
  15. Freakmeister

    Freakmeister Активный пользователь

    С нами с:
    20 дек 2009
    Сообщения:
    888
    Симпатии:
    5
    Это какие такие схемы? Тут есть только SSO (тоже не до конца понятно что это такое) и вот этот CORS-костыль. Спрашивается, как я должен делать проверки у себя на странице? Вот нажал чувак на какую-то админскую кнопку, которая появилась на его странице по щучьему веленью, и мне получается проверять его сессию отдельным AJAX-запросом? Трындец какой-то, пойду ругаться на разрабов этой софтины.
     
  16. [vs]

    [vs] Суперстар
    Команда форума Модератор

    С нами с:
    27 сен 2007
    Сообщения:
    10.559
    Симпатии:
    632
    Ну к примеру гугл авторизируется (или до недавнего времени) на ютубе (при логине в gmail например) с помощью редиректа по особому урлу (в урле - одноразовый токен). Редирект на ютюб, он в свою очередь коннектится к общей базе и проверяет токен на годность, по нему идентифицирует пользователя и ставит свои куки. И посылает клиенту Location обратно на gmail.
    Кроссдоменная авторизация предполагает общий сервер авторизации или общую базу данных.
     
  17. Freakmeister

    Freakmeister Активный пользователь

    С нами с:
    20 дек 2009
    Сообщения:
    888
    Симпатии:
    5
    Общая база данных есть, но толку от неё нет, потому что этот CORS не присылает id сессии пользователя, который можно было бы сравнить с id пользователя. Или вообще вытащить id пользователя по id сессии на серверной стороне - было бы идеально. Увы, оно присылает только бесполезную информацию типа вот этого:

    Код (Text):
    1. id: 2
    2. username: Maestro
    3. uploaded_avatar_id: 5
    4. avatar_template: /user_avatar/forum.red-squadron.ru/maestro/{size}/5.png
    5. name: the Barbarian
    6. total_unread_notifications: 0
    7. unread_notifications: 0
    8. unread_private_messages: 0
    9. admin: true
    10. notification_channel_position: null
    11. site_flagged_posts_count: 0
    12. moderator: true
    13. staff: true
    14. title: null
    15. reply_count: 867
    16. topic_count: 875
    17. enable_quoting: true
    18. external_links_in_new_tab: true
    19. dynamic_favicon: false
    20. trust_level: 4
    21. can_edit: true
    22. can_invite_to_forum: true
    23. should_be_redirected_to_top: false
    24. disable_jump_reply: false
    25. custom_fields: [object Object]
    26. muted_category_ids:
    27. dismissed_banner_key: 5959
    28. is_anonymous: false
     
  18. [vs]

    [vs] Суперстар
    Команда форума Модератор

    С нами с:
    27 сен 2007
    Сообщения:
    10.559
    Симпатии:
    632
    Тогда всё просто. Надо в ней хранить соответствие id пользователей и id их текущий сессий. AJAX-запросом извлекать id сессии текущего пользователя и передавать php-скрипту на текущем доменем. Он полезет в общую базу, по sid найдет id и[​IMG]

    Добавлено спустя 2 минуты 44 секунды:
    По сути тебе надо у удаленного сервера спросить идентификатор, который уже есть в браузере. Выглядит тупо, но это единственный путь. Вместо собственно идентификатора сессии, можно завести собственный рандомный токен для каждой авторизации.

    Добавлено спустя 41 секунду:
    Вся защищенность сессий на том и стоит, что подобрать ид сессии почти невозможно. Так что это путь!

    Добавлено спустя 2 минуты 56 секунд:
    Ну и в конце концов, раз у тебя поддомен, то почему бы не сделать просто
     
  19. Freakmeister

    Freakmeister Активный пользователь

    С нами с:
    20 дек 2009
    Сообщения:
    888
    Симпатии:
    5
    Предлагаешь вообще забыть нафиг про эту ссылку и написать свой end-point с властелином колец и световыми палками?
    http://forum.discourse.su/session/current.json
    Я думаю, эта штука уже есть где-то. Должна быть, по крайней мере, иначе как эта софтина запоминает сессию? Действительно, запилить свою серверную часть для CORS будет проще наверно.
    А вот тут не особо понял. Фишка в чём - в корне домена example.com у меня PHP. А на forum.example.com крутится софтина, написанная на Ruby on Rails. Так что, внести в неё какие-либо изменения, или применить настройки php.ini я не могу.) Но зато могу зайти в её БД с корневого домена.
     
  20. Freakmeister

    Freakmeister Активный пользователь

    С нами с:
    20 дек 2009
    Сообщения:
    888
    Симпатии:
    5
    Похоже, я раскатал губу. Сделал свой скрипт ответа на корневом домене. Вот он:

    Код (PHP):
    1. header("Access-Control-Allow-Origin: http://red-squadron.ru");
    2. header('Access-Control-Allow-Credentials: true');
    3. header('Access-Control: no-cache');
    4. header("Access-Control-Allow-Headers: Content-Type, *");
    5. header("Access-Control-Allow-Methods: GET, OPTIONS"); 
    6.  
    7. echo '<pre>$_GET: <br>'; var_export($_GET); echo '</pre>'; // отладка
    8. echo '<pre>$_SERVER: <br>'; var_export($_SERVER); echo '</pre>'; // отладка       
    В ответе от него нет кук с субдомена forum. Я правильно понимаю, что чтобы получить куки субдомена, я должен обращаться к скрипту, расположенному на этом субдомене?

    [​IMG]
     
  21. [vs]

    [vs] Суперстар
    Команда форума Модератор

    С нами с:
    27 сен 2007
    Сообщения:
    10.559
    Симпатии:
    632
    Абсолютно верно. А возможности внести изменения в прогу но Ruby совсем нет? Там куки ставятся подобным образом и тоже можно задать домен.
     
  22. Freakmeister

    Freakmeister Активный пользователь

    С нами с:
    20 дек 2009
    Сообщения:
    888
    Симпатии:
    5
    Возможность есть, но это геморрой размером с грецкий орех. Или плагин написать, что я не умею. =(

    Чисто гипотетически, отправка через CORS айди сессии может быть перехвачена сниффингом? Я сейчас просматриваю офф-форум, и тут кажись при просмотре бегает айди сессии туда-сюда. Так что, походу, в плане безопасности я ещё больше дыр не наделаю.

    [​IMG]
     
  23. [vs]

    [vs] Суперстар
    Команда форума Модератор

    С нами с:
    27 сен 2007
    Сообщения:
    10.559
    Симпатии:
    632
    Айди сессии не секретен. Он передается в куках или иногда прямо в урле. Защита сессии обсепечивается длиной, случайностью и ограниченным сроком действия идентификатора.
     
  24. Freakmeister

    Freakmeister Активный пользователь

    С нами с:
    20 дек 2009
    Сообщения:
    888
    Симпатии:
    5
    Вот и я тоже самое разрабам написал, а они галдят своё - передавать так id сессии это не безопасно. =\
    Ладно, не важно. Нашёл плагин, который переносит скрипт авторизации на заданный прокси. Так что, буду ловить сессию другим способом.