编程开源技术交流,分享技术与知识

网站首页 > 开源技术 正文

Nginx完全指南--内容解析(七) nginx1

wxchong 2024-12-17 16:58:07 开源技术 27 ℃ 0 评论

实现高性能负载均衡的进阶实操指南

经典书籍《NGINX 完全指南》中文版全新再版

这本由 O'Reilly 出版的电子书涵盖了最新的 NGINX 操作指南和使用技巧,是 NGINX 学习及实操的必备指南。新版不仅扩充更新了已有章节,还添加了不少前沿的热门话题。

本书是由中文官方网站推荐,免费下载的电子书籍,大家有兴趣的可以到官方地址下载获取,或者私信我获取。

中文官方网站:https://www.nginx-cn.net/

第6章 身份验证


1、简介

NGINX 能够对客户端进行身份验证。使用 NGINX 对客户端请求进行身份验证可以减轻服务器的工作负载,并能够阻止未经身份验证的请求到达应用服务器。NGINX 开源版模块包括基本身份验证和身份验证子请求。NGINX Plus 专有的 JSON Web Token(JWT)验证模块可与使用身份验证标准 OpenID Connect 的第三方身份验证提供商集成。本章介绍了结合使用 NGINX 与身份验证来保护资源的多种方法。

2、HTTP 基本身份验证

想要通过 HTTP 基本身份验证保护应用或内容。可生成以下格式的文件,其中的密码使用某个受支持的格式进行了加密或哈希处理:

# comment
name1:password1
name2:password2:comment
name3:password3

第一个字段是用户名,第二个字段是密码,冒号是分隔符。第三个字段为可选项,您可以使用该字段对每个用户进行评论。NGINX 能理解几种不同的密码格式,其中一个是使用 C 函数 crypt() 加密的密码。该函数通过 openssl passwd 命令暴露在命令行中。安装 openssl 后,您可以使用以下命令创建加密的密码字符串:

$ openssl passwd MyPassword1234

输出结果将是一个字符串,可供 NGINX 在密码文件中使用。

在 NGINX 配置中使用 auth_basic 和 auth_basic_user_file 指令,实现基本身份验证:

location / {
 		auth_basic "Private site";
		auth_basic_user_file conf.d/passwd;
}

您可以在 http、server 或 location 上下文中使用 auth_basic 指令。auth_basic 指令带一个字符串参数,如有未经授权的用户访问,该参数将显示在基本身份验证弹窗中。auth_basic_user_file 指定了用户文件的路径。

如要测试配置,您可以使用带 -u 或 --user 标志的 curl 来构建请求的 Authorization请求头:

$ curl --user myuser:MyPassword1234 https://localhost

详解

您可以通过几种方式生成具有不同格式和安全等级的基本身份验证密码。Apache 的htpasswd 命令也可以生成密码。openssl 和 htpasswd 都可以使用 apr1 算法生成密码,并且 NGINX 也能理解这种格式的密码。该密码也可以是轻型目录访问协议(LDAP)和 Dovecot 使用的 Salted SHA-1 格式。NGINX 支持其他更多格式和哈希算法;然而,许多算法容易遭到暴力破解攻击,因此人们认为这些算法不安全。

您可以使用基本身份验证来保护整个 NGINX 主机的上下文、特定的虚拟服务器甚至只是特定的 location 代码块。基本身份验证不会取代 Web 应用的用户身份验证,但可以保护私人信息的安全。实际上,基本身份验证是由服务器返回 401 UnauthorizedHTTP 代码和响应头 WWW-Authenticate 完成的。该响应头的值为 Basic realm="your string "。收到此响应后,浏览器将提示输入用户名和密码。用户名和密码用冒号连接和分隔,然后用 base64 编码,最后在名为 Authorization 的请求头中发送。Authorization 请求头将指定一个 Basic 和 user:password 编码字符串。服务器对请求头进行解码,并根据提供的 auth_basic_user_file 进行验证。由于用户名和密码字符串仅通过 base64 编码,我们建议在基本身份验证中使用 HTTPS,否则用户凭证将以明文形式通过互联网发送。

3、身份验证子请求

通过第三方身份验证系对请求进行身份验证。可使用 http_auth_request_module 请求访问身份验证服务,在响应请求之前验证身份:

location /private/ {

    auth_request /auth;
    auth_request_set $auth_status $upstream_status;
}
location = /auth {
    internal;
    proxy_pass http://auth-server;
    proxy_pass_request_body off;
    proxy_set_header Content-Length "";
    proxy_set_header X-Original-URI $request_uri;
}

auth_request 指令带一个 URI 参数,该参数必须是本地内部位置。auth_request_set指令允许您设置身份验证子请求的变量。

详解

http_auth_request_module 可验证 NGINX 服务器处理的每个请求的身份。该模块将使用子请求来确定是否授予请求访问权。子请求是指 NGINX 将请求传递给内部替代位置,并在将请求路由到目的地之前观察它的响应。/auth location 代码块将原始请求(包括正文和请求头)传递到身份验证服务器。子请求的 HTTP 状态码决定是否授予请求访问权。如果子请求返回 HTTP 200 状态码,则表示身份验证成功,请求已完成。如果子请求返回 HTTP 401 或 403,则原始请求也将返回 HTTP 401 或 403。

如果您的身份验证服务未请求请求正文,则可以使用 proxy_pass_request_body 指令删除请求正文,如上所示。这种做法可减少请求的大小和时间。由于响应正文被丢弃,Content-Length 请求头必须设置为空字符串。如果身份验证服务需要知道请求访问的URI,则需要将该值放入身份验证服务检查和验证的自定义请求头中。如果您确实希望将子请求中的某些内容保留给身份验证服务(例如响应头或其他信息),您可以使用auth_request_set 指令从响应数据中创建新的变量。

4、使用 NGINX Plus 验证 JWT

要在使用 NGINX Plus 处理请求之前验证 JWT,可使用 NGINX Plus 的 HTTP JWT 身份验证模块来验证令牌签名,并将 JWT 声明和请求头作为 NGINX 变量嵌入:

location /api/ {
    auth_jwt "api";
    auth_jwt_key_file conf/keys.json;
}

此配置可以验证该位置的 JWT。auth_jwt 指令传递一个字符串,该字符串被用作身份验证领域。auth_jwt 配置带一个保存 JWT 的变量的可选令牌参数。默认情况下,根据JWT 标准使用 Authentication 请求头。auth_jwt 指令还可用于从继承的配置中消除所需的 JWT 身份验证的影响。要关闭(off)身份验证,使用 auth_jwt 指令即可,无需传递任何参数。要取消继承的身份验证要求,只需将 off 关键字传递到 auth_jwt 指令。auth_jwt_key_file 带一个参数。该参数是采用标准 JSON Web Key(JWK)格式的密钥文件的路径。

在 NGINX Plus R29 中添加了一个模块,当 JWS 与速率限制搭配使用时,可有效防范未签名 JWT 拒绝服务攻击。该模块名为 nginx_http_internal_redirect_module,可将速率限制检查重排在 JWT 检查之前,以加强对攻击者防御。请查看下面的示例及internal_redirect 指令的用法:

limit_req_zone $jwt_claim_sub zone=jwt_sub:10m rate=1r/s;
server {
    location / {
        auth_jwt "realm";
        auth_jwt_key_file key.jwk;
        internal_redirect @rate_limited;
    }
    location @rate_limited {
        internal;
        limit_req zone=jwt_sub burst=10;
        proxy_pass http://backend;
    }
}

详解

NGINX Plus 支持验证 JSON Web 签名类型的令牌,而不是将整个令牌进行加密的JSON Web 加密类型。NGINX Plus 支持验证使用 HS256、RS256 和 ES256 算法签名的签名。使用 NGINX Plus 验证令牌可以节省向身份验证服务发出子请求所需的时间和资源。NGINX Plus 可破解 JWT 请求头和有效载荷,并将标准请求头和声明捕获到嵌入式变量中,供您使用。auth_jwt 指令可在 http、server、location 及 limit_except上下文中使用。本节还演示了如何使用 NGINX Plus 的 internal_redirect 模块来防范未签名 JWT 拒绝服务攻击;有关该模块的更多信息,请参阅“其他参考资料”部分。

其他参考资料

RFC JSON Web Signature 标准文档 https://tools.ietf.org/html/rfc7515

RFC JSON Web 算法标准文档 https://tools.ietf.org/html/rfc7518

RFC JSON Web Token 标准文档 https://tools.ietf.org/html/rfc7519

NGINX Plus JWT 身份验证 https://docs.nginx.com/nginx/admin-guide/security-controls/configuring-jwt-authentication

“借助 JWT 和 NGINX Plus 验证 API 客户端身份” https://www.nginx-cn.net/blog/authenticating-api-clients-jwt-nginx-plus/

NGINX internal_redirect 模块 https://nginx.org/en/docs/http/ngx_http_internal_redirect_module.html

5、创建 JSON Web Key

想要使用 JSON Web Key(JWK)才能使用 NGINX Plus。NGINX Plus 使用 RFC 标准中指定的 JWK 格式。该标准允许在 JWK 文件中包含一个关键对象数组。

以下是该密钥文件的示例:

{"keys":
    [
        {
            "kty":"oct",
            "kid":"0001",
            "k":"OctetSequenceKeyValue"
        },
        {
            "kty":"EC",
            "kid":"0002"
            "crv":"P-256",
            "x": "XCoordinateValue",
            "y": "YCoordinateValue",
            "d": "PrivateExponent",
            "use": "sig"
        },
        {
            "kty":"RSA",
            "kid":"0003"
            "n": "Modulus",
            "e": "Exponent",
            "d": "PrivateExponent"
        }
    ]
}

所示的 JWK 文件演示了 RFC 标准中指出的三类初始密钥。这些密钥的格式也是 RFC标准的一部分。kty 属性是密钥类型。该文件显示了三种密钥类型:Octet Sequence(oct)、Elliptic Curve(EC)和 RSA 类型。kid 属性是密钥 ID。这些密钥的标准中指定了其他属性。更多信息请查看这些标准的 RFC 文档。

详解

有许多提供不同语言的库可以生成 JWK。建议创建一个密钥服务,作为 JWK 的中央权限,以定期创建和轮换您的 JWK。为了增强安全性,建议让 JWK 与 SSL/TLS 证书一样安全。使用适当的用户和组权限保护密钥文件。最好将它们保存在主机的内存中。您可以通过创建类似 ramfs 的内存文件系统来实现。定期轮换密钥也很重要;您可以选择创建一个密钥服务来创建公钥和私钥,并通过 API 将它们提供给应用和 NGINX。

其他参考资料

RFC JSON Web Key 标准文档 https://tools.ietf.org/html/rfc7517


6、使用 NGINX Plus 通过现有的 OpenID Connect SSO 验证用户身份

将 NGINX Plus 与 OpenID Connect(OIDC)身份验证供应商集成在一起。该解决方案由许多配置要素和一些 NGINX JavaScript(njs)代码组成。身份验证供应商(IdP)必须支持 OpenID Connect 1.0。NGINX Plus 将在授权代码流中充当 OIDC的中继方。

F5 公司维护了一个 GitHub 公共仓库,该仓库包含作为 OIDC 与 NGINX Plus 集成参考实现的配置和代码。“其他参考资料”部分中的仓库链接提供了关于如何使用您自己的IdP 设置参考实现的最新说明。

详解

该解决方案只与参考实现有关,可确保各位读者拥有最新的解决方案。提供的参考将NGINX Plus 配置为 OpenID Connect 1.0 授权代码流的中继方。在此配置中,如果将对受保护资源未经授权的请求发送到 NGINX Plus,NGINX Plus 首先会将该请求重定向到 IdP。IdP 会让客户端完成自己的登录流程,然后向 NGINX Plus 返回一个身份验证代码。然后,NGINX Plus 直接与 IdP 通信,用身份验证代码交换一组 ID 令牌。这些令牌使用 JWT 进行验证,并存储在 NGINX Plus 的键值(key-value)存储中。通过使用键值存储,采用高可用性(HA)配置的所有 NGINX Plus 节点都能获得这组令牌。在这个过程中,NGINX Plus 为客户端生成了一个会话 cookie,该 cookie 被用于在键值存储中查找令牌的密钥。然后,客户端的 cookie 被重定向到初始请求的资源。随后的请求将通过使用 cookie 查找 NGINX Plus 键值存储中的 ID 令牌来进行验证。该功能支持与大多数主要身份验证供应商进行集成,包括 CA 单点登录(以前称为SiteMinder)、ForgeRock OpenAM、Keycloak、Okta、OneLogin 和 Ping Identity。作为一项标准,OIDC 与身份验证密切相关 —— 前面提到的身份验证供应商只是可能集成的一个子集。

其他参考资料

“借助 OpenID Connect 和 NGINX Plus 对应用的现存用户进行身份验证” https://www.f5.com/company/blog/nginx/authenticating-users-existing-applications-openid-connect-nginx-plus

OpenID Connect https://openid.net/developers/how-connect-works/

NGINX OpenID Connect GitHub https://github.com/nginxinc/nginx-openid-connect

为 OIDC Connect 提供访问令牌支持 https://www.nginx-cn.net/company/blog/nginx/nginx-plus-r29-released#Other-Enhancements-in-NGINX-Plus-R29

7、使用 NGINX Plus 验证 JSON Web Token(JWT)

要使用 NGINX Plus 验证 JSON Web Token。可使用 NGINX Plus 自带的 JWT 模块保护位置或服务器,并指示 auth_jwt 指令使用$cookie_auth_token 作为要验证的令牌:

location /private/ {
    auth_jwt "Google Oauth" token=$cookie_auth_token;
    auth_jwt_key_file /etc/nginx/google_certs.jwk;
}

此配置指示 NGINX Plus 通过 JWT 验证保护 /private/ URI 路径。Google OAuth 2.0 OpenID Connect 使用 cookie auth_token 而不是默认的 bearer 令牌。因此,您必须指示 NGINX 在此 cookie 中查找令牌,而不是在 NGINX Plus 的默认位置中查找。我们将在下一小节中介绍如何将 auth_jwt_key_file 位置设置为任意路径。

详解

此配置说明了如何使用 NGINX Plus 验证 Google OAuth 2.0 OpenID Connect JWT。NGINX Plus 的 HTTP JWT 身份验证模块支持验证符合 RFC JSON Web Signature规范的 JWT,允许任何使用 JWT 的 SSO 授权立即在 NGINX Plus 层中进行验证。OpenID 1.0 协议层位于 OAuth 的上面。OpenID 2.0 身份验证协议添加了身份,支持使用 JWT 来证明发送请求的用户的身份。NGINX Plus 可通过令牌的签名验证令牌自签名以来是否经过修改。这允许 Google 使用一种异步签名方法,可在保护其私人 JWK的同时分发公共 JWK。

其他参考资料

“借助 JWT 和 NGINX Plus 验证 API 客户端身份” https://www.nginx-cn.net/company/blog

8、使用 NGINX Plus 自动获取和缓存 JSON Web Key Set

希望 NGINX Plus 自动请求提供商的 JSON Web Key Set(JWKS)并进行缓存。可利用缓存区和 auth_jwt_key_request 指令自动更新密钥:

proxy_cache_path /data/nginx/cache levels=1 keys_zone=foo:10m;
server {
    # ...
    location / {
        auth_jwt "closed site";
        auth_jwt_key_request /jwks_uri;
    }
    location = /jwks_uri {
        internal;
        proxy_cache foo;
        proxy_pass https://idp.example.com/keys;
    }
}

在此示例中,auth_jwt_key_request 指令指示 NGINX Plus 从内部子请求中检索JWKS。该子请求被定向到 /jwks_uri,后者将请求代理给身份验证供应商。默认请求缓存时间为 10 分钟,以限制开销。

详解

NGINX Plus R17 中引入了 auth_jwt_key_request 指令。此功能支持 NGINX Plus 服务器在发出请求时动态更新其 JWKS。使用子请求方法来获取 JWKS,这意味着指令指向的位置必须是 NGINX Plus 服务器本地的位置。在上面的示例中,子请求的位置被锁定,以确保仅响应内部的 NGINX Plus 请求。还可使用缓存来确保仅在必要时发出JWKS 检索请求,并且不会导致身份验证供应商过载。auth_jwt_key_request 指令在http、server、location 和 limit_except 上下文中有效。

其他参考资料

“借助 JWT 和 NGINX Plus 验证 API 客户端身份” https://www.nginx-cn.net/company/blog

NGINX Plus“借助 JSON Web Key Set 缓存加快 JWT 验证 https://www.nginx-cn.net/company/blog/nginx/nginx-plus-r26-released#jwks-caching

9、将 NGINX Plus 配置为 SAML 身份验证的服务提供商

希望将 NGINX Plus 与 SAML 身份验证供应商(IdP)相集成,以保护资源。

此解决方案利用了 NGINX Plus 键值存储,因此仅适用于 NGINX Plus。此外,它还使用了 NGINX JavaScript (njs) 模块。首先安装 njs。

#使用 APT 软件包管理器的 NGINX Plus:
$ apt install nginx-plus-module-njs
#使用 YUM 软件包管理器的 NGINX Plus:
$ yum install nginx-plus-module-njs

上面的操作将 njs 安装为动态模块。您需要将以下内容添加到 nginx.conf 配置,从而指示 NGINX Plus 加载该模块:

load_module modules/ngx_http_js_module.so;
$ wget https://github.com/nginxinc/nginx-saml/archive/refs/heads/main.zip \
-O nginx-saml-main.zip
$ unzip nginx-saml-main.zip
$ mv nginx-saml-main/* /etc/nginx/conf.d/

下载、解压并移动 SAML JavaScript 和 NGINX Plus 配置文件,以激活此功能:

load_module modules/ngx_http_js_module.so;
$ wget https://github.com/nginxinc/nginx-saml/archive/refs/heads/main.zip \
-O nginx-saml-main.zip
$ unzip nginx-saml-main.zip
$ mv nginx-saml-main/* /etc/nginx/conf.d

NGINX Plus SAML 解决方案尚无法解析标准 SAML XML 配置文件。您需要更新在前面步骤中下载的配置文件,以便与您的系统相集成。以下是每个文件的描述以及所需更新内容的说明:

saml_sp_configuration.conf

在 map{} 代码块中包含一个或多个服务提供商(SP)和 IdP 的主要配置。可使用映射功能根据 $host 变量配置多个 SP 或 IdP。

? 修改所有提供带 $saml_sp_ 前缀的变量的 map 代码块,以匹配 SP 配置。

? 修改所有提供带 $saml_idp_ 前缀的变量的 map 代码块,以匹配 IdP 配置。

? 修改提供 $saml_log out_redirect 变量的 map 代码块中定义的 URI,以指定在请求 /logout location 后显示的未受保护资源。

? 如果 NGINX Plus 部署在另一个代理或负载均衡器后面,请修改 $redirect_base 和 $proto 变量的映射,以定义获取原始协议和端口号的方式。

frontend.conf

使用 SAML 解决方案通过导入 saml_sp.server_conf 文件来保护资源的反向代理配置示例。

? 在服务器配置中复制 include conf.d/saml_sp.server_conf;。

? 当请求未经授权时,使用 error_page 指令启动 SAML SP 流。在需要保护的location 代码块中添加以下内容:

error_page 401 = @do_samlsp_flow;
error_page if ($saml_access_granted 401 = @do_samlsp_flow != "1");{
if return ($saml_access_granted 401; != "1") {
  return 401;
} 

? 使用经过身份验证的用户名设置上游请求的请求头:

proxy_set_header username: $saml_name_id;
proxy_set_header username: $saml_name_id;

? 可选择通过更新传递给 error_log 指令的 level 参数来更新日志级别。

saml_sp.server_conf

用于处理 IdP 响应的 NGINX 配置。

? 该文件通常无需更改。

? 为了进行优化,修改 client_body_buffer_size 指令,以匹配最大 IdP 响应(post 正文)大小。

saml_sp.js

用于执行 SAML 身份验证的 JavaScript 代码。

? 无需更改。

详解

此解决方案结合使用了 NGINX JavaScript 模块与 NGINX Plus 键值存储模块,支持NGINX 作为 SAML 服务提供商(SP)通过单点登录保护资源。F5 公司的 NGINX 团队在 GitHub 上以公共仓库的形式提供了 JavaScript 代码(需要将其安装到配置中并启用)。端点和密钥的配置及其他 SAML 配置由一系列 map 代码块提供给 JavaScript 代码,以便根据所处理请求的主机名配置多个 SP 或 IdP。

配置 SP 和 IdP 后,您可将 saml_sp.server_conf 添加到服务器配置中,并在 NGINXPlus 未为用户保存会话时使用 error_page 指令启动与 IdP 的 SP 流。SP 流会将用户定向到 IdP 以使用现有会话或登录,成功后,用户将被重定向到 NGINX Plus,并收到经过 NGINX Plus 验证并存储在键值存储中的 SAML 响应。SAML 响应的密钥将以cookie 的形式返回给客户端,供后续请求使用,最后,客户端将被定向回最初请求的资源。

该解决方案还支持 SAML 单点注销(SLO),允许用户通过单个操作注销所有 SP 和IdP。这一操作既可由 SP 发起,也可由 IdP 发起。当 SP 发起注销时,NGINX Plus 会向 IdP 发送 LogoutRequest 消息。然后,IdP 终止用户会话,并向 NGINX Plus 返回LogoutResponse 消息,NGINX Plus 会删除存储在该用户会话键值存储中的值。当 IdP 发起注销时,它负责以 SP 的身份联系 NGINX Plus,并通过向已注册的 LogoutURL 发送 LogoutRequest 来启动注销流程。在此过程中,NGINX Plus 会从与用户会话相关的键值存储中删除值,并向 IdP 返回 LogoutResponse 消息。如果 IdP 不支持 SLO 功能,或者您不希望 NGINX Plus SP 允许使用该功能,则可将其禁用。要禁用 SLO,请将 $saml_idp_slo_url 的变量映射配置设置为空字符串。


其他参考资料

NGINX Plus 支持 SAML SSO https://github.com/nginxinc/nginx-saml/tree/main



书末题署

《NGINX 完全指南》封面上的动物是欧亚猞猁(Lynx lynx),是最大的猞猁物种,分布范围广泛,从西欧延伸到中亚。猞猁的耳尖生有黑色耸立簇毛,两颊毛发浓密而粗糙。皮毛颜色从黄灰色到灰褐色,腹部为白色。这只猞猁通身布满黑斑,与南部地区的亚种相比,北部地区的亚种更灰白,斑点更少。

与其他猞猁物种不同,欧亚猞猁捕食较大的有蹄类动物,例如鹿、麋,甚至是驯养的绵羊。成年猞猁每天消耗两到五磅肉,可长达一周食用单一食物。欧亚猞猁在二十世纪中叶濒临灭绝,后来经过坚持不懈的保护,降级为无危物种。

O'Reilly 封面上的许多动物都濒临灭绝,但对世界意义重大。

封面插画由 Karen Montgomery 参考 Shaw 著作《Zoology(动物学)》中的黑白版画绘制而成。该系列由 Edie Freedman、Ellie Volckhausen 和 Karen Montgomery 共同设计。封面字体为微软雅黑系列字体,Neusa Next Std Bold 和 Arial 粗体。正文字体为微软雅黑和 Arial 字体,标题字体为微软雅黑粗体,Proxima Nova 粗体和 Arial 粗体,代码字体为 Dalton Maag's Ubuntu Mono。

Tags:

本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表