Nginx HTTP认证配置
HTTP Authentication Configuration
概述
HTTP认证是保护Web资源的基本安全机制。Nginx支持多种认证方式,包括基础认证、摘要认证、客户端证书认证等。本文将详细介绍各种HTTP认证的配置方法。
1. 基础认证 (Basic Authentication)
1.1 基本配置
server {
listen 80;
server_name secure.example.com;
location /admin {
auth_basic "Administrator Area";
auth_basic_user_file /etc/nginx/.htpasswd;
root /var/www/admin;
index index.html;
}
location /users {
auth_basic "User Area";
auth_basic_user_file /etc/nginx/users.htpasswd;
root /var/www/users;
index index.html;
}
}
1.2 创建密码文件
# 安装htpasswd工具
sudo apt install apache2-utils # Ubuntu/Debian
sudo yum install httpd-tools # CentOS/RHEL
# 创建密码文件(第一个用户)
sudo htpasswd -c /etc/nginx/.htpasswd admin
# 添加更多用户
sudo htpasswd /etc/nginx/.htpasswd user1
sudo htpasswd /etc/nginx/.htpasswd user2
# 批量创建用户
#!/bin/bash
# create-users.sh
PASSWD_FILE="/etc/nginx/.htpasswd"
USERS=("admin:admin123" "user1:pass123" "user2:secret456")
for user_pass in "${USERS[@]}"; do
username=$(echo $user_pass | cut -d: -f1)
password=$(echo $user_pass | cut -d: -f2)
echo "$password" | htpasswd -i $PASSWD_FILE $username
done
1.3 高级基础认证配置
http {
# 定义认证区域映射
map $request_uri $auth_realm {
~^/admin/ "Admin Panel - Restricted Access";
~^/api/ "API Access - Authentication Required";
~^/reports/ "Reports Section - Authorized Personnel Only";
default "Restricted Area";
}
map $request_uri $auth_file {
~^/admin/ /etc/nginx/auth/admin.htpasswd;
~^/api/ /etc/nginx/auth/api.htpasswd;
~^/reports/ /etc/nginx/auth/reports.htpasswd;
default /etc/nginx/auth/default.htpasswd;
}
server {
listen 80;
server_name secure.example.com;
location ~ ^/(admin|api|reports) {
auth_basic $auth_realm;
auth_basic_user_file $auth_file;
# 记录认证尝试
access_log /var/log/nginx/auth.log auth_format;
try_files $uri $uri/ =404;
}
}
# 认证日志格式
log_format auth_format '$remote_addr - $remote_user [$time_local] '
'"$request" $status $body_bytes_sent '
'"$http_referer" "$http_user_agent" '
'auth_realm="$auth_realm"';
}
2. 条件认证
2.1 基于IP的条件认证
server {
listen 80;
server_name conditional.example.com;
location /admin {
# 内网IP无需认证
satisfy any;
allow 192.168.1.0/24;
allow 10.0.0.0/8;
deny all;
# 外网IP需要认证
auth_basic "Admin Area";
auth_basic_user_file /etc/nginx/.htpasswd;
root /var/www/admin;
}
location /secure {
# 必须同时满足IP和认证条件
satisfy all;
allow 192.168.1.100;
allow 192.168.1.101;
deny all;
auth_basic "Highly Secure Area";
auth_basic_user_file /etc/nginx/secure.htpasswd;
root /var/www/secure;
}
}
2.2 基于时间的条件认证
http {
# 定义工作时间
map $time_local $is_work_hours {
default 0;
~^[0-9]+/[A-Za-z]+/[0-9]+:(09|10|11|12|13|14|15|16|17):[0-9]+:[0-9]+ 1;
}
server {
listen 80;
server_name timeauth.example.com;
location /office {
# 工作时间内需要认证,其他时间拒绝访问
if ($is_work_hours = 0) {
return 403 "Access denied outside work hours";
}
auth_basic "Office Access";
auth_basic_user_file /etc/nginx/office.htpasswd;
root /var/www/office;
}
}
}
2.3 基于用户代理的认证
http {
map $http_user_agent $skip_auth {
default 1;
~*bot 0; # 机器人需要认证
~*curl 0; # curl需要认证
~*wget 0; # wget需要认证
~*scanner 0; # 扫描工具需要认证
}
server {
listen 80;
server_name uaauth.example.com;
location /api {
if ($skip_auth = 0) {
auth_basic "API Access";
auth_basic_user_file /etc/nginx/api.htpasswd;
}
proxy_pass http://backend_api;
}
}
}
3. 客户端证书认证
3.1 SSL客户端证书配置
server {
listen 443 ssl;
server_name clientcert.example.com;
# 服务器证书
ssl_certificate /etc/ssl/certs/server.crt;
ssl_certificate_key /etc/ssl/private/server.key;
# 客户端证书验证
ssl_client_certificate /etc/ssl/certs/ca.crt;
ssl_verify_client on;
ssl_verify_depth 2;
location / {
# 客户端证书信息传递给后端
proxy_set_header X-SSL-Client-Verify $ssl_client_verify;
proxy_set_header X-SSL-Client-DN $ssl_client_s_dn;
proxy_set_header X-SSL-Client-CN $ssl_client_s_dn_cn;
proxy_set_header X-SSL-Issuer $ssl_client_i_dn;
proxy_set_header X-SSL-Client-Serial $ssl_client_serial;
proxy_set_header X-SSL-Client-Fingerprint $ssl_client_fingerprint;
proxy_pass http://secure_backend;
}
# 证书信息展示页面
location /cert-info {
return 200 "Client Certificate Information:
Subject: $ssl_client_s_dn
Issuer: $ssl_client_i_dn
Serial: $ssl_client_serial
Fingerprint: $ssl_client_fingerprint
Verify: $ssl_client_verify
";
add_header Content-Type text/plain;
}
}
3.2 可选客户端证书认证
server {
listen 443 ssl;
server_name optional-cert.example.com;
ssl_certificate /etc/ssl/certs/server.crt;
ssl_certificate_key /etc/ssl/private/server.key;
ssl_client_certificate /etc/ssl/certs/ca.crt;
ssl_verify_client optional;
location / {
# 根据证书验证结果进行不同处理
if ($ssl_client_verify != SUCCESS) {
return 301 https://$server_name/login;
}
root /var/www/secure;
}
location /login {
# 证书验证失败时的登录页面
auth_basic "Login Required";
auth_basic_user_file /etc/nginx/.htpasswd;
root /var/www/login;
}
location /public {
# 公开区域,无需证书
root /var/www/public;
}
}
4. 外部认证集成
4.1 LDAP认证集成
# 需要安装nginx-auth-ldap模块
server {
listen 80;
server_name ldap.example.com;
location /ldap-auth {
auth_ldap "LDAP Authentication";
auth_ldap_servers ldap_server;
root /var/www/ldap-protected;
}
}
# LDAP服务器配置
ldap_server ldap_server {
url ldap://ldap.company.com:389/DC=company,DC=com?sAMAccountName?sub?(objectClass=person);
binddn "CN=nginx,CN=Users,DC=company,DC=com";
binddn_passwd "password123";
group_attribute member;
group_attribute_is_dn on;
require group "CN=WebUsers,CN=Groups,DC=company,DC=com";
require valid_user;
satisfy all;
}
4.2 OAuth2/JWT认证
# 使用lua脚本进行JWT验证
location /api {
access_by_lua_block {
local jwt = require "resty.jwt"
local secret = "your-secret-key"
-- 获取Authorization头
local auth_header = ngx.var.http_authorization
if not auth_header then
ngx.status = 401
ngx.header.content_type = "application/json"
ngx.say('{"error":"Missing Authorization header"}')
ngx.exit(401)
end
-- 提取JWT token
local token = string.match(auth_header, "Bearer%s+(.+)")
if not token then
ngx.status = 401
ngx.header.content_type = "application/json"
ngx.say('{"error":"Invalid Authorization format"}')
ngx.exit(401)
end
-- 验证JWT
local jwt_obj = jwt:verify(secret, token)
if not jwt_obj.valid then
ngx.status = 401
ngx.header.content_type = "application/json"
ngx.say('{"error":"Invalid token"}')
ngx.exit(401)
end
-- 检查权限
if not jwt_obj.payload.scope or
not string.find(jwt_obj.payload.scope, "api:read") then
ngx.status = 403
ngx.header.content_type = "application/json"
ngx.say('{"error":"Insufficient permissions"}')
ngx.exit(403)
end
-- 传递用户信息到后端
ngx.req.set_header("X-User-ID", jwt_obj.payload.sub)
ngx.req.set_header("X-User-Role", jwt_obj.payload.role)
ngx.req.set_header("X-User-Scope", jwt_obj.payload.scope)
}
proxy_pass http://api_backend;
}
4.3 外部认证服务
# 使用auth_request模块
location /external-auth {
auth_request /auth;
# 传递认证结果
auth_request_set $user $upstream_http_x_user;
auth_request_set $role $upstream_http_x_role;
proxy_set_header X-User $user;
proxy_set_header X-Role $role;
proxy_pass http://protected_service;
}
# 内部认证检查
location = /auth {
internal;
proxy_pass http://auth_service/verify;
proxy_pass_request_body off;
proxy_set_header Content-Length "";
proxy_set_header X-Original-URI $request_uri;
proxy_set_header X-Original-Method $request_method;
proxy_set_header X-Real-IP $remote_addr;
}
# 认证失败重定向
error_page 401 = @error401;
location @error401 {
return 302 https://auth.example.com/login?redirect=$request_uri;
}
5. 多因素认证
5.1 组合认证策略
server {
listen 443 ssl;
server_name mfa.example.com;
ssl_certificate /etc/ssl/certs/server.crt;
ssl_certificate_key /etc/ssl/private/server.key;
ssl_client_certificate /etc/ssl/certs/ca.crt;
ssl_verify_client optional;
location /high-security {
# 多层认证:客户端证书 + 基础认证
if ($ssl_client_verify != SUCCESS) {
return 401 "Client certificate required";
}
auth_basic "Additional Authentication Required";
auth_basic_user_file /etc/nginx/mfa.htpasswd;
# IP白名单
allow 192.168.1.0/24;
deny all;
# 时间限制
if ($time_local !~ "^[0-9]+/[A-Za-z]+/[0-9]+:(09|10|11|12|13|14|15|16|17):[0-9]+:[0-9]+") {
return 403 "Access denied outside business hours";
}
root /var/www/high-security;
}
}
5.2 基于风险的认证
http {
# 定义可疑活动检测
map $remote_addr $is_suspicious_ip {
default 0;
include /etc/nginx/suspicious_ips.map;
}
map $http_user_agent $is_suspicious_ua {
default 0;
~*bot 1;
~*scanner 1;
~*curl 1;
}
# GeoIP检测
geoip_country /usr/share/GeoIP/GeoIP.dat;
map $geoip_country_code $is_high_risk_country {
default 0;
CN 1; # 示例:某些国家需要额外验证
RU 1;
KP 1;
}
server {
listen 80;
server_name risk-based.example.com;
location /sensitive {
# 风险评估
set $risk_score 0;
if ($is_suspicious_ip) {
set $risk_score 1;
}
if ($is_suspicious_ua) {
set $risk_score 2;
}
if ($is_high_risk_country) {
set $risk_score 3;
}
# 根据风险等级要求不同认证
if ($risk_score = 0) {
# 低风险:无需认证
root /var/www/sensitive;
break;
}
if ($risk_score = 1) {
# 中风险:基础认证
auth_basic "Medium Risk - Authentication Required";
auth_basic_user_file /etc/nginx/.htpasswd;
}
if ($risk_score >= 2) {
# 高风险:强认证或拒绝
return 403 "High risk access denied";
}
root /var/www/sensitive;
}
}
}
6. 认证性能优化
6.1 认证缓存
# 使用auth_request缓存
proxy_cache_path /var/cache/nginx/auth
levels=1:2 keys_zone=auth_cache:10m
inactive=60m max_size=100m;
location = /auth-cached {
internal;
proxy_cache auth_cache;
proxy_cache_key "$remote_addr$http_authorization";
proxy_cache_valid 200 5m;
proxy_cache_valid 401 403 1m;
proxy_pass http://auth_service/verify;
proxy_pass_request_body off;
proxy_set_header Content-Length "";
}
location /protected-cached {
auth_request /auth-cached;
proxy_pass http://backend;
}
6.2 认证会话管理
# 使用Redis进行会话管理
location /session-auth {
access_by_lua_block {
local redis = require "resty.redis"
local red = redis:new()
red:connect("127.0.0.1", 6379)
-- 检查会话
local session_id = ngx.var.cookie_session_id
if session_id then
local user_info = red:get("session:" .. session_id)
if user_info and user_info ~= ngx.null then
-- 会话有效,更新过期时间
red:expire("session:" .. session_id, 3600)
ngx.req.set_header("X-User-Info", user_info)
return
end
end
-- 会话无效,要求认证
ngx.status = 401
ngx.header.www_authenticate = 'Basic realm="Session Required"'
ngx.exit(401)
}
proxy_pass http://backend;
}
7. 安全最佳实践
7.1 防暴力破解
# 限制认证尝试次数
limit_req_zone $binary_remote_addr zone=auth_limit:10m rate=1r/m;
server {
listen 80;
server_name secure.example.com;
location /admin {
limit_req zone=auth_limit burst=3 nodelay;
auth_basic "Admin Login";
auth_basic_user_file /etc/nginx/.htpasswd;
# 记录失败的认证尝试
error_page 401 = @auth_failed;
root /var/www/admin;
}
location @auth_failed {
access_log /var/log/nginx/auth_failures.log;
return 401 "Authentication failed";
}
}
7.2 密码文件安全
# 安全设置密码文件
#!/bin/bash
# secure-passwd-file.sh
PASSWD_FILE="/etc/nginx/.htpasswd"
# 设置正确的权限
chmod 600 $PASSWD_FILE
chown root:nginx $PASSWD_FILE
# 定期轮换密码
rotate_passwords() {
backup_file="${PASSWD_FILE}.$(date +%Y%m%d)"
cp $PASSWD_FILE $backup_file
# 生成新密码并更新
new_password=$(openssl rand -base64 12)
echo "New password for admin: $new_password"
echo "$new_password" | htpasswd -i $PASSWD_FILE admin
}
# 监控密码文件变化
inotifywait -m -e modify $PASSWD_FILE --format '%w %e %T' --timefmt '%Y-%m-%d %H:%M:%S' |
while read file event time; do
echo "[$time] Password file modified: $file $event" >> /var/log/nginx/passwd_changes.log
done
8. 故障排除
8.1 常见认证问题
# 诊断认证问题的脚本
#!/bin/bash
# auth-troubleshoot.sh
echo "=== Nginx认证故障排除 ==="
# 检查密码文件
echo "1. 检查密码文件:"
if [ -f "/etc/nginx/.htpasswd" ]; then
echo " ✓ 密码文件存在"
echo " 权限: $(ls -l /etc/nginx/.htpasswd)"
echo " 用户数: $(wc -l < /etc/nginx/.htpasswd)"
else
echo " ✗ 密码文件不存在"
fi
# 检查配置语法
echo "2. 检查Nginx配置:"
if nginx -t &>/dev/null; then
echo " ✓ 配置语法正确"
else
echo " ✗ 配置语法错误:"
nginx -t
fi
# 检查认证模块
echo "3. 检查认证模块:"
nginx -V 2>&1 | grep -q "http_auth_basic_module" && echo " ✓ Basic认证模块已启用" || echo " ✗ Basic认证模块未启用"
# 测试认证
echo "4. 测试认证:"
response=$(curl -s -o /dev/null -w "%{http_code}" http://localhost/admin)
if [ "$response" = "401" ]; then
echo " ✓ 认证保护正常工作"
else
echo " ✗ 认证保护可能未生效 (状态码: $response)"
fi
# 检查日志
echo "5. 检查最近的认证日志:"
tail -5 /var/log/nginx/error.log | grep -i auth
8.2 性能监控
# 认证性能监控脚本
#!/bin/bash
# auth-performance-monitor.sh
while true; do
echo "=== $(date) ==="
# 统计认证请求
auth_requests=$(tail -1000 /var/log/nginx/access.log | grep -c "401")
successful_auth=$(tail -1000 /var/log/nginx/access.log | grep -c "200.*auth")
echo "认证请求数: $auth_requests"
echo "成功认证数: $successful_auth"
if [ "$auth_requests" -gt 0 ]; then
success_rate=$(echo "scale=2; $successful_auth * 100 / $auth_requests" | bc)
echo "认证成功率: ${success_rate}%"
fi
# 检查认证延迟
avg_response_time=$(tail -1000 /var/log/nginx/access.log |
awk '$9==401 {sum+=$NF; count++} END {print sum/count}')
echo "平均认证响应时间: ${avg_response_time}s"
sleep 60
done
小结
通过本文学习,你应该掌握:
- 基础HTTP认证的配置和管理
- 条件认证和多因素认证策略
- 客户端证书认证的实现
- 外部认证系统集成方法
- 认证性能优化技巧
- 安全最佳实践和防护措施
- 常见认证问题的诊断和解决
下一篇文章将介绍Nginx的缓存配置与优化。