Небольшие заметки из личного (и не только) опыта, рекомендации
-
Raven
- Бородатый сис
- Сообщения: 2800
- Зарегистрирован: 03 мар 2010, 15:12
- ОС: RHEL 8
- Откуда: Из серверной
Сообщение
Raven » 10 июл 2013, 16:20
Понадобилось недавно сделать хитрожопый финт ушами - наши чудо-программисты написали супер-пупер крутую прогу, которой в обязалову потребовалось работать через собственный прокс (ибо в обязательном порядке SSL ннада!) на кучу серваков в локалке . Часть отвечающую за передачу динамического контента они написали сами, на PHP с использованием curl (держись прокся - северный пушной зверек крадется медленно, но верно), отдачу статики же было решено поручить веб-серверу. В общем самая хитрость заключалась в следующем - url выглядят следующим образом:
Код: Выделить всё
http://frontend.tld/?url=http://backend.tld/some/path/file.ext
То есть адрес файла вместе с адресом сервера передается в качестве аргумента к url= . Чтож, mod_rewrite в помощь, закручиваем хорошую самокрутку манов и курим-курим-курим! Я в итоге накурил до:
Код: Выделить всё
RewriteEngine On
RewriteBase /
RewriteCond %{QUERY_STRING} ^url=(.*)$ [NC]
RewriteRule .* %1 [P,L]
добавленное в .htaccess корневой директории домена оно в принципе справлялось достаточно хорошо. Однако вскоре случился затык - кое-где на бэкендах имелись файлы с пробелами в названии (криворукость итернет-пользователей заставляет подозревать что человеческая раса вымрет быстро). И естественно они не загружались. Оказалось что url содержащий пробел кодировался - пробел заменялся на '%20'. Казалось-бы, что в этом такого? Нормальное поведение браузера... Да не тут-то было! Веб-сервер при передаче запроса на проксирование, углядывал в запросе небезопасный по его мнению символ '%' и... кодировал его от греха подальше Тупо заменял на '%25'! В конце-концов бедолага пробел выглядел уже как '%2520' и понять что это за покемон уже никто не был способен. В общем ситуацию удалось разрешить добавлением флага NE (NoEncode) в RewriteRule
Правда радости это много не принесло - аналогичная проблема всплыла и с закодированными слешами и др. спецсимволами. А причина вся вот в чем - правила rewrite составлены таким образом, что если url= имеет аргументы, то присваиваются переменной %1 и содержимое всего запроса меняется на нее и передается в прокси КАК ЕСТЬ! А прокси не разрешает использование закодированных символов в обозначении хоста - то есть можно использовать кодированные символы только в {REQUEST_URI}, {QUERY_STRING} - то есть после http://backend.tld/. У меня же кодировалась вся строка запроса http%3A%2F%2Fbackend.tld%2F.
Перекурив маны еще раз вдоль и поперек нашел весьма интересную директиву - RewriteMap, позволяющую запускать для рерайта внешние обработчики. Быстренько сообразив что к чему накатал простенький скрипт на perl
Код: Выделить всё
#!/usr/bin/perl
use URI::Escape;
$| = 1;
while (<STDIN>) {
print uri_unescape($_);
}
Скрипт был назван decode.pl и помещен в папку с конфигами апача (заострю внимание на том, что скрипту требуется модуль URI::Escape, поставить можно через cpan).
далее в конфиге виртуалхоста добавляем строку
Код: Выделить всё
RewriteMap decode prg:/usr/local/etc/apache22/decode.pl
а в .htaccess приводим правила рерайта к следующему виду:
Код: Выделить всё
RewriteEngine On
RewriteBase /
RewriteCond %{QUERY_STRING} ^url=(.*)$ [NC]
RewriteRule .* ${decode:%1} [P,L,NE]
то есть, прежде чем передать строку в прокси-сервер, рерайт прогоняет ее через перловый скрипт слушающий stdin и заменяющий все кодированные символы на обычные. Profit!
UPD: Не, не profit! На боевом сервере оказался ужасно старючий перл, который при попытке собрать модуль URI::Escape возжелал обновиться. Ждать пока сие чудо скомпилится на серваке эквивалентном PIII желания особого не было, но к счастью там обнаружился python, нормальной версии 2.6!!! Спасибо gen1us2k за за помощь в конвертировании скрипта в python - все воркает замечательно!
Код: Выделить всё
#!/usr/bin/env python
from urllib2 import unquote
import sys
while 1:
request = sys.stdin.readline().strip()
sys.stdout.write('%s\n' % unquote(request))
sys.stdout.flush()
Я не злопамятный, я просто часто ковыряю логи
Raven
-
Raven
- Бородатый сис
- Сообщения: 2800
- Зарегистрирован: 03 мар 2010, 15:12
- ОС: RHEL 8
- Откуда: Из серверной
Сообщение
Raven » 12 июл 2013, 10:18
Да, кстати. Вот теперь вопрос - мож кто знает как отсечь передачу query_string в запросе к бэкенду? Просто проанализировав логи на серверах назначения обнаружил интересную картинку - запросы приходят в таком виде:
Код: Выделить всё
/some/path/file.ext?url=http://backend.tld/some/path/file.ext
Для серверов отдающих статику это конечно не очень критично, но тут уже чисто мои эстетические принципы - все должно быть чисто!
Я не злопамятный, я просто часто ковыряю логи
Raven
-
Gen1us2k
- Модератор
- Сообщения: 771
- Зарегистрирован: 02 мар 2010, 16:13
Сообщение
Gen1us2k » 13 авг 2013, 20:51
Raven
try:
sys.stdout.write('%s\n' % unquote(request.split('?')[1]))
except Exception:
sys.stdout.write('%s\n' % unquote(request))
Home: Windows Heaven
Home: Debian 6
For Servers: Debian || RHEL Based || Gentoo || FreeBSD
Gen1us2k