nginx-ში HTTP/1.0-ის დასაბლოკად შეამოწმე $server_protocol და დროულად დააბრუნე პასუხი: if ($server_protocol = HTTP/1.0) { return 444; } server ბლოკის შიგნით. Apache-ში %{SERVER_PROTOCOL} შეადარე mod_rewrite-ით და უპასუხე 403-ით, ან გამოიყენე <If> ბლოკი Require all denied-ით. ორივეს დაწერას ერთი წუთი სჭირდება. უფრო დიდხანს სჭირდება იმაზე ფიქრს, ღირს თუ არა ამის გაკეთება, რადგან ტრაფიკი, რომელსაც ამოწმებ (ძველი ბოტები, მასობრივი სკანერები, მოთხოვნები Host header-ის გარეშე), შერეულია რამდენიმე კანონიერ კლიენტთან, რომლებიც ჯერ კიდევ HTTP/1.0-ით მუშაობენ - ხშირად შენი საკუთარი reverse proxy-ც კი. ჯერ ჩაიწერე, მერე დაბლოკე, და უმეტეს შემთხვევაში catch-all default server უკვე აკეთებს სასარგებლო სამუშაოს თითქმის მთელ ნაწილს, HTTP/1.0-ს საერთოდ რომ არ შეეხო.
რატომ ღირს HTTP/1.0 ტრაფიკზე დაკვირვება#
HTTP/1.0 1997 წელს HTTP/1.1-მა ჩაანაცვლა. ამ საუკუნეში გამოშვებული ყველა ბრაუზერი მინიმუმ 1.1-ს იყენებს, HTTPS-ით კი HTTP/2-ზე ან HTTP/3-ზე თანხმდება. ამიტომ, როცა access log-ი HTTP/1.0 მოთხოვნებით ივსება, ისინი შენი საიტის მკითხველებისგან არ მოდის. ისინი სამი ტიპის კლიენტისგანაა:
- მასობრივი სკანერები და banner-ების ამკრეფები. ინსტრუმენტი, რომელიც მთელ IPv4 სივრცეს ათვალიერებს, ყველაზე მოკლე მოთხოვნას ეძებს, რომელზეც პასუხს მიიღებს.
GET / HTTP/1.0ცარიელი ხაზით სწორედ ასეთია:Hostheader არ არის სავალდებულო, keep-alive-ის მართვა არ სჭირდება, სერვერი კი დასრულებისას კავშირს თვითონ ხურავს. - ძველი ან ზარმაცი ბოტები. უძველეს HTTP ბიბლიოთეკებზე აგებული scraper-ები, ათწლიანი exploit სკრიპტებიდან გადაკოპირებული მოწყვლადობის ზონდები და თვითნაკეთი crawler-ები, რომლებსაც request line მყარად აქვთ ჩაწერილი.
- მანქანები, რომლებიც მანქანებს ელაპარაკებიან. load balancer-ის health check-ები, benchmark ინსტრუმენტები, მონიტორინგის სკრიპტები და - ის, რაც ადამიანებს ხვდებათ - reverse proxy-ები, რომლებიც თავის უკან მდგომ სერვერს ესაუბრებიან.
HTTP/1.0-ის საინტერესო თვისებაა, რომ Host header არასავალდებულოა. HTTP/1.1-ში ის სავალდებულოა, და nginx-იც და Apache-ც HTTP/1.1 მოთხოვნას მის გარეშე 400 Bad Request-ით უარყოფს. HTTP/1.0 მოთხოვნა Host-ის გარეშე კანონიერია, ამიტომ სერვერმა უნდა გამოიცნოს, რომელი საიტი მიაწოდოს, და ირჩევს ამ მისამართისა და პორტის default საიტს. ასე აღმოაჩენენ სკანერები, რა მუშაობს IP მისამართზე, მისი დომენური სახელების ცოდნის გარეშე: ითხოვენ სახელის გარეშე და კითხულობენ, რასაც default საიტი დააბრუნებს - CMS-ის შესვლის გვერდს, framework-ის შეცდომის გვერდს, header-ში სტეკის ვერსიას.
ესეც ღირს. უფრო ჩუმ log-ზე გაფრთხილებების მორგება ადვილია, ხოლო აპლიკაცია, რომელიც ნაგავ მოთხოვნებს არასდროს ხედავს, მათზე database query-ს არ ხარჯავს. უბრალოდ ამას "გამაგრებაში" ნუ ჩაწერ.
ჯერ ჩაიწერე, მერე დაბლოკე#
ქცევის შეცვლამდე გაიგე, ვინ გიგზავნის სინამდვილეში HTTP/1.0-ს. ორივე სერვერის default combined log ფორმატი ამას უკვე ინახავს, რადგან request line - მეთოდი, გზა და პროტოკოლი - ერთი ველია.
# How many HTTP/1.0 requests, out of how many in total$ grep -c 'HTTP/1.0"' /var/log/nginx/access.log$ wc -l < /var/log/nginx/access.log# Which user agents send them, most frequent first$ grep 'HTTP/1.0"' /var/log/nginx/access.log \ | awk -F'"' '{print $6}' | sort | uniq -c | sort -rn | head -20# Which addresses send them$ grep 'HTTP/1.0"' /var/log/nginx/access.log \ | awk '{print $1}' | sort | uniq -c | sort -rn | head -20Apache-ის ექვივალენტი იგივე ბრძანებებია, Debian-სა და Ubuntu-ზე /var/log/apache2/access.log-ის, RHEL-ის ოჯახის სისტემებზე კი /var/log/httpd/access_log-ის წინააღმდეგ. awk -F'"' ხრიკი იმიტომ მუშაობს, რომ combined ფორმატში user agent მესამე ბრჭყალებში ჩასმული ველია.
რას უნდა დაუკვირდე გამოტანაში:
- შენი საკუთარი მისამართები.
127.0.0.1, კერძო დიაპაზონი, მაგალითად10.0.0.0/8, ან load balancer-ის მისამართი. ეს მანქანები შენია და მათი დაბლოკვა რაღაცას გააფუჭებს. - ამოსაცნობი ინსტრუმენტები.
ApacheBench, მონიტორინგის პროდუქტის სახელი,HAProxy-ის health check-ები, uptime სერვისი. თითოეული ვიღაცის სამუშაოა. - ცარიელი ან უაზრო user agent-ები მისამართების გრძელი კუდიდან, რომლებიც
/,/.env,/wp-login.php,/phpmyadmin/და მსგავს გზებს ეხეთქებიან. სწორედ ეს ტრაფიკია, რომლის მოცილებაც გინდა.
დააკვირდი ერთ კვირას და არა ერთ საღამოს. ყოველკვირეული cron job-ები, ყოველთვიური ანგარიშები და გადახდის პროვაიდერი, რომელიც წელიწადში ორჯერ გირეკავს, საბოლოოდ მაინც გამოჩნდება, ხოლო კვირა ყველაზე მოკლე ფანჯარაა, რომელიც მათ უმეტესობას იჭერს. Logs worth keeping განიხილავს, რამდენ ხანს შეინახო access log-ები, რომ ასეთი შემოწმება შემდეგაც შესაძლებელი იყოს.
nginx-ში HTTP/1.0 მოთხოვნები ცალკე ფაილშიც შეგიძლია ჩაწერო, რაც ერთკვირიან დაკვირვებას უმტკივნეულოს ხდის. access_log-ის if= პარამეტრი მოთხოვნას მხოლოდ მაშინ წერს, როცა ცვლადი ცარიელი არ არის და 0-ის ტოლი არ არის:
map $server_protocol $is_http10 { default 0; "HTTP/1.0" 1;}server { # ... your existing configuration ... access_log /var/log/nginx/access.log combined; access_log /var/log/nginx/http10.log combined if=$is_http10;}Apache იგივეს აკეთებს SetEnvIf-ით, რომელსაც Request_Protocol-ზე პირდაპირ შეუძლია შედარება, და CustomLog-ით, რომელიც მხოლოდ მაშინ მუშაობს, როცა ცვლადი დაყენებულია:
SetEnvIf Request_Protocol "^HTTP/1\.0$" old_httpCustomLog ${APACHE_LOG_DIR}/http10.log combined env=old_httpჩართე a2enconf http10-log-ით და გადატვირთე reload-ით. RHEL-ის ოჯახის სისტემებზე ფაილი ჩააგდე /etc/httpd/conf.d/-ში და ${APACHE_LOG_DIR} ჩაანაცვლე logs-ით.
ჯერ catch-all default server#
ის, რაც ადამიანებს "HTTP/1.0-ის დაბლოკვაში" სინამდვილეში უნდათ, არის "შეწყვიტე იმ მოთხოვნებზე პასუხი, რომლებიც ჩემს არცერთ საიტს არ ასახელებენ". ამას უფრო სუფთა გამოსავალი აქვს, რომელიც პროტოკოლის ყველა ვერსიაზე მუშაობს: default server, რომელიც ყველაფერს უარყოფს, რათა რეალურ საიტამდე მხოლოდ რეალური hostname-ის მქონე მოთხოვნები მივიდეს.
nginx-ში ეს არის server ბლოკი, რომელიც თითოეულ პორტზე default_server-ით არის მონიშნული. მოთხოვნები Host header-ის გარეშე და მოთხოვნები, რომელთა სახელი არცერთ server_name-ს არ ემთხვევა, აქ ხვდება:
server { listen 80 default_server; listen [::]:80 default_server; server_name _; return 444;}server { listen 443 ssl default_server; listen [::]:443 ssl default_server; server_name _; ssl_reject_handshake on;}444 რეალური HTTP სტატუსი არ არის. ის nginx-ს ეუბნება, რომ კავშირი არაფრის გაგზავნის გარეშე დახუროს, ასე რომ კლიენტი არაფერს იგებს - იმასაც კი არა, რომელმა სერვერის პროგრამამ უპასუხა. 443 პორტზე TLS handshake ნებისმიერ HTTP მოთხოვნამდე ხდება, ამიტომ მხოლოდ return 444-ს ჯერ წარსადგენი სერტიფიკატი დასჭირდებოდა; ssl_reject_handshake on (nginx 1.19.4 და უფრო ახალი) handshake-ს იმ სახელებზე უარყოფს, რომლებიც არ გაქვს მორგებული, სერტიფიკატის გარეშე. უფრო ძველ nginx-ზე catch-all-ს self-signed სერტიფიკატი უნდა მისცე. nginx reverse proxy guide განიხილავს დანარჩენ სტრუქტურას, მათ შორის იმასაც, რატომ შეიძლება მხოლოდ ერთ ბლოკს ჰქონდეს default_server თითო პორტზე.
Apache-ს default_server საკვანძო სიტყვა არ აქვს. მისამართისა და პორტისთვის პირველად ჩატვირთული VirtualHost არის default, ამიტომ ეძახის Debian თავის default საიტს 000-default.conf-ს. შეცვალე მისი შიგთავსი vhost-ით, რომელიც ყველაფერს უარყოფს:
<VirtualHost *:80> ServerName default.invalid <Location /> Require all denied </Location> ErrorLog ${APACHE_LOG_DIR}/default-error.log CustomLog ${APACHE_LOG_DIR}/default-access.log combined</VirtualHost>Apache კავშირს nginx-ივით ჩუმად ვერ წყვეტს, ამიტომ აბრუნებს 403 Forbidden-ს. .invalid უმაღლესი დონის დომენი დარეზერვებულია და არასდროს გარჩევდება, რაც იმას ნიშნავს, რომ არცერთი რეალური მოთხოვნა სახელით მას არ დაემთხვევა.
catch-all-ის არსებობისას Host-გარეშე HTTP/1.0 მოთხოვნა უკვე არაფერ სასარგებლოს არ იღებს. ბევრი საიტისთვის ესეც საკმარისია, ხოლო დარჩენილი HTTP/1.0 ტრაფიკი - მოთხოვნები, რომლებიც შენს დომენს ასახელებენ - იმდენად უვნებელია, რომ ხელი არ უნდა ახლო. თუ მაინც გინდა მისი მოცილება, წაიკითხე შემდეგი ნაწილი.
HTTP/1.0-ის დაბლოკვა nginx-ში#
$server_protocol-ში ინახება პროტოკოლი, რომელიც კლიენტმა გამოიყენა: HTTP/1.0, HTTP/1.1, HTTP/2.0 ან HTTP/3.0. უმარტივესი დაბლოკვა მას პირდაპირ ადარებს:
server { listen 80; server_name example.com www.example.com; if ($server_protocol = HTTP/1.0) { return 444; } # ... the rest of the site ...}ჩვეულებრივი გაფრთხილება, რომ nginx-ში if საშიშია, ეხება location-ის შიგნით მდგარ if-ს, რომელიც სხვა დირექტივებთანაა შერწყმული. server დონეზე მდგარი if, რომელიც მხოლოდ return-ს შეიცავს, ერთ-ერთი იმ შემთხვევაა, რომელსაც nginx-ის დოკუმენტაცია უსაფრთხოდ მიიჩნევს.
HTTP/1.0 პირდაპირ შეადარე. წესი if ($server_protocol != HTTP/1.1) ექვივალენტურად გამოიყურება, მაგრამ არ არის: ის ყველა HTTP/2 და HTTP/3 ვიზიტორსაც ბლოკავს, რაც HTTPS საიტზე თითქმის ყველაა.
map მიდგომა, გამონაკლისებით
მარტივი if ყველას ბლოკავს. როგორც კი გამონაკლისი გჭირდება - შენი მონიტორინგის სერვერი, load balancer, 127.0.0.1 - map უკეთ იკითხება და ყველა საიტისთვის ერთ ადგილას ცხოვრობს. geo ნდობით აღჭურვილ მისამართებს ნიშნავს, map კი ორ ცვლადს ერთ გადაწყვეტილებად აერთიანებს:
geo $http10_trusted { default 0; 127.0.0.1 1; 10.0.0.0/8 1; 203.0.113.25 1; # monitoring host}map "$server_protocol:$http10_trusted" $http10_block { default 0; "HTTP/1.0:0" 1;}შემდეგ თითოეულ server ბლოკში, რომელმაც ეს უნდა აღასრულოს:
if ($http10_block) { return 444;}conf.d-ის ფაილები http კონტექსტში ჩაირთვება, სადაც map-ს და geo-ს უნდა ეცხოვრათ. ორივე ზარმაცად ფასდება, მხოლოდ მაშინ, როცა ცვლადი გამოიყენება, ამიტომ მათი აღწერა არაფერი ღირს იმ საიტებზე, რომლებიც მათ არ იყენებენ. მისამართის ნაცვლად user agent-ის გამონაკლისში გასატანად $http_user_agent დაამატე map-ის წყაროში და გამოიყენე regex გასაღებები, მაგრამ გახსოვდეს, რომ user agent არის ის, რასაც კლიენტი ამბობს.
444, 426 თუ 403
რომელი პასუხი გაგზავნო, იმაზეა დამოკიდებული, ვინ უნდა წაიკითხოს.
| პასუხი | რას ხედავს კლიენტი | გამოიყენე, როცა |
|---|---|---|
444 | კავშირი დაიხურა, ბაიტების გარეშე | ტრაფიკი ნაგავია და არაფერს იმსახურებს |
426 | Upgrade Required, მიზეზით | რეალურ კლიენტს შეიძლება ეთქვას |
403 | Forbidden | გინდა ჩვეულებრივი, კარგად გასაგები უარი |
426 Upgrade Required თავაზიანი, სტანდარტზე მორგებული პასუხია: ის ამბობს, რომ მოთხოვნა გასაგებია და უფრო ახალი პროტოკოლია საჭირო. HTTP სპეციფიკაცია ელის, რომ Upgrade header პროტოკოლს დაასახელებს, nginx-ში კი add_header if-ის შიგნით მხოლოდ location დონეზეა დაშვებული, ამიტომ სრული ვერსია ასე გამოიყურება:
location / { if ($http10_block) { add_header Upgrade "HTTP/1.1" always; add_header Connection "Upgrade" always; return 426 "HTTP/1.1 or newer is required.\n"; } # ... proxy_pass, try_files, etc ...}always მნიშვნელოვანია: მის გარეშე add_header მხოლოდ წარმატებისა და გადამისამართების კოდების მოკლე სიაზე მუშაობს და header-ები 426-დან უჩუმრად გაქრებოდა. პრაქტიკაში უმეტესი საიტისთვის 444 სწორი არჩევანია. სკანერი სტატუს ხაზებს არ კითხულობს, კანონიერი კლიენტი კი, რომელიც ცარიელ პასუხს იღებს, ნათელ შეცდომას გამოიმუშავებს (curl: (52) Empty reply from server), რომელიც ზუსტად გეუბნება, სად უნდა ეძებო.
HTTP/1.0-ის დაბლოკვა Apache-ში#
Apache-ში ამის გაკეთების სამი გზა გაქვს. აირჩიე ერთი; მათი შერევა შემდეგი ადამიანის დებაგინგს აუტანელს ხდის.
mod_rewrite SERVER_PROTOCOL-ზე ან THE_REQUEST-ზე
ეს ვერსიაა, რომელსაც უმეტესი გზამკვლევი აჩვენებს, და ის მუშაობს როგორც მთავარ კონფიგურაციაში, ისე .htaccess-ში:
RewriteEngine OnRewriteCond %{SERVER_PROTOCOL} =HTTP/1.0RewriteRule ^ - [F]%{SERVER_PROTOCOL} პროტოკოლის სტრიქონს ინახავს, = პრეფიქსი კი შედარებას regex-ის ნაცვლად ზუსტ სტრიქონულ შედარებად აქცევს. [F] აბრუნებს 403 Forbidden-ს და დამუშავებას წყვეტს. 426-ის გასაგზავნად გამოიყენე RewriteRule ^ - [R=426,L] - როცა R-ისთვის მითითებული სტატუსი 3xx დიაპაზონს გარეთაა, mod_rewrite ჩანაცვლებას უგულებელყოფს და უბრალოდ ამ კოდს აბრუნებს.
%{THE_REQUEST} არის სრული თავდაპირველი request line, მაგალითად GET /index.php HTTP/1.0. მასზე შედარება ამ მიზნისთვის ექვივალენტურია:
RewriteCond %{THE_REQUEST} HTTP/1\.0$RewriteRule ^ - [F]სხვაობა სხვაგან აქვს მნიშვნელობა: THE_REQUEST არასდროს იცვლება ადრინდელი rewrite-ებით ან შიდა გადამისამართებებით, ამიტომ სწორედ მას იღებენ ხელში, როცა ნედლ მოთხოვნაზე ბლოკავენ. პროტოკოლის შემოწმებისთვის SERVER_PROTOCOL უფრო გასაგებად იკითხება. გამონაკლისები ერთი დამატებითი პირობაა: წესამდე მოთავსებული RewriteCond %{REMOTE_ADDR} !^10\. კერძო დიაპაზონს გამოტოვებს.
.htaccess-ის შიგნით mod_rewrite მხოლოდ მაშინ მუშაობს, თუ დირექტორიის AllowOverride შეიცავს FileInfo-ს (ან All-ს). თუ წესები არაფერს აკეთებს, ეს არის პირველი, რაც უნდა შეამოწმო, შემდეგ კი - საერთოდ ჩართულია თუ არა mod_rewrite (a2enmod rewrite Debian-ზე).
Require გამოსახულებით, mod_rewrite-ის გარეშე
Apache 2.4-ის გამოსახულებების parser-იც იცნობს SERVER_PROTOCOL-ს, ამიტომ იგივე წესი წერის ნაცვლად წვდომის კონტროლით შეიძლება დაიწეროს:
<If "%{SERVER_PROTOCOL} == 'HTTP/1.0' && ! -R '10.0.0.0/8'"> Require all denied</If>-R ამოწმებს, არის თუ არა კლიენტის მისამართი ქვექსელის შიგნით. ალტერნატივად, ხელახლა გამოიყენე old_http ცვლადი logging ნაწილიდან და <RequireAll> ბლოკში Require all granted-ის გვერდით ჩაწერე Require not env old_http. ორივე ფორმა 403-ს აბრუნებს. ეს მიდგომა rewrite წესებზე უფრო მარტივად იკითხება და არ ერევა იმ rewrite-ში, რომელსაც შენი CMS უკვე აკეთებს, რაც WordPress-ის ან Laravel-ის .htaccess-ზე რეალური უპირატესობაა.
რას აკეთებს და რას არ აკეთებს HttpProtocolOptions
HttpProtocolOptions ამ კითხვის თითქმის ყველა პასუხში ჩანს და HTTP/1.0-ს არ ბლოკავს. ის Apache 2.4.24-ში დაემატა და აკონტროლებს, რამდენად მკაცრად იკითხება request line და header-ები. მისი default არის Strict LenientMethods Allow0.9, ოფცია კი, რომელსაც ადამიანები ეძებენ, ასეთია:
HttpProtocolOptions Strict Require1.0Require1.0 HTTP/0.9-ს უარყოფს - 1996 წლამდელ ფორმას, სადაც მოთხოვნა მხოლოდ GET /-ია, ვერსიისა და header-ების გარეშე. HTTP/1.0 და უფრო ახალი მაინც მიიღება. მისი დაყენება ღირს, რადგან ათწლეულებია არაფერი კანონიერი 0.9-ით არ მუშაობს, მაგრამ ეს სხვა (და უფრო მცირე) პრობლემის სხვა გამოსწორებაა. Strict უკვე default-ია და Apache-ს აიძულებს, არასწორი request line-ები და header-ები 400-ით უარყოს; დატოვე ჩართული, თუ ძველი კლიენტი Unsafe-ის გამოყენებას არ გაიძულებს.
ტესტირება curl-ით#
curl-ს მოთხოვნისას HTTP/1.0-ით საუბარი შეუძლია, რაც შემოწმებებს სწრაფს ხდის. გაუშვი ისინი მანქანიდან, რომელიც შენს გამონაკლისების სიაში არ არის.
# HTTP/1.0 with a Host header - should be blocked if you block 1.0$ curl --http1.0 -sv -o /dev/null http://example.com/# HTTP/1.0 with no Host header - should hit the catch-all$ curl --http1.0 -sv -o /dev/null -H "Host:" http://203.0.113.10/# HTTP/1.1, the control - should work normally$ curl --http1.1 -sv -o /dev/null http://example.com/# Over HTTPS, where browsers will negotiate HTTP/2$ curl --http1.0 -sv -o /dev/null https://example.com/-H "Host:" ორწერტილის შემდეგ არაფრით curl-ს ეუბნება, რომ header, რომელსაც სხვა შემთხვევაში დაამატებდა, მოაშოროს, და ეს ერთადერთი გზაა, რომ Host-გარეშე მოთხოვნა გააგზავნოს. რას უნდა ელოდო:
- nginx-ის
444ჩანს როგორცcurl: (52) Empty reply from server. 403ან426ჩანს როგორც< HTTP/1.1 403 Forbiddenან მსგავსი verbose გამოტანაში. გაითვალისწინე, რომ სერვერი სტატუს ხაზში საკუთარი უმაღლესი ვერსიით პასუხობს მაშინაც, როცა მოთხოვნა 1.0 იყო; ეს ნორმალურია.- HTTP/1.1 მოთხოვნა Host header-ის გარეშე ორივე სერვერზე
400-ით უარიყოფა შენი წესების გაშვებამდეც.
ყველაზე ნედლი ტესტისთვის, კლიენტის ლოგიკის გარეშე, მოთხოვნა თვითონ დაწერე:
$ printf 'GET / HTTP/1.0\r\n\r\n' | nc example.com 80ტესტირების შემდეგ შეამოწმე, რომ გამონაკლისები კვლავ მუშაობს - პირველი ბრძანება გაუშვი სანდო მისამართიდან - და დარწმუნდი, რომ log-ები დაბლოკილ მოთხოვნებს შენი არჩეული სტატუსით აჩვენებს. reload-ამდე ყოველთვის გაუშვი nginx -t ან apachectl configtest - map-ში შეცდომა სერვერზე ყველა საიტს ჩამოაგდებს და არა მხოლოდ იმას, რომელსაც ცვლიდი.
კანონიერი კლიენტები, რომლებიც შეიძლება გაფუჭდეს#
ეს ნაწილი ორჯერ წაიკითხე. თითოეული მათგანი default-ად ან გავრცელებულ კონფიგურაციაში მაინც HTTP/1.0-ს აგზავნის:
- თვითონ nginx, როგორც proxy.
proxy_http_version-ის default არის1.0. თუ nginx სხვა nginx-ის ან Apache-ის წინ გიდგას, backend ყველა მოთხოვნას HTTP/1.0-ად ხედავს, backend-ზე პროტოკოლის დაბლოკვა კი მთელ საიტს გაფუჭებს. ან front proxy-ზე დააყენეproxy_http_version 1.1;(რაც ისედაც გინდა, keep-alive-სა და websocket-ებისთვის), ან წესი მხოლოდ გარე server-ზე აამუშავე. - Load balancer-ის health check-ები. HAProxy-ის
option httpchkHTTP/1.0 მოთხოვნას აგზავნის, თუ ვერსიას არ მიუთითებ. დაბლოკილი health check backend-ს გამორთულად მონიშნავს და load balancer თვითონ გამოგირთავს საიტს. - ApacheBench.
abმხოლოდ HTTP/1.0-ით მუშაობს. შენი load test ყველა მოთხოვნას წარუმატებლად ჩათვლის და ერთ საათს აპლიკაციაზე ეჭვით გაატარებ. - მონიტორინგი და uptime შემოწმებები. ზოგიერთი უფრო ძველი შემოწმება და plugin ჯერ კიდევ 1.0-ს იყენებს default-ად. მათ დაკვირვების კვირაში მოძებნე და არა მაშინ, როცა გაფრთხილებები შეწყდება.
- ძალიან ძველი command-line ინსტრუმენტები და ჩაშენებული კლიენტები. ძველი
wgetვერსიები, პრინტერები, რაუტერები, IoT firmware და უძველეს ბიბლიოთეკებზე დაწერილი სკრიპტები. თუ ერთ-ერთი მათგანი შენს საიტზე webhook-ს აგზავნის, ის უჩუმრად შეწყვეტს მუშაობას. - ძველი სისტემების webhook-ები. გადახდის, მიწოდებისა და ERP ინტეგრაციებში ცხოვრობს ხანგრძლივი ცხოვრების legacy კოდი. ისინი იშვიათია, ზუსტად ამიტომ ტოვებს მათ ერთი შუადღის log-ები შეუმჩნეველს.
პირველი პრობლემის უფრო ფაქიზი ვერსიაც არსებობს: proxy, რომელსაც შენ არ აკონტროლებ. როცა საიტი CDN-ის, ჰოსტინგ პროვაიდერის front end-ის ან სხვა reverse proxy-ის უკან დგას, ვერსია, რომელსაც ხედავ, არის ის, რომლითაც proxy-მ შენამდე მოაღწია და არა ის, რომელიც ვიზიტორმა გამოიყენა. RE:NODE-ის app და web გეგმებზე, გეგმის proxy სლოტით მიბმული დომენი ასე მუშაობს: სლოტი სერტიფიკატს ამუშავებს და რეალურ კლიენტის მისამართს X-Forwarded-For-ში გადასცემს. წესის დაწერამდე შეამოწმე $server_protocol (ან %H Apache-ის log ფორმატში) შენს სერვერზე: თუ ყველა მოთხოვნა ერთი და იმავე ვერსიით მოდის, ამ ფენაზე პროტოკოლის შემოწმება ან არაფერს ბლოკავს, ან ყველაფერს. dedicated server-ზე, სადაც შენი nginx ინტერნეტში პირველია, log-ში ნანახი ვერსია თვით ვიზიტორისაა.
რას არ აჩერებს ეს#
ზღვრის გულწრფელად აღიარება იმედგაცრუებას გიხსნის. კლიენტი, რომელიც HTTP/1.1-ს და სწორ Host header-ს აგზავნის, ამ პოსტის ყველა წესს პირდაპირ გაივლის, თანამედროვე სკანირების framework-ები, credential-stuffing ინსტრუმენტები და scraper-ები კი ყველა ასე იქცევა. პროტოკოლის შემოწმება ფონური ხმაურის ყველაზე ზარმაც ფენას ფილტრავს; გადაწყვეტილ თავდამსხმელზე ან კარგად დაწერილ ბოტზე ის არაფერს აკეთებს.
ტრაფიკისთვის, რომელიც მას გადის, სხვა ინსტრუმენტებია საჭირო. Rate limiting ზღუდავს, რამდენად სწრაფად შეუძლია ერთ კლიენტს ძვირ endpoint-ებს, როგორიცაა login ფორმები, ეხეთქოს. Fail2ban კითხულობს log-ებს და განმეორებითი ცუდი მოთხოვნების შემდეგ firewall-ზე მისამართებს ბანავს - ხოლო logging ნაწილის http10.log მარტივი jail-ის შესასვლელი მონაცემია, თუ გინდა, რომ მუდმივი დამრღვევები სრულად დაიბანოს. Firewall rules that matter განიხილავს ყველა იმ პორტის დახურვას, რომლის გახსნაც საჭირო არ არის, და ეს გაცილებით მეტ შეტევის ზედაპირს აშორებს, ვიდრე ნებისმიერი რამ HTTP ფენაზე. WordPress საიტისთვის WordPress security hardening ეხება იმ გზებს, რომლებსაც ეს სკანერები ჩვეულებრივ ეძებენ.
მაშასადამე, სამუშაოს გონივრული თანმიმდევრობა ასეთია: მოაწყე catch-all default server, ერთი კვირა ჩაიწერე HTTP/1.0, დაამატე გამონაკლისები ყველაფერზე, რაც შენია და გამოჩნდება, დაბლოკე 444-ით nginx-ში ან 403-ით Apache-ში, გატესტე curl-ით და ცალკე log-ი გააგრძელე, რომ იმ დღეს შეამჩნიო, როცა რაღაც კანონიერი გაფუჭდება.
FAQ#
HTTP/1.0-ის დაბლოკვა საძიებო სისტემების crawler-ებზე იმოქმედებს?
არა. Googlebot, Bingbot და სხვა მსხვილი crawler-ები HTTP/1.1-ს ან HTTP/2-ს იყენებენ. თუ რომელიმე უცნობი crawler, რომელიც შენთვის მნიშვნელოვანია, დაკვირვების კვირაში შენს HTTP/1.0 log-ში გამოჩნდება, დაბლოკვამდე მისთვის გამონაკლისი დაამატე.
nginx-ში 444 გამოვიყენო თუ 403?
444 - ტრაფიკისთვის, რომლის ნაგვობაშიც დარწმუნებული ხარ, რადგან კლიენტს არაფერს აძლევს - იმის დადასტურებასაც კი არა, რომელმა სერვერმა უპასუხა. 403 ან 426 - როცა რეალურ კლიენტზე შეიძლება იმოქმედოს და მის მფლობელს წასაკითხი შეცდომა სჭირდება, რომ გაარკვიოს, რა შეიცვალა.
Apache-ში HttpProtocolOptions Require1.0 ბლოკავს HTTP/1.0-ს?
არა, სახელის მიუხედავად. ის მინიმუმ 1.0 ვერსიას მოითხოვს, რაც ნიშნავს, რომ HTTP/0.9-ს უარყოფს. თვით HTTP/1.0-ის უარსაყოფად გამოიყენე mod_rewrite პირობა %{SERVER_PROTOCOL}-ზე ან <If> ბლოკი Require all denied-ით.
შემიძლია Host header-ის გარეშე მოთხოვნები დავბლოკო, მაგრამ HTTP/1.0 მასთან ერთად დავუშვა?
დიახ, და ხშირად ეს უკეთესი კომპრომისია. nginx-ში catch-all default_server ან Apache-ში პირველად ჩატვირთული deny-all VirtualHost იღებს ყველა მოთხოვნას, რომელიც არცერთ ცნობილ საიტს არ ასახელებს, მათ შორის ყველა Host-გარეშეს. მოთხოვნებზე, რომლებიც შენს დომენს ასახელებენ, ვერსიის მიუხედავად, ეს არ მოქმედებს.
რატომ ჩამოვარდა მთელი საიტი HTTP/1.0-ის დაბლოკვის შემდეგ?
თითქმის დანამდვილებით იმიტომ, რომ შენ მიერ შეცვლილი სერვერის წინ სხვა proxy დგას და მასთან HTTP/1.0-ით საუბრობს - nginx ამას default-ად აკეთებს. მოაშორე წესი backend-ს, გამოიყენე გარე proxy-ზე და იქვე დააყენე proxy_http_version 1.1.
ეხმარება ეს DDoS შეტევის წინააღმდეგ?
მნიშვნელოვნად არა. ფლუდ ტრაფიკს HTTP/1.0 არ სჭირდება, და სანამ nginx კავშირს დახურავს, ის უკვე მიღებულია. მოცულობით შეტევებს ვებ სერვერის ზემოთ ებრძვიან და არა მის კონფიგურაციაში.


