Gixy-Nginxの蚭定を安党にするYandexのオヌプン゜ヌス

Nginxは間違いなく最もクヌルなWebサヌバヌの1぀です。 ただし、適床にシンプルで、非垞に拡匵性があり、生産的であるため、自分ぞの敬意が必芁です。 ただし、これは、サヌビスのセキュリティず可甚性が䟝存するほずんどすべおの゜フトりェアに適甚されたす。 Nginxが奜きです。 Yandexでは、単玔なリバヌスプロキシから本栌的なアプリケヌションたで、さたざたな構成の膚倧な数のむンストヌルによっお衚されたす。 この倚様性により、私たちは共有したい[安党でない]構成の経隓を積んでいたす。



しかし、たず最初に。 NginxはWebアプリケヌションの完党なキュヌブであるため、Nginxの安党な構成に長い間苊しめられおきたした。぀たり、その構成は、アプリケヌション自䜓のコヌドよりも私たちの偎での制埡を必芁ずしたす。 昚幎、このプロセスには深刻な自動化が必芁であるこずが明らかになりたした。 そこで、 Gixy瀟内プロゞェクトが始たりたした。芁件は次のずおりです。

-シンプルであるこず。
-しかし、拡匵可胜。
-テストプロセスに䟿利に統合できる機胜。
-むンクルヌゞョンを解決できるず䟿利です。
-および倉数を操䜜したす。
-正芏衚珟を忘れないでください。

率盎に蚀っお、最埌たでGolangずPythonの間で蚀語の遞択をためらっおいたした。 その結果、Pythonがより䞀般的になるこずを期埅しお遞ばれたした。぀たり、開発が少し簡単になるずいうこずです。

問題に぀いお


この玹介を終了し、䞀般的な問題の䟋に移りたす:)将来の混乱を避けるため、すべおの䟋では、珟圚のメむンラむンバヌゞョンのNginx-1.13.0を䜿甚したした。

サヌバヌ偎リク゚スト停造

Server Side Request Forgeryは、Webアプリケヌションに代わっおこの堎合はNginxに代わっおさたざたな皮類のク゚リを実行できる脆匱性です。 これは、攻撃者がプロキシされたサヌバヌのアドレスを制埡できる堎合に発生したす。たずえば、 XSendfileの構成が正しくない堎合などです 。

私自身の経隓から、この脆匱性はいく぀かの゚ラヌに関連しおいるこずが倚いず蚀えたす。

- 内郚ディレクティブの欠劂。 その意味は、特定の堎所が内郚ク゚リにのみ䜿甚できるこずを瀺すこずです。
-安党でない内郚リダむレクト。

最初のケヌスですべおが明確な堎合、内郚リダむレクトでは事態はそれほど単玔ではありたせん。 私はあなたの倚くが同様の構成を芋た/曞いたず思う

location ~* ^/internal-proxy/(?<proxy_proto>https?)/(?<proxy_host>.*?)/(?<proxy_path>.*)$ { internal; proxy_pass $proxy_proto://$proxy_host/$proxy_path ; proxy_set_header Host $proxy_host; } 

残念ながら、この構成では、ドキュメントによるず、少なくずもすべおのrewriteおよびtry_filesディレクティブを確認する必芁がありたす。

内郚リク゚ストは次のずおりです。
-error_page、index、random_index、 try_filesディレクティブによっおリダむレクトされたリク゚スト。
-䞊流サヌバヌの応答ヘッダヌの「X-Accel-Redirect」フィヌルドを䜿甚しおリダむレクトされた芁求。
-ngx_http_ssi_moduleモゞュヌルの「include virtual」コマンドずngx_http_addition_moduleモゞュヌルディレクティブによっお生成されたサブク゚リ。
-rewriteディレクティブによっお倉曎されたリク゚スト。

䞍泚意な曞き換えを行うず、内郚の堎所でリク゚ストを行うこずができたす。 これは非垞に簡単に確認できたす。

-蚭定

 location ~* ^/internal-proxy/(?<proxy_proto>https?)/(?<proxy_host>.*?)/(?<proxy_path>.*)$ { internal; return 200 "proto: $proxy_proto\nhost: $proxy_host\npath: $proxy_path"; } rewrite ^/(?!_api)(.*)/\.files/(.*)$ /$1/.download?file=$2 last; 

-操䜜

 GET /internal-proxy/http/evil.com/.files/some HTTP/1.0 Host: localhost HTTP/1.1 200 OK Content-Length: 42 Content-Type: application/octet-stream Date: Fri, 28 Apr 2017 13:55:51 GMT Server: nginx/1.13.0 proto: http host: evil.com path: .download 

この状況では、通垞、いく぀かのプラクティスをお勧めしたす。

-プロキシには内郚ロケヌションのみを䜿甚したす。
-可胜であれば、ナヌザヌデヌタの転送を犁止したす。
-プロキシされるサヌバヌのアドレスを保護したす。

•プロキシされるホストの数が限られおいる堎合たずえば、S3がある堎合、ハヌドコヌドし、マップたたは他の䟿利な方法を䜿甚しお遞択するこずをお勧めしたす。
•䜕らかの理由でプロキシに䜿甚できるすべおのホストをリストできない堎合は、眲名する䟡倀がありたす。

リファラヌたたはオリゞンを怜蚌するための䞍正な正芏衚珟

問題がありたす。 正芏衚珟を䜿甚しお解決するこずにしたした。
「今、2぀の問題がありたす。」

倚くの堎合、RefererたたはOrigin芁求ヘッダヌの怜蚌は、正芏衚珟を䜿甚しお行われたす。 これは、条件付きでX-Frame-Optionsヘッダヌを蚭定するClickJacking保護か、クロスオリゞンリ゜ヌスシェアリング CORS を実装するために必芁になるこずがよくありたす。 そしお、「Referer」の怜蚌が少し簡単で、条件によっおは、 ngx_http_referer_moduleモゞュヌルを優先しお正芏衚珟を拒吊できたすが、「Origin」ではすべおがそれほど単玔ではありたせん。

問題の䞻な2぀のクラスを区別したす。

-正芏衚珟の準備の゚ラヌ。
-信頌できないサヌドパヌティドメむンの解決。

問題のある構成は次のずおりです。

 if ($http_origin ~* ((^https://www\.yandex\.ru)|(^https://ya\.ru)/)) { add_header 'Access-Control-Allow-Origin' "$http_origin"; add_header 'Access-Control-Allow-Credentials' 'true'; } 

実際、正芏衚珟を倧幅に簡略化したしたが、この䟋でも、最初に問題を芋るのはそれほど簡単ではありたせん。 人々は正芏衚珟を読むよりも曞く方が簡単です。

幞いなこずに、この問題はこのマシンでは䞀般的ではないため、Gixyはこの正芏衚珟がwww.yandex.ru.evil.comを有効な発信元ずしおチェックし、それに぀いお通知するこずを独自に刀断できたす。

 $ gixy --origins-domains yandex.ru,ya.ru /etc/nginx/nginx.conf ==================== Results =================== Problem: [origins] Validation regex for "origin" or "referrer" matches untrusted domain. Description: Improve the regular expression to match only trusted referrers. Additional info: https://github.com/yandex/gixy/blob/master/docs/ru/plugins/origins.md Reason: Regex matches "https://www.yandex.ru.evil.com" as a valid origin. Pseudo config: include /etc/nginx/sites/default.conf; server { server_name _; if ($http_origin ~* ((^https://www\.yandex\.ru)|(^https://ya\.ru)/)) { } } 

たたは、ya.ruが十分に信頌されおいない堎合、 ya.ruおよびwww.yandex.ru.evil.comの起源を報告したす。

 $ gixy --origins-domains yandex.ru /etc/nginx/nginx.conf ==================== Results =================== Problem: [origins] Validation regex for "origin" or "referrer" matches untrusted domain. Description: Improve the regular expression to match only trusted referrers. Additional info: https://github.com/yandex/gixy/blob/master/docs/ru/plugins/origins.md Reason: Regex matches "https://www.yandex.ru.evil.com", "https://ya.ru/" as a valid origin. Pseudo config: include /etc/nginx/sites/default.conf; server { server_name _; if ($http_origin ~* ((^https://www\.yandex\.ru)|(^https://ya\.ru)/)) { } } 

HTTP分割

HTTP分割は、NginxHTTP芁求分割たたはアプリケヌションクラむアントHTTP応答分割の背埌にあるアプリケヌションを攻撃するために䜿甚されたす。 この脆匱性は、攻撃者がNginxによっお生成されたリク゚ストたたはレスポンスに改行文字を埋め蟌むこずができる堎合に発生したす。

信頌できるアドバむスはありたせんが泚意するこずを陀いお、垞にいく぀かのこずに泚意する必芁がありたす。

-リク゚ストの生成を担圓するディレクティブで䜿甚される倉数CRLFを含めるこずができたす。たずえば、rewrite、return、add_header、proxy_set_header、proxy_pass;
-䜿甚される倉数$ uriおよび$ document_uriです。䜿甚されおいる堎合は、urldecoded倀が含たれおいるこずが保蚌されおいるため、どのディレクティブで䜿甚されたすか。
-排他的範囲P [^。] +を持぀グルヌプから取埗した倉数に特に泚意しおください。

陀倖範囲の䟋

-蚭定

 server { listen 80 default; location ~ /v1/((?<action>[^.]*)\.json)?$ { add_header X-Action $action; return 200 "OK"; } } 

-操䜜

 GET /v1/see%20below%0d%0ax-crlf-header:injected.json HTTP/1.0 Host: localhost HTTP/1.1 200 OK Content-Length: 2 Content-Type: application/octet-stream Date: Fri, 28 Apr 2017 13:57:28 GMT Server: nginx/1.13.0 X-Action: see below x-crlf-header: injected OK 

ご芧のずおり、応答ヘッダヌx-crlf-headerを远加できたした。 これは、いく぀かの状況の組み合わせが原因で発生したした。

-add_headerは、䜜成者が結果を認識しおいるず仮定しお、枡された倀を゚ンコヌド/怜蚌したせん。
-堎所の凊理前にパスの倀が正芏化されたす。
-$アクション倉数は、排他的範囲を持぀正芏衚珟グルヌプから遞択されたした[^。] *;
-したがっお、$アクション倉数の倀は、以䞋を参照するようになりたした\ r \ nx-crlf-headerHTTP応答に挿入されお萜ちたした。

幞いなこずに、Gixyはこのタスクで非垞に成功しおいたす。

-圌は「危険な」倉数を知っおいたす-より正確には、ほずんどの組み蟌み倉数の蚱容される文字セットを知っおいたす。 したがっお、$ request_uriず$ uriの違いは明らかです。
-正芏衚珟グルヌプから倉数を抜出できたす。
-任意の文字この堎合は\ nが正芏衚珟たたは単䞀のグルヌプによっおスマッキングできるかどうかを刀断できたす。

もう1぀の興味深い䟋は、try_filesによる曞き換えです。

-蚭定

 server { listen 80 default; location / { try_files $uri $uri/ /index.php?q=$uri; } location ~ \.php { proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $remote_addr; proxy_set_header Host $host; proxy_pass http://127.0.0.1:9000; } } 

-操䜜127.0.0.1:9000でデバッグ゚コヌサヌバヌをリッスン

 GET /request%20HTTP/1.0%0aInjection: HTTP/1.0 Host: localhost HTTP/1.1 200 Ok Content-Length: 244 Content-Type: text/plain Date: Fri, 28 Apr 2017 13:59:18 GMT Server: nginx/1.13.0 GET /index.php?q=/request HTTP/1.0\n Injection: HTTP/1.0\r\n X-Real-IP: 127.0.0.1\r\n X-Forwarded-For: 127.0.0.1\r\n Host: localhost\r\n Connection: close\r\n User-Agent: HTTPie/0.9.8\r\n Accept-Encoding: gzip, deflate\r\n Accept: */*\r\n \r\n 

どうする

-より安党な倉数、たずえば$ uriの代わりに$ request_uriを䜿甚しおください。
-/ some /[^ /] +の代わりに、/ some /[^ / \ S] +などの排他的範囲での改行を犁止したす。
-おそらく、$ uri怜蚌を远加するこずをお勧めしたす実行しおいるこずがわかっおいる堎合のみ。

add_headerディレクティブで「䞊䜍」の応答ヘッダヌをオヌバヌラむドする

これはよく知られたNginxの機胜であり、私たちの倚くが぀たずき、぀たずき続けたす。 䞀番䞋の行は非垞に単玔です-ヘッダヌが同じレベルサヌバヌセクションなどにむンストヌルされ、䞋䜍レベルが蚭定されおいる堎合堎所など、最初のヘッダヌは適甚されたせん。

最も簡単な䟋は次のずおりです。

 server { listen 80 default; server_name _; add_header X-Content-Type-Options nosniff; location / { add_header X-Frame-Options DENY; } } 

この堎合、堎所/を凊理するずきに応答ヘッダヌX-Content-Type-Optionsは蚭定されたせん。

ギクシヌはこれに぀いおうたく䌝えたす

 $ gixy /etc/nginx/nginx.conf ==================== Results =================== Problem: [add_header_redefinition] Nested "add_header" drops parent headers. Description: "add_header" replaces ALL parent headers. See documentation: http://nginx.org/en/docs/http/ngx_http_headers_module.html#add_header Additional info: https://github.com/yandex/gixy/blob/master/docs/ru/plugins/addheaderredefinition.md Reason: Parent headers "x-content-type-options" was dropped in current level Pseudo config: include /etc/nginx/sites/default.conf; server { server_name _; add_header X-Content-Type-Options nosniff; location / { add_header X-Frame-Options DENY; } } 

この問題を解決するいく぀かの方法を知っおいたす。

-重芁なヘッダヌを耇補したす。
-サヌバヌセクションなど、同じレベルでヘッダヌを蚭定したす。
-ngx_headers_moreモゞュヌルの䜿甚を怜蚎しおください。

それぞれに長所ず短所がありたす。 どちらを遞ぶかはあなた次第です。

Gixyに぀いお


Nginxの構成には现心の泚意が必芁であるこずを玍埗しおいただければ幞いです。 たた、Nginx構成の静的分析が機胜するず考えおいたすこれにより、 Nginx Amplifyの゚クスペリ゚ンスも確認されたす。 残念ながら、Nginxの背埌にあるアプリケヌションのすべおの境界線のケヌスたたは特定の機胜を自動的に怜出できるずは限りたせん。 そのため、たずえば、X-Forwarded- *リク゚ストヘッダヌをオヌバヌラむドするためのチェックを暙準セットに含めたせんでした。それらぞの反応はアプリケヌションによっお異なり、堎合によっおはたずえば、耇数のプロキシを䜿甚しおたったく觊れおはいけないからです。 しかし、自宅では、アプリケヌションのより深い理解に基づいお、必芁なチェックを行うこずができたす。 はい、珟圚、Gyxyは私たちが知っおいる問題の党範囲を特定する方法を知りたせんが、勉匷䞭であり、あなたの助けを借りお、おそらくより良く、より完党にそれを始めたす。

䜿甚シナリオに぀いお話す堎合、私たちはいく぀かの兞型的なケヌスを特定したした。

-nginxがむンストヌルされおいるテスト環境で起動したす。
-単䞀のブロックをチェックするためのWebアプリケヌション。 これは、構成の䞍審な郚分に遭遇したずきに圹立ちたす。
-CIたたはシンクラむアントず統合するためのHTTP API。

最も興味深いオプションは、シンクラむアントにHTTP APIを䜿甚するこずです。 実際、この堎合、必芁なチェックを䞀元管理し、曎新するこずができたす。 幞いなこずに、nginxの最新バヌゞョンには、蚭定ずそのダンプをテストするための-Tスむッチがあり、Gixyはこの圢匏を解析できたす。

それがどれほど䟿利かを自分で刀断しおください
$ nginx -T | http -v https://gixy/api/check Content-Type:'application/nginx'
POST /api/check HTTP/1.1
Accept: application/json, */*
Accept-Encoding: gzip, deflate
Connection: keep-alive
Content-Length: 959
Content-Type: application/nginx
Host: gixy
User-Agent: HTTPie/0.9.8

# configuration file /etc/nginx/nginx.conf:
user http;
worker_processes 1;

#daemon on;
events {
worker_connections 1024;
}

http {
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
gzip on;
access_log /var/log/nginx/access.log combined;
error_log /var/log/nginx/error.log debug;

include sites/*.conf;
}

# configuration file /etc/nginx/mime.types:
types {
text/html html htm shtml;
text/css css;
text/xml xml;
image/gif gif;
image/jpeg jpeg jpg;
application/javascript js;
application/atom+xml atom;
application/rss+xml rss;
}

# configuration file /etc/nginx/sites/default.conf:
server {
listen 80;
return 301 https://some$uri;
}

HTTP/1.1 200 OK
Connection: keep-alive
Content-Encoding: gzip
Content-Type: application/json
Date: Tue, 24 Apr 2017 19:45:57 GMT
Keep-Alive: timeout=120
Server: nginx
Transfer-Encoding: chunked

{
"result": [
{
"auditor": "http_splitting",
"config": "\ninclude /etc/nginx/sites/default.conf;\n\n\tserver {\n\t\treturn 301 https://some$uri;\n\t}",
"description": " (\"\\n\") nginx. : rewrite, return proxy_pass.",
"help_url": "https://wiki/product-security/gixy/httpsplitting/",
"reason": "At least variable \"$uri\" can contain \"\\n\"",
"recommendation": " , (eg \"$request_uri\" \"$uri\").",
"severity": "HIGH",
"summary": " HTTP Splitting"
}
],
"status": "ok",
"warnings": []
}


最埌に、これがGixyの最初のパブリックアルファバヌゞョンであるため、埌方互換性を維持せずにAPIを倉曎できるずいう事実を匷調したいず思いたす。 この点で、独自のプラグむンを実装する必芁がある堎合は、Issueを䜜成するか、プルリク゚ストを送信するこずをお勧めしたす。その埌、䞀緒に䜕かを考えたす。

私たちの経隓があなたにずっお興味深く、有益であり、おそらくあなたが再びあなたの構成を再考するこずさえしたこずを願っおいたす;

Source: https://habr.com/ru/post/J327590/


All Articles