Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 20 additions & 1 deletion scapy/layers/http.py
Original file line number Diff line number Diff line change
Expand Up @@ -1053,8 +1053,27 @@ def request(
continue
# Second case: follow redirection
if resp.Status_Code in [b"301", b"302"] and follow_redirects:
location = resp.Location.decode()
# Host and Path must be computed from the new URL
headers.pop("Host")
headers.pop("Path")
# Do not forward credentials to another origin
try:
redirect = urlsplit(location)
redirect_port = redirect.port
except ValueError:
raise ValueError("Bad URL !") from None
if redirect_port is None:
redirect_port = 443 if redirect.scheme == "https" else 80
if (redirect.scheme, redirect.hostname, redirect_port) != (
transport,
host,
port,
):
for hdr in ["Authorization", "Proxy_Authorization", "Cookie"]:
headers.pop(hdr, None)
return self.request(
resp.Location.decode(),
location,
data=data,
timeout=timeout,
follow_redirects=follow_redirects,
Expand Down
44 changes: 44 additions & 0 deletions test/scapy/layers/http.uts
Original file line number Diff line number Diff line change
Expand Up @@ -346,6 +346,50 @@ assert client.connected == ("allowed.example", 8080, False)
assert client.sent_request.Host == b"allowed.example:8080"
assert client.sent_request.Path == b"/resource?item=1"

= HTTP - HTTP_Client does not forward credentials on a cross-origin redirect
~ http-client

from scapy.layers.http import HTTP_Client, HTTPResponse

class RedirectClient(HTTP_Client):
def __init__(self, location):
super().__init__(verb=False)
self.location = location
self.sent = []
def _connect_or_reuse(self, host, port=None, tls=False, timeout=5):
self.connected = (host, port, tls)
def sr1(self, req, **kwargs):
self.sent.append((self.connected, req))
if len(self.sent) == 1:
return HTTPResponse(Status_Code=b"302", Location=self.location)
return HTTPResponse(Status_Code=b"200")

client = RedirectClient(b"http://other.example/landing")
resp = client.request(
"http://origin.example/api",
Authorization=b"Bearer s3cret",
Cookie=b"session=abcd",
)
assert resp.Status_Code == b"200"
connected, req = client.sent[1]
assert connected == ("other.example", 80, False)
assert req.Host == b"other.example"
assert req.Path == b"/landing"
assert req.Authorization is None
assert req.Cookie is None

client = RedirectClient(b"http://origin.example/landing")
resp = client.request(
"http://origin.example/api",
Authorization=b"Bearer s3cret",
Cookie=b"session=abcd",
)
assert resp.Status_Code == b"200"
connected, req = client.sent[1]
assert req.Path == b"/landing"
assert req.Authorization == b"Bearer s3cret"
assert req.Cookie == b"session=abcd"

= HTTP - HTTP_client asks HTTP_server with NTLMSSP
~ http-client

Expand Down
Loading