Máy Tính

Ngồi đọc lại


curl

Một tình huống tìm hiểu thêm về webserver

Một tình huống tìm hiểu thêm về webserver

Đây là tình huống hôm nay mình gặp với một web server chạy IIS. Mô tả lại cấu hình của các máy và sự khác biệt:

  • Máy 1:
    • Chạy web trên IIS bản 8.5.9600.16384 trong Windows Server 2012R2 version 6.2 (build 9200)
    • Máy mở port 80
    • Sử dụng domain1.com bind cho 1 site
    • domain1.com trỏ tới 1 IP
    • Giờ bind thêm domain2.com vào site này
    • domain2.com trỏ tới 1 IP khác

Test kết nối từ một server cùng mạng nội bộ vào máy này bằng curl phiên bản 8.0.1 sử dụng câu lệnh curl -LIkv -H "Host: <domain>" http://<local-network-ip>:80

Kết quả máy 1: Kết quả nhận được từ câu lệnh trên với domain1.com là status code 200 với 1 kết nối duy nhất, nhưng với domain2.com thì lại là status code 302 với 3 kết nối.

  • Máy 2: chạy web trên IIS trắng với domain2.com:
    • Chạy web trên IIS bản 8.5.9600.16384 trong Windows Server 2012R2 version 6.2 (build 9200)
    • Máy mở port 80
    • Sử dụng sub1.domain.com trỏ vào 1 IP
    • Sử dụng sub2.domain.com là subdomain giả (không tồn tại trên bản ghi của domain)
    • Giờ bind thêm sub2.domain.com vào site này

Test kết nối từ một server cùng mạng nội bộ vào máy này bằng curl phiên bản 7.88.1 sử dụng câu lệnh curl -LIkv -H "Host: <domain>" http://<local-network-ip>:80

Kết quả máy 2: Kết quả nhận được từ câu lệnh trên với cả 2 subdomain đều là status code 200 với 1 kết nối duy nhất.

Các kết nối 200 có quá trình gửi và nhận requests như sau:

*   Trying <local-network-ip>:80...
* Connected to <local-network-ip> (<local-network-ip>) port 80 (#0)
> HEAD / HTTP/1.1
> Host: domain1.com
> User-Agent: curl/8.0.1
> Accept: */*
>
< HTTP/1.1 200 OK
HTTP/1.1 200 OK
< Cache-Control: private
Cache-Control: private
< Content-Length: 67884
Content-Length: 67884
< Content-Type: text/html; charset=utf-8
Content-Type: text/html; charset=utf-8
< Server: Microsoft-IIS/8.5
Server: Microsoft-IIS/8.5
< Set-Cookie: lang=vi; expires=Wed, 19-Feb-2025 04:45:54 GMT; path=/
Set-Cookie: lang=vi; expires=Wed, 19-Feb-2025 04:45:54 GMT; path=/
< Set-Cookie: langAd=vi; expires=Wed, 19-Feb-2025 04:45:54 GMT; path=/
Set-Cookie: langAd=vi; expires=Wed, 19-Feb-2025 04:45:54 GMT; path=/
< Set-Cookie: ASP.NET_SessionId=ujfrcghecp11tx3gxu4zg21a; path=/; HttpOnly; SameSite=Lax
Set-Cookie: ASP.NET_SessionId=ujfrcghecp11tx3gxu4zg21a; path=/; HttpOnly; SameSite=Lax
< X-AspNetMvc-Version: 4.0
X-AspNetMvc-Version: 4.0
< X-AspNet-Version: 4.0.30319
X-AspNet-Version: 4.0.30319
< X-Powered-By: ASP.NET
X-Powered-By: ASP.NET
< Date: Wed, 19 Feb 2025 03:45:54 GMT
Date: Wed, 19 Feb 2025 03:45:54 GMT

<
* Connection #0 to host <local-network-ip> left intact

Các kết nối của trường hợp 302 có nội dung như sau

*   Trying <local-network-ip>:80...
* Connected to <local-network-ip> (<local-network-ip>) port 80 (#0)
> HEAD / HTTP/1.1
> Host: domain2.com
> User-Agent: curl/8.0.1
> Accept: */*
>
< HTTP/1.1 302 Found
HTTP/1.1 302 Found
< Cache-Control: private
Cache-Control: private
< Content-Length: 144
Content-Length: 144
< Content-Type: text/html; charset=utf-8
Content-Type: text/html; charset=utf-8
< Location: https://<another-domain>/
Location: https://<another-domain>/
< Server: Microsoft-IIS/8.5
Server: Microsoft-IIS/8.5
< Set-Cookie: lang=vi; expires=Wed, 19-Feb-2025 04:47:01 GMT; path=/
Set-Cookie: lang=vi; expires=Wed, 19-Feb-2025 04:47:01 GMT; path=/
< Set-Cookie: langAd=vi; expires=Wed, 19-Feb-2025 04:47:01 GMT; path=/
Set-Cookie: langAd=vi; expires=Wed, 19-Feb-2025 04:47:01 GMT; path=/
< X-Powered-By: ASP.NET
X-Powered-By: ASP.NET
< Date: Wed, 19 Feb 2025 03:47:00 GMT
Date: Wed, 19 Feb 2025 03:47:00 GMT

<
* Connection #0 to host <local-network-ip> left intact
* Clear auth, redirects to port from 80 to 443
* Issue another request to this URL: 'https://<another-domain>/'
*   Trying <another-ip>:443...
* Connected to <another-domain> (<another-ip>) port 443 (#1)
* ALPN: offers h2,http/1.1
* Cipher selection: ALL:!EXPORT:!EXPORT40:!EXPORT56:!aNULL:!LOW:!RC4:@STRENGTH
* TLSv1.2 (OUT), TLS handshake, Client hello (1):
* TLSv1.2 (IN), TLS handshake, Server hello (2):
* TLSv1.2 (IN), TLS handshake, Certificate (11):
* TLSv1.2 (IN), TLS handshake, Server key exchange (12):
* TLSv1.2 (IN), TLS handshake, Server finished (14):
* TLSv1.2 (OUT), TLS handshake, Client key exchange (16):
* TLSv1.2 (OUT), TLS change cipher, Change cipher spec (1):
* TLSv1.2 (OUT), TLS handshake, Finished (20):
* TLSv1.2 (IN), TLS change cipher, Change cipher spec (1):
* TLSv1.2 (IN), TLS handshake, Finished (20):
* SSL connection using TLSv1.2 / ECDHE-RSA-AES256-GCM-SHA384
* ALPN: server accepted http/1.1
* Server certificate:
*  subject: CN=<another-domain>
*  start date: Jun  4 10:06:57 2024 GMT
*  expire date: Jul  6 10:06:56 2025 GMT
*  issuer: C=BE; O=GlobalSign nv-sa; CN=GlobalSign GCC R6 AlphaSSL CA 2023
*  SSL certificate verify result: self signed certificate in certificate chain (19), continuing anyway.
* using HTTP/1.1
> HEAD / HTTP/1.1
> Host: <another-domain>
> User-Agent: curl/8.0.1
> Accept: */*
>
< HTTP/1.1 301 Moved Permanently
HTTP/1.1 301 Moved Permanently
< Server: nginx
Server: nginx
< Date: Wed, 19 Feb 2025 03:47:01 GMT
Date: Wed, 19 Feb 2025 03:47:01 GMT
< Content-Type: text/html
Content-Type: text/html
< Content-Length: 162
Content-Length: 162
< Connection: keep-alive
Connection: keep-alive
< Location: https://<another-domain>/
Location: https://<another-domain>/

<
* Connection #1 to host <another-domain> left intact
* Issue another request to this URL: 'https://<another-domain>/'
*   Trying <another-ip>:443...
* Connected to <another-domain> (<another-ip>) port 443 (#2)
* ALPN: offers h2,http/1.1
* Cipher selection: ALL:!EXPORT:!EXPORT40:!EXPORT56:!aNULL:!LOW:!RC4:@STRENGTH
* TLSv1.2 (OUT), TLS handshake, Client hello (1):
* TLSv1.2 (IN), TLS handshake, Server hello (2):
* TLSv1.2 (IN), TLS handshake, Certificate (11):
* TLSv1.2 (IN), TLS handshake, Server key exchange (12):
* TLSv1.2 (IN), TLS handshake, Server finished (14):
* TLSv1.2 (OUT), TLS handshake, Client key exchange (16):
* TLSv1.2 (OUT), TLS change cipher, Change cipher spec (1):
* TLSv1.2 (OUT), TLS handshake, Finished (20):
* TLSv1.2 (IN), TLS change cipher, Change cipher spec (1):
* TLSv1.2 (IN), TLS handshake, Finished (20):
* SSL connection using TLSv1.2 / ECDHE-RSA-AES256-GCM-SHA384
* ALPN: server accepted h2
* Server certificate:
*  subject: CN=<another-domain>
*  start date: Jun  4 10:06:57 2024 GMT
*  expire date: Jul  6 10:06:56 2025 GMT
*  issuer: C=BE; O=GlobalSign nv-sa; CN=GlobalSign GCC R6 AlphaSSL CA 2023
*  SSL certificate verify result: unable to get local issuer certificate (20), continuing anyway.
* using HTTP/2
* h2h3 [:method: HEAD]
* h2h3 [:path: /]
* h2h3 [:scheme: https]
* h2h3 [:authority: <another-domain>]
* h2h3 [user-agent: curl/8.0.1]
* h2h3 [accept: */*]
* Using Stream ID: 1 (easy handle 0x55bfa4641d20)
> HEAD / HTTP/2
> Host: <another-domain>
> user-agent: curl/8.0.1
> accept: */*
>
< HTTP/2 200
HTTP/2 200
< server: <server-name>
server: <server-name>
< date: Wed, 19 Feb 2025 03:47:01 GMT
date: Wed, 19 Feb 2025 03:47:01 GMT
< content-type: text/html; charset=utf-8
content-type: text/html; charset=utf-8
< vary: Accept-Encoding
vary: Accept-Encoding
< cache-control: no-cache, no-store
cache-control: no-cache, no-store
< pragma: no-cache
pragma: no-cache
< set-cookie: .AspNetCore.Antiforgery.9TtSrW0hzOs=CfDJ8FYCfKI4e31KrM_5VUSEEOyVXdorn8bVfHak5Xo69tEzIg6c8Qjzjt-RdNB1cP1oRjsSnCcK2XZFPVTUTpYYFS62lSzeu8E7oAVxmfHrtRDmDjFPzTmuIGaciu13SfQ-7bWjgokTMH_UJUzrazwPfHY; path=/; samesite=strict; httponly
set-cookie: .AspNetCore.Antiforgery.9TtSrW0hzOs=CfDJ8FYCfKI4e31KrM_5VUSEEOyVXdorn8bVfHak5Xo69tEzIg6c8Qjzjt-RdNB1cP1oRjsSnCcK2XZFPVTUTpYYFS62lSzeu8E7oAVxmfHrtRDmDjFPzTmuIGaciu13SfQ-7bWjgokTMH_UJUzrazwPfHY; path=/; samesite=strict; httponly
< vary: User-Agent
vary: User-Agent
< content-security-policy: style-src 'self' 'unsafe-inline' www.google-analytics.com cdn.jsdelivr.net fonts.googleapis.com cdn.linearicons.com connect.facebook.com;font-src 'self' fonts.googleapis.com fonts.gstatic.com cdn.linearicons.com;frame-src 'self' td.doubleclick.net www.googletagmanager.com connect.facebook.net www.facebook.com www.google.com www.gstatic.com www.youtube.com web.facebook.com;object-src 'none';media-src 'self';img-src 'self' www.googletagmanager.com connect.facebook.net www.facebook.com www.google.com www.gstatic.com www.google-analytics.com/collect www.google.com.vn/ads/ga-audiences;
content-security-policy: style-src 'self' 'unsafe-inline' www.google-analytics.com cdn.jsdelivr.net fonts.googleapis.com cdn.linearicons.com connect.facebook.com;font-src 'self' fonts.googleapis.com fonts.gstatic.com cdn.linearicons.com;frame-src 'self' td.doubleclick.net www.googletagmanager.com connect.facebook.net www.facebook.com www.google.com www.gstatic.com www.youtube.com web.facebook.com;object-src 'none';media-src 'self';img-src 'self' www.googletagmanager.com connect.facebook.net www.facebook.com www.google.com www.gstatic.com www.google-analytics.com/collect www.google.com.vn/ads/ga-audiences;
< x-frame-options: SAMEORIGIN
x-frame-options: SAMEORIGIN
< x-content-type-options: nosniff
x-content-type-options: nosniff
< permissions-policy: accelerometer=(), camera=(), geolocation=(), gyroscope=(), magnetometer=(), microphone=(), payment=(), usb=()
permissions-policy: accelerometer=(), camera=(), geolocation=(), gyroscope=(), magnetometer=(), microphone=(), payment=(), usb=()
< referrer-policy: no-referrer
referrer-policy: no-referrer
< x-permitted-cross-domain-policies: none
x-permitted-cross-domain-policies: none
< cross-origin-resource-policy: cross-origin
cross-origin-resource-policy: cross-origin
< cross-origin-opener-policy: cross-origin
cross-origin-opener-policy: cross-origin
< cross-origin-embedder-policy: unsafe-none
cross-origin-embedder-policy: unsafe-none
< strict-transport-security: max-age=31536000
strict-transport-security: max-age=31536000

<
* Connection #2 to host <another-domain> left intact

Mình bắt đầu tìm về nguyên nhân vì sao lại xảy ra sự kiện như trên, thì có các manh mối sau:

  • Thay đổi gì của code curl (?): theo dõi trên danh sách phiên bản của curl thì giữa 7.88.1 với 8.0.1 chỉ có 1 version 8.0.0 ở giữa, các thay đổi từ 7.88.1 lên 8.0.0 và 8.0.0 lên 8.0.1 đều không phải những ảnh hưởng thay đổi tính năng mà có thể dẫn tới kết quả như trên.
  • Thẻ -L của curl thực sự đã làm gì (?): nhận status code từ phía IIS và các header liên quan:
    • Trường hợp status code 200, không cần thêm header gì, đến được trang đích.
    • Trường hợp status code 302, thêm header location để dẫn đường tiếp cho requests tiếp theo.
  • Có điều chỉnh gì ở Máy 1 khiến cho truy cập với header Host: domain2.com trả 302 (?)