Przepisanie Nginx https zmienia POST na GET

17

Mój serwer proxy działa na ip A i w ten sposób ludzie uzyskują dostęp do mojej usługi internetowej. Konfiguracja nginx przekieruje na maszynę wirtualną na ip B.

W przypadku serwera proxy w sieci IP A mam go w moich witrynach dostępnych

server {
        listen 443;
        ssl on;
        ssl_certificate nginx.pem;
        ssl_certificate_key nginx.key;

        client_max_body_size 200M;
        server_name localhost 127.0.0.1;
        server_name_in_redirect off;

        location / {
                proxy_pass http://10.10.0.59:80;
                proxy_redirect http://10.10.0.59:80/ /;

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

}

server {
        listen 80;
        rewrite     ^(.*)   https://$http_host$1 permanent;
        server_name localhost 127.0.0.1;
        server_name_in_redirect off;
        location / {
                proxy_pass http://10.10.0.59:80;
                proxy_redirect http://10.10.0.59:80/ /;
                proxy_set_header Host $http_host;
                proxy_set_header X-Real-IP $remote_addr;
                proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        }
}

proxy_redirectZostała podjęta z jak mogę nginx do przekazania żądania HTTP POST poprzez przepisanie?

Wszystko, co trafi do publicznego adresu IP, osiągnie wartość 443 z powodu przepisania. Wewnętrznie przekierowujemy do 80 na maszynie wirtualnej.

Ale kiedy uruchamiam skrypt Pythona, taki jak poniższy, aby przetestować naszą konfigurację

import requests

data = {'username': '....', 'password': '.....'}
url = 'http://IP_A/api/service/signup'

res  = requests.post(url, data=data, verify=False)
print res
print res.json
print res.status_code
print res.headers

Dostaję 405 Method Not Allowed. W nginx odkryliśmy, że kiedy uderzył w wewnętrzny serwer, wewnętrzny nginx otrzymywał GETżądanie, mimo że w oryginalnym nagłówku tak zrobiliśmy POST(zostało to pokazane w skrypcie Python).

Wygląda na to, że przepisywanie ma problem. Jakiś pomysł jak to naprawić? Kiedy skomentowałem przepisywanie, z pewnością osiąga 80 i przeszło. Ponieważ przepisanie było w stanie rozmawiać z naszym wewnętrznym serwerem, więc samo przepisywanie nie ma problemu. Po prostu przepisano POSTna GET.

Dziękuję Ci!

(Zostanie to również zadane na forum Nginx, ponieważ jest to krytyczny bloker ...)

CppLearner
źródło

Odpowiedzi:

8

To nie jest Nginx, to twoja przeglądarka.

Uwaga z RFC2616:

RFC 1945 i RFC 2068 określają, że klient nie może zmieniać metody przekierowanego żądania. Jednak większość istniejących implementacji agenta użytkownika traktuje 302 tak, jakby była odpowiedzią 303, wykonując GET w lokalizacji [..]

Dotyczy to wszystkich popularnych przeglądarek i nic nie możesz na to poradzić.

c2h5oh
źródło
@ c2h50h Rozumiem, że specyfikacja HTTP podała coś podobnego. Ale co mogę zrobić w Nginx? Znaczy to jest trywialne setup, gdzie ludzie forward 443 do wewnętrznego portu 80, ale może jeszcze zrobić PUT, POST, DELETE, GET. W mojej poprzedniej konfiguracji nie miałem tego dodatkowego proxy z przodu służącego tłumowi. Miałem tę samą konfigurację na tym samym serwerze wewnętrznym (naszym serwerze testowym). To działa dobrze.
CppLearner
Nic. Jest w 100% po stronie klienta. Jeśli serwer WWW, jakikolwiek serwer zwróci przekierowanie 301 lub 302, przeglądarka po stronie klienta zastąpi żądanie dowolnego typu GET. Żadna konfiguracja po stronie serwera ani żadne zwrócone nagłówki HTTP tego nie zmienią. Jest tak z przyczyn historycznych (wczesne przeglądarki zachowywały się w ten sposób z powodu nieporozumień i stały się de facto standardem).
c2h5oh
Po pierwsze, tak naprawdę nie jest to przeglądarka. Cóż, możesz powiedzieć, że to przeglądarka, ponieważ używa protokołu HTTP .. OK .. to dobrze. Ale z drugiej strony wygląda na to, że dzieje się tak tylko wtedy, gdy wykonuję tę konfigurację dwuwarstwową. Jeśli miałbym umieścić tę samą konfigurację bezpośrednio na maszynie wewnętrznej i uruchomić tam test, nie będzie narzekać. Ale z drugiej strony, jak ludzie robią to w swojej produkcji? Zakładam, że niektórzy ludzie robią podobne rzeczy, odwróć 443 na niektóre maszyny wirtualne, które mogą działać tylko w wersji 80. Jeśli istnieje lepsza praktyka, chciałbym się jej nauczyć i usłyszeć o niej.
CppLearner
1
Przez przeglądarkę miałem na myśli klienta HTTP i ze wszystkimi popularnymi klientami POSTstanie się, GETjeśli zostanie przekierowany 301 lub 302. POST pozostanie POST przy przekierowaniu proxy, ale nie przy przepisywaniu.
c2h5oh
1
RFC2616 ponownie: If the 307 status code is received in response to a request other than GET or HEAD, the user agent MUST NOT automatically redirect the request unless it can be confirmed by the user, since this might change the conditions under which the request was issued.więc większość przeglądarek wyświetli komunikat ostrzegawczy, ponieważ w przypadku innych klientów HTTP nie mogę nawet zgadnąć, jakie będzie ich zachowanie.
c2h5oh
1

Odkryłem, że POST /api/brandzostał zamieniony, GET /api/brandponieważ aplikacja internetowa, z której korzystałem ( flask-restful), składała „nieprawidłowe” żądanie. Jeśli użyłem POST /api/brand/(zwróć uwagę na końcowe /), powiodło się.

gaozhidf
źródło
Używałem programu Listonosz do testowania logowania do autoryzacji django rest-auth i widziałem ten sam opisany problem. Kluczem było to, że zlekceważyłem końcowe „/” w żądaniu POST.
Steve L