2013-12-03 10 views
1

Привет, У меня очень странная проблема, и хостинговая компания говорит мне, что это невозможно. Я надеюсь, что вы, ребята, можете помочь.Varnish, Nginx, SSL - проблема с обнаружением IP-адресов

У меня есть nginx/лак, который действует как балансировщик нагрузки и кеш, сидящий перед моими веб-серверами. Мои веб-серверы являются стандартными веб-серверами apache.

У меня возникли проблемы с обнаружением подлинного IP-адреса пользователей, подключающихся к системе. $ _SERVER ["REMOTE_ADDR"] показывает IP-адрес балансира/кеша нагрузки, а не пользователя, посещающего сайт.

Мы написали хак, чтобы с HTTP-трафиком мы отправляли через заголовок X-Forwarded-For с правильным IP-адресом, но мне сказали, что это невозможно с SSL.

К сожалению, из-за строгих требований безопасности мы не можем отключить SSL на балансировщик/кеш-память, к которому он должен перейти в apache.

У кого-нибудь есть идеи о том, как мы можем определить IP-адрес при использовании SSL?

спасибо за помощь, Si

--- VCL Config ---

import std; 

C{ 
     #include <stdlib.h> 
}C 



sub vcl_recv {  
/* Add X-Forwarded-For header */ 
    if (req.restarts == 0) { 
     if (req.http.X-Forwarded-For) { 
      set req.http.X-Forwarded-For = req.http.X-Forwarded-For + ", " + client.ip; 
     } else { 
      set req.http.X-Forwarded-For = client.ip; 
     } 
    } 



    /* Fix compression */ 
    if (req.http.Accept-Encoding) { 
     if (req.url ~ "\.(ico|png|jpe?g|gif|xpm|swf|flv|pdf|mp3|ogg|zip|gz|tgz|bz2|xz|7z)$") { 
      remove req.http.Accept-Encoding; 
     } else if (req.http.Accept-Encoding ~ "gzip") { 
      set req.http.Accept-Encoding = "gzip"; 
     } else if (req.http.Accept-Encoding ~ "deflate") { 
      set req.http.Accept-Encoding = "deflate"; 
     } else { 
      remove req.http.Accept-Encoding; 
     } 
    } 

    /* Handle SSL offloading */ 
    if (client.ip == "127.0.0.1") { 
     std.log("SSL offloading detected " + client.ip + " " + req.http.X-Real-IP); 
     set client.identity = req.http.X-Real-IP; 
    } else { 
     set client.identity = client.ip; 
    } 

    if (req.http.Cookie) { 
     set client.identity = req.http.Cookie; 
    } 


    set req.http.X-Varnish-XID = req.xid; 
    set req.backend = lb231; 

    if (req.backend.healthy) { 
     set req.grace = 30s; 
    } else { 
     set req.grace = 1h; 
    } 

     call normalise_user_agent; 

    if (req.request == "PURGE") { 
     if (!client.ip ~ purge) { 
      error 405 "Not allowed."; 
     } 
     return(lookup); 
    } 

    if (req.request != "GET" && 
     req.request != "HEAD" && 
     req.request != "PUT" && 
     req.request != "POST" && 
     req.request != "TRACE" && 
     req.request != "OPTIONS" && 
     req.request != "DELETE") { 
     return (pipe); 
    } 

    if (req.http.Cookie) { 
       set req.http.Cookie = ";" + req.http.Cookie; 
       set req.http.Cookie = regsuball(req.http.Cookie, "; +", ";"); 
       set req.http.Cookie = regsuball(req.http.Cookie, ";(PHPSESSID)=", "; \1="); # Cookies to keep here 
       set req.http.Cookie = regsuball(req.http.Cookie, ";[^ ][^;]*", ""); 
       set req.http.Cookie = regsuball(req.http.Cookie, "^[; ]+|[; ]+$", ""); 

       if (req.http.Cookie == "") { 
         remove req.http.Cookie; 
       } 
    } 

    if (req.request != "GET" && req.request != "HEAD") { 
     return (pass); 
    } 


    if (req.url ~ "/nocache") { 
     set req.http.X-No-Cache = "true"; 
     return (pass); 
    } 

    if (req.request == "BAN") { 
     if (client.ip ~ purge) { 
      error 401 "Forbidden"; 
     } 
     ban("req.http.Host == " + req.http.X-VCL-Ban-Host + " && req.url ~ " + req.http.X-VCL-Ban-URL); 
     error 200 "Ban OK " + req.url + " " + req.http.Host; 
    } 

    if (req.request == "REFRESH") { 
     set req.request = "GET"; 
     set req.hash_always_miss = true; 
    } 

    if (req.request != "GET" && req.request != "HEAD") { 
     return (pass); 
    } 

    return (lookup); 
} 


    if (beresp.status >= 400) { 
     /* Cache error pages for a short amount of time */ 
     set beresp.ttl = 5s; 
     set beresp.grace = 5s; 
     set beresp.http.Cache-Control = "max-age=5, must-revalidate"; 
     unset beresp.http.Cookie; 
     unset beresp.http.Set-Cookie; 
    } 

    if (beresp.status == 503) { 
     /* Do not cache 503s at all */ 
     set beresp.ttl = 0s; 
     set beresp.http.Cache-Control = "no-store, no-cache, must-revalidate"; 
     set beresp.http.Pragma = "no-cache"; 
    } 

    if (beresp.http.X-Varnish-TTL) { 
     C{ 
      char *ttl; 
      ttl = VRT_GetHdr(sp, HDR_BERESP, "\016X-Varnish-TTL:"); 
      VRT_l_beresp_ttl(sp, atoi(ttl)); 
     }C 
     #unset beresp.http.X-Varnish-TTL; 
    } else { 
     set beresp.ttl = 0s; 
    } 

    if (beresp.ttl <= 0s) { 
     set beresp.http.X-Cacheable = "No, not cacheable."; 
    } elsif (req.http.Cookie ~ "(UserID|_session)") { 
     set beresp.http.X-Cacheable = "No, got session."; 
     return(hit_for_pass); 
    } elsif (beresp.http.Cache-Control ~ "private") { 
     set beresp.http.X-Cacheable = "No, Cache-Control=private"; 
     return(hit_for_pass); 
    } else { 
     set beresp.http.X-Cacheable = "Yes."; 
     set beresp.grace = 1h; 
    } 
} 

sub vcl_deliver { 
    if (resp.http.reset-client-side-age) { 
     unset resp.http.reset-client-side-age; 
     set resp.http.Age = "0"; 
    } 

    if (obj.hits > 0) { 
     set resp.http.X-Cache = "Hit"; 
     set resp.http.X-Cache-Hits = obj.hits; 
    } else { 
     set resp.http.X-Cache = "Miss"; 
    } 

    if (resp.http.Server == "Varnish") { 
     set resp.http.Server = "OnCommerce Framework Ltd"; 
    } 

    unset resp.http.X-Varnish; 
    unset resp.http.X-Scrubbed-For; 
} 

sub vcl_hit { 
    if (req.request == "PURGE") { 
     purge; 
     error 200 "Purged."; 
    } 
} 

sub vcl_miss { 
    if (req.request == "PURGE") { 
     purge; 
     error 200 "Purged."; 
    } 
} 

sub vcl_pipe { 
    set bereq.http.Connection = "close"; 
} 

sub vcl_error { 

} 

sub normalise_user_agent 
{ 
       if(req.http.user-agent ~ "Mobile"){ 
           set req.http.X-UA = "mobile"; 
       } 
       else if (req.http.user-agent ~ "Android") 
       { 
           set req.http.X-UA = "android"; 
       } 
       else if (req.http.user-agent ~ "Opera Mini/") 
       { 
           set req.http.X-UA = "mobile"; 
       } 
       else if (req.http.user-agent ~ "Opera Mobi/") 
       { 
           set req.http.X-UA = "mobile"; 
       } 
       else if (req.http.user-agent ~ "iP(ad|od|hone)/") 
       { 
           set req.http.X-UA = "iOS"; 
       } 
       else if (req.http.user-agent ~ "MSIE/") 
       { 
           if(req.http.user-agent ~ "MSIE\s[1-7]/") 
           { 
               set req.http.X-UA = "desktop-old"; 
           } 
           else 
           { 
               set req.http.X-UA = "desktop"; 
           } 
       } 
       else if (req.http.user-agent ~ "Chrome/") 
       { 
           set req.http.X-UA = "desktop"; 
       } 
       else if (req.http.user-agent ~ "Firefox/") 
       { 
           set req.http.X-UA = "desktop"; 
       } 
       else if (req.http.user-agent ~ "Waterfox/") 
       { 
           set req.http.X-UA = "desktop"; 
       } 
       else if (req.http.user-agent ~ "Safari/") 
       { 
           set req.http.X-UA = "desktop"; 
       } 
       else if (req.http.user-agent ~ "Opera/") 
       { 
           set req.http.X-UA = "desktop"; 
       } 
       else if (req.http.user-agent ~ "curl/") 
       { 
           set req.http.X-UA = "desktop"; 
       } 
       else 
       { 
           set req.http.X-UA = req.http.user-agent; 
       } 
} 
+1

Это зависит от того, в какой части настройки заканчивается согласование SSL. Я сделал это с HAProxy, сидящим перед лаком (в основном, вы настроили переадресованный заголовок на конечной точке SSL) – NITEMAN

+0

Почему бы не опубликовать ваши файлы конфигурации, а не заставить людей работать слепыми? – Danack

+0

Конечная точка SSL находится на серверах apache, а не в лаке для лака, поэтому, к сожалению, в точке, где мы могли бы установить заголовок для конечной точки SSL, мы больше не знаем, что такое IP-адрес. – Simon

ответ

0

в моем файле default.vcl я переписать де "X-Forwarded-For" заголовок следующим образом:

sub vcl_recv { 

    # your code 

    remove req.http.X-Forwarded-For; 
    set req.http.X-Forwarded-For = client.ip; 

    # your code again 
} 

Не знаю, если это хак, о котором вы говорили, но таким образом он работает для нас. Важно удалить фактический заголовок, чтобы он не передавался, а также новый.

У нас есть CloudFlare + Varnish, и все работает нормально!

+0

Можете ли вы вставлять заголовки в запрос SSL, поскольку нам сказали, что это не сработает, потому что пакеты зашифрованы и, поскольку SSL должен пройти через зашифрованный лак, он не сможет подключить заголовок. – Simon

0

Если вы используете Nginx в качестве кэша необходимо добавить

proxy_set_header  X-Real-IP $remote_addr; 
proxy_set_header  X-Forwarded-For $proxy_add_x_forwarded_for; 
proxy_set_header  Host $http_host; 

в location. То же самое касается и лака.

sub vcl_rev { 
    set bereq.http.X-Real-IP = client.ip; 
    set bereq.http.X-Forwarded-For = req.http.X-Forwarded-For; 
    set bereq.http.host = req.http.host; 
} 
+0

Просто, чтобы подтвердить, мне сказали, что когда вы получаете запрос SSL, и вы не дешифруете, что запрос SSL на сам лак (передается в apache), что заголовки зашифрованы и, таким образом, вы не можете добавлять новые заголовки к соединению таких как X-Forwarded-For и X-Real-IP. Возможно, моя информация неверна, можете ли вы подтвердить? – Simon

+0

Если вы хотите использовать Nginx точно так же, как SSL-обертку и Varnish в качестве кеша, Nginx получит только HTTPS-запросы и передаст их в Larnish. Действительно, Varnish не может шифровать/расшифровывать запросы SSL. Но я думаю, вы можете добавить заголовки в Varnish, так как в Varnish вы получаете в любом случае обычный HTTP-запрос. –

+0

И в описанном выше сценарии Apache не получит никаких HTTPS-запросов. Если вы хотите, чтобы Apache обрабатывал запросы HTTPS, для чего вам нужен Nginx? Более того, таким образом вы не сможете воспользоваться лаком таким образом. Кстати, знаете ли вы, что Nginx - полнофункциональный веб-сервер и может предлагать многие функции Apache? –

0

Можете ли вы прояснить это?

В этом случае вы не можете использовать ничего, кроме балансировщика tcp, поскольку вы не можете просто поместить обычный кеш-кеш http-прокси, например nginx или лак, поскольку он должен читать (и изменять) заголовки http, которые избили всю цель ssl/encryption («человек посередине»).

Конечно, nginx может проксировать также https-трафик (например, proxy_pass https: // yoursite;) для бэкэнд, но для поддержки https для клиентов все равно понадобятся SSL-сертификаты.

Вот почему обычно разгрузка SSL выполняется на верхнем уровне (в вашем случае это будет nginx, который затем передает заголовок X-Forwarded-For для лака, который далее передает его apache и apache преобразует его в клиентский ip).

+0

К сожалению, это требование - это то, что я не контролирую, у нас очень строгие требования безопасности, и я должен был следовать им за письмом. Мне было интересно, есть ли другой способ передать IP-адрес, который не включает заголовки. Например, apache обнаруживает $ _SERVER ["REMOTE_ADDR"] в качестве адреса лака, может ли не подделывать IP-адрес, чтобы он отображал IP-адрес пользователя? – Simon

+0

Хорошо вставлять лак между ними в этом случае не имеет смысла в любом случае (поскольку он не сможет кэшировать что-либо /, также лак никак не понимает SSL). Но на самом деле есть механик для «подмены» клиента ip - «прозрачный прокси» или tproxy. Тогда это не так просто, поскольку включает в себя настройку всего сервера (iptables) также, насколько я знаю, только Haproxy (http://haproxy.1wt.eu/) и Squid имеют только реальную реализацию. http://wiki.squid-cache.org/Features/Tproxy4 https://www.kernel.org/doc/Documentation/networking/tproxy.txt – Simon

0

Хорошо, решение, с которым мы пошли, состояло в том, чтобы маршрутизировать весь трафик SSL вокруг лака, поскольку он не кэшировал его, так как это имело больше смысла для этого. Однако, если кто-нибудь придумает решение, мне было бы очень интересно услышать.

 Смежные вопросы

  • Нет связанных вопросов^_^