diff --git a/doc/部署说明/安全扫描.md b/doc/部署说明/安全扫描.md index c68ca204..a29bf160 100644 --- a/doc/部署说明/安全扫描.md +++ b/doc/部署说明/安全扫描.md @@ -1,20 +1,60 @@ -执法/企业端: -1: 支持较老的 TLS 版本- 中 (已改) -2: 未实施加密- 中 (一期的https问题. 不好改变当前生产环境) -3: 检测到 SHA-1 密码套件- 中 (已改) - -监督端: -1: JWT中的弱签名(3个) - 高 (已改) -2: JWT过期(3个) - 高 (已改) -3: 易受攻击的组件(2个) - 高 -4: 查询中的密码参数 - 高 -5: SRI (Subresource Integrity) 的检查 - 中 - -主机: -.25: waf 我们动不了 -- SSLV2和SSLV3 协议检测【原理扫描】 - 高 -- 目标使用过期的TLS1.0 版协议【原理扫描】 - 中 -.19: 目标主机showmount -e信息泄露(CVE-1999-0554) - 高 (同步服务器) -.3: 目标使用过期的TLS1.0 版协议【原理扫描】 - 中 (已改) -.6: SSH 服务支持弱加密算法【原理扫描】 - 中 (已改) -.5: SSH 服务支持弱加密算法【原理扫描】 - 中 (已改) \ No newline at end of file +# 安全扫描问题清单 + +## 执法/企业端 + +| 序号 | 问题描述 | 风险等级 | 状态 | +|------|----------|----------|------| +| 1 | 支持较老的 TLS 版本 | 中 | 已改 | +| 2 | 未实施加密 | 中 | 未改(一期的 HTTPS 问题,不好改变当前生产环境) | +| 3 | 检测到 SHA-1 密码套件 | 中 | 已改 | + +## 监督端 + +| 序号 | 问题描述 | 风险等级 | 状态 | +|------|----------|----------|----| +| 1 | JWT 中的弱签名(3个) | 高 | 已改 | +| 2 | JWT 过期(3个) | 高 | 已改 | +| 3 | 易受攻击的组件(2个) | 高 | 已改 | +| 4 | 查询中的密码参数 | 高 | 已改 | +| 5 | SRI (Subresource Integrity) 的检查 | 中 | 已改 | + +## 主机 + +| 主机 | 问题描述 | 风险等级 | 状态 | +|------|----------|----------|-----------| +| .25 | SSLV2 和 SSLV3 协议检测【原理扫描】 | 高 | WAF 我们动不了 | +| .25 | 目标使用过期的 TLS1.0 版协议【原理扫描】 | 中 | WAF 我们动不了 | +| .19 | 目标主机 showmount -e 信息泄露(CVE-1999-0554) | 高 | 已改 | +| .3 | 目标使用过期的 TLS1.0 版协议【原理扫描】 | 中 | 已改 | +| .6 | SSH 服务支持弱加密算法【原理扫描】 | 中 | 已改 | +| .5 | SSH 服务支持弱加密算法【原理扫描】 | 中 | 已改 | + +## 等保测评项 + +### 监督端 + +| 编号 | 测试项 | 风险等级 | +|------|--------|----------| +| 4.2.1.1 | 验证码测试 | 低风险 | +| 4.2.1.2 | 认证错误提示 | 低风险 | +| 4.1.2 | 服务器指纹信息 | 低风险 | +| 4.2.3.3 | 业务数据机密性保护 | 高风险 | +| 4.2.3.4 | 个人信息机密性保护 | 高风险 | +| 4.2.2.4 | 基于用户身份的纵向越权操作测试 | 高风险 | +| 4.2.2.1 | 服务器敏感目录遍历 | 中风险 | + +### 企业端 + +| 测试项 | 风险等级 | +|--------|----------| +| 验证码测试 | 低风险 | +| 认证错误提示 | 低风险 | +| 基于用户身份的横向越权测试 | 中风险 | + +### 执法端 + +| 测试项 | 风险等级 | +|--------|----------| +| 验证码测试 | 低风险 | +| 认证错误提示 | 低风险 | +| 基于用户身份的横向越权测试 | 中风险 | diff --git a/doc/部署说明/部署过程描述.md b/doc/部署说明/部署过程描述.md index fce99065..c3c82822 100644 --- a/doc/部署说明/部署过程描述.md +++ b/doc/部署说明/部署过程描述.md @@ -321,7 +321,15 @@ ng配置文件路径 --- ## 10.76.108.19 文件存储主服务器 - +1. 配置允许访问的 IP(仅允许业务服务器查询) + cat >> /etc/hosts.allow << 'EOF' + mountd: 10.76.108.1, 10.76.108.7, 10.76.108.8, 10.76.108.9, 10.76.108.10, 10.76.108.16 + EOF + +# 2. 拒绝所有其他主机 +cat >> /etc/hosts.deny << 'EOF' +mountd: ALL +EOF ### NFS 挂载设置 ``` diff --git a/ng/14/nginx.conf b/ng/14/nginx.conf index b1dca488..929987f0 100644 --- a/ng/14/nginx.conf +++ b/ng/14/nginx.conf @@ -80,7 +80,6 @@ http { } } - # zdxt-efcode-enforcement-app 执法端应用 server { listen 12003; listen [::]:12003; diff --git a/ng/14/源码安装nginx-1.26.3.md b/ng/14/源码安装nginx-1.26.3.md new file mode 100644 index 00000000..b7f79930 --- /dev/null +++ b/ng/14/源码安装nginx-1.26.3.md @@ -0,0 +1,158 @@ +# 10.76.108.14 源码安装 nginx-1.26.3(麒麟V10 ARM64) + +## 一、卸载旧版 yum 安装的 Nginx(如存在) + +```bash +systemctl stop nginx +yum remove nginx nginx-mod-stream -y +``` + +## 二、安装编译依赖 + +```bash +yum install -y gcc gcc-c++ make pcre pcre-devel zlib zlib-devel openssl openssl-devel +``` + +## 三、下载并解压源码 + +```bash +cd /usr/local/src +wget https://nginx.org/download/nginx-1.26.3.tar.gz +tar -zxvf nginx-1.26.3.tar.gz +cd nginx-1.26.3 +``` + +> 如服务器无法访问外网,可先在本地下载后通过 scp 上传到 `/usr/local/src/` 目录。 + +## 四、配置编译参数 + +```bash +./configure \ + --prefix=/etc/nginx \ + --sbin-path=/usr/sbin/nginx \ + --modules-path=/usr/lib64/nginx/modules \ + --conf-path=/etc/nginx/nginx.conf \ + --error-log-path=/var/log/nginx/error.log \ + --http-log-path=/var/log/nginx/access.log \ + --pid-path=/run/nginx.pid \ + --lock-path=/var/run/nginx.lock \ + --user=nginx \ + --group=nginx \ + --with-http_ssl_module \ + --with-http_v2_module \ + --with-http_realip_module \ + --with-http_gzip_static_module \ + --with-http_stub_status_module \ + --with-stream \ + --with-stream_ssl_module \ + --with-pcre +``` + +## 五、编译并安装 + +```bash +make -j$(nproc) +make install +``` + +## 六、创建 nginx 用户(如不存在) + +```bash +id nginx 2>/dev/null || (groupadd nginx && useradd -r -g nginx -s /sbin/nologin nginx) +``` + +## 七、验证安装 + +```bash +/usr/sbin/nginx -v +# 应输出: nginx version: nginx/1.26.3 + +/usr/sbin/nginx -V 2>&1 | grep stream +# 应看到: --with-stream +``` + +## 八、配置 systemd 服务 + +```bash +cat > /usr/lib/systemd/system/nginx.service << 'EOF' +[Unit] +Description=nginx - high performance web server +Documentation=http://nginx.org/en/docs/ +After=network-online.target remote-fs.target nss-lookup.target +Wants=network-online.target + +[Service] +Type=forking +PIDFile=/run/nginx.pid +ExecStartPre=/usr/sbin/nginx -t -c /etc/nginx/nginx.conf +ExecStart=/usr/sbin/nginx -c /etc/nginx/nginx.conf +ExecReload=/bin/kill -s HUP $MAINPID +ExecStop=/bin/kill -s QUIT $MAINPID +PrivateTmp=true +LimitNOFILE=65535 + +[Install] +WantedBy=multi-user.target +EOF +``` + +## 九、部署业务配置文件 + +将业务 nginx.conf 覆盖到配置路径: + +```bash +# 备份默认配置 +cp /etc/nginx/nginx.conf /etc/nginx/nginx.conf.bak + +# 上传或编辑业务配置(注意:必须移除 include /usr/share/nginx/modules/*.conf; 这行) +vi /etc/nginx/nginx.conf +``` + +> **重要**:源码编译安装后,模块(stream、ssl等)已静态链接到二进制文件中,无需动态加载。 +> 必须移除或注释掉配置文件中的 `include /usr/share/nginx/modules/*.conf;` 否则启动报错。 + +## 十、启动并设置开机自启 + +```bash +systemctl daemon-reload +systemctl start nginx +systemctl enable nginx +systemctl status nginx +``` + +## 十一、防火墙设置 + +```bash +firewall-cmd --state +firewall-cmd --list-all +firewall-cmd --add-port={80,85,445,81,12001,12002,12003,12004,12005}/tcp --permanent +firewall-cmd --reload +firewall-cmd --list-all +``` + +## 十二、常用命令 + +| 操作 | 命令 | +|------|------| +| 测试配置并重载 | `/usr/sbin/nginx -t && systemctl reload nginx` | +| 查看状态 | `systemctl status nginx` | +| 启动 | `systemctl start nginx` | +| 停止 | `systemctl stop nginx` | +| 查看版本 | `/usr/sbin/nginx -v` | +| 查看错误日志 | `tail -f /var/log/nginx/error.log` | + +## 路径说明 + +| 项目 | 路径 | +|------|------| +| 二进制文件 | /usr/sbin/nginx | +| 配置文件 | /etc/nginx/nginx.conf | +| 日志目录 | /var/log/nginx/ | +| PID 文件 | /run/nginx.pid | + +## 注意事项 + +- 系统平台:银河麒麟 V10 ARM64 (aarch64) +- nginx 1.26.3 已修复 CVE-2022-41742 安全漏洞 +- 配置文件中需添加 `server_tokens off;` 隐藏版本号进行安全加固 +- 使用绝对路径 `/usr/sbin/nginx` 调用,因 sudo 的 secure_path 默认不包含 /usr/sbin diff --git a/ng/3/nginx.conf b/ng/3/nginx.conf index a7c8dd9c..d0000065 100644 --- a/ng/3/nginx.conf +++ b/ng/3/nginx.conf @@ -107,12 +107,12 @@ http { proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } -# location /efcode20-sup-web/ { -# proxy_pass http://10.76.108.15:12004/; -# proxy_set_header Host $http_host; -# proxy_set_header X-Real-IP $remote_addr; -# proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; -# } + location /efcode20-sup-web/ { + proxy_pass http://10.76.108.15:12004/; + proxy_set_header Host $http_host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + } #location ~* /(uploads|images)/.*\.(php|php2|php3|php4|php5|phpm|phpml|phtml|phtm|phps|pht|asp|aspx|asa|cer|cdx|ashx|exe|sh|bash|jsp|jspx|jspa|html|web.config|cfm|cgi|war|ashx|htaccess|py|pl)$ { #deny all; # 拦截.html和.htm文件,并返回403禁止访问 #return 403; @@ -316,7 +316,6 @@ http { # } #} - # HTTPS server # server { @@ -326,14 +325,14 @@ http { ssl_certificate /usr/local/nginx/ssl/szssfj.cn.pem; ssl_certificate_key /usr/local/nginx/ssl/szssfj.cn.key; - ssl_session_cache shared:SSL:1m; - ssl_session_timeout 5m; - - ssl_protocols TLSv1.2 TLSv1.3; - - ssl_ciphers HIGH:!aNULL:!MD5:!3DES:!RC4:!DES:!EXPORT; + ssl_protocols TLSv1.2 TLSv1.3; + ssl_ciphers 'ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384'; ssl_prefer_server_ciphers on; + ssl_session_cache shared:SSL:10m; + ssl_session_timeout 10m; + ssl_session_tickets off; + root /usr/local/nginx/html; location /enterprisetest { diff --git a/zdxt-common/zdxt-common-satoken/src/main/java/org/dromara/common/satoken/config/SaTokenConfig.java b/zdxt-common/zdxt-common-satoken/src/main/java/org/dromara/common/satoken/config/SaTokenConfig.java index 43755f87..4a25ebc3 100644 --- a/zdxt-common/zdxt-common-satoken/src/main/java/org/dromara/common/satoken/config/SaTokenConfig.java +++ b/zdxt-common/zdxt-common-satoken/src/main/java/org/dromara/common/satoken/config/SaTokenConfig.java @@ -1,12 +1,14 @@ package org.dromara.common.satoken.config; import cn.dev33.satoken.dao.SaTokenDao; +import cn.dev33.satoken.jwt.SaJwtUtil; import cn.dev33.satoken.jwt.StpLogicJwtForMixin; import cn.dev33.satoken.jwt.StpLogicJwtForSimple; import cn.dev33.satoken.stp.StpInterface; import cn.dev33.satoken.stp.StpLogic; import org.dromara.common.core.factory.YmlPropertySourceFactory; import org.dromara.common.satoken.core.dao.PlusSaTokenDao; +import org.dromara.common.satoken.core.jwt.PlusSaJwtTemplate; import org.dromara.common.satoken.core.service.SaPermissionImpl; import org.dromara.common.satoken.handler.SaTokenExceptionHandler; import org.springframework.boot.autoconfigure.AutoConfiguration; @@ -26,6 +28,8 @@ public class SaTokenConfig { public StpLogic getStpLogicJwt() { // Sa-Token 整合 jwt (简单模式) //return new StpLogicJwtForSimple(); + // 注册自定义 SaJwtTemplate,补充标准 RFC 7519 exp 声明 + SaJwtUtil.setSaJwtTemplate(new PlusSaJwtTemplate()); return new StpLogicJwtForMixin(); } diff --git a/zdxt-common/zdxt-common-satoken/src/main/java/org/dromara/common/satoken/core/jwt/PlusSaJwtTemplate.java b/zdxt-common/zdxt-common-satoken/src/main/java/org/dromara/common/satoken/core/jwt/PlusSaJwtTemplate.java new file mode 100644 index 00000000..964f95ec --- /dev/null +++ b/zdxt-common/zdxt-common-satoken/src/main/java/org/dromara/common/satoken/core/jwt/PlusSaJwtTemplate.java @@ -0,0 +1,68 @@ +package org.dromara.common.satoken.core.jwt; + +import cn.dev33.satoken.jwt.SaJwtTemplate; +import cn.dev33.satoken.util.SaFoxUtil; +import cn.hutool.jwt.JWT; + +import java.util.Map; + +/** + * 自定义 SaJwtTemplate,在生成 JWT 时追加标准 RFC 7519 的 exp(过期时间)声明 + *

+ * Sa-Token 默认使用私有 eff 字段(毫秒级),不包含标准 exp(秒级)声明, + * 某些安全扫描工具会标记缺少 exp 为合规风险,因此在此扩展中补充 exp 字段。 + *

+ * + * @author zdxt + */ +public class PlusSaJwtTemplate extends SaJwtTemplate { + + /** + * RFC 7519 标准过期时间声明 key + */ + public static final String EXP = "exp"; + + /** + * 创建 jwt(全参数方式)—— 追加标准 exp 声明 + * + * @param loginType 账号类型 + * @param loginId 账号id + * @param deviceType 设备类型 + * @param timeout token有效期 (单位 秒) + * @param extraData 扩展数据 + * @param keyt 秘钥 + * @return jwt-token + */ + @Override + public String createToken(String loginType, Object loginId, String deviceType, + long timeout, Map extraData, String keyt) { + // 计算 eff 有效期(Sa-Token 私有字段,毫秒级) + long effTime = timeout; + if (timeout != NEVER_EXPIRE) { + effTime = timeout * 1000 + System.currentTimeMillis(); + } + + // 计算标准 exp(RFC 7519,秒级 Unix 时间戳) + long expTime; + if (timeout == NEVER_EXPIRE) { + // 永不过期时,exp 设为一个极大值(100年后) + expTime = System.currentTimeMillis() / 1000 + 100L * 365 * 24 * 3600; + } else { + expTime = System.currentTimeMillis() / 1000 + timeout; + } + + // 创建 JWT 并追加 exp 声明 + JWT jwt = JWT.create() + .setPayload(LOGIN_TYPE, loginType) + .setPayload(LOGIN_ID, loginId) + .setPayload(DEVICE_TYPE, deviceType) + .setPayload(EFF, effTime) + .setPayload(EXP, expTime) + // 塞入一个随机字符串,防止同账号同一毫秒下每次生成的 token 都一样的 + .setPayload(RN_STR, SaFoxUtil.getRandomString(32)) + .addPayloads(extraData); + + // 返回签名后的 token + return generateToken(jwt, keyt); + } +} diff --git a/zdxt-web-server/zdxt-admin-web-server/src/main/java/org/dromara/web/service/impl/EmailAuthStrategy.java b/zdxt-web-server/zdxt-admin-web-server/src/main/java/org/dromara/web/service/impl/EmailAuthStrategy.java index f013b1cb..2d9536eb 100644 --- a/zdxt-web-server/zdxt-admin-web-server/src/main/java/org/dromara/web/service/impl/EmailAuthStrategy.java +++ b/zdxt-web-server/zdxt-admin-web-server/src/main/java/org/dromara/web/service/impl/EmailAuthStrategy.java @@ -60,10 +60,7 @@ public class EmailAuthStrategy implements IAuthStrategy { loginUser.setDeviceType(client.getDeviceType()); SaLoginParameter model = new SaLoginParameter(); model.setDeviceType(client.getDeviceType()); - // 自定义分配 不同用户体系 不同 token 授权时间 不设置默认走全局 yml 配置 - // 例如: 后台用户30分钟过期 app用户1天过期 - model.setTimeout(client.getTimeout()); - model.setActiveTimeout(client.getActiveTimeout()); + // 不从数据库读取超时配置,统一使用全局 yml 默认配置(timeout: 86400, active-timeout: 1800) model.setExtra(LoginHelper.CLIENT_KEY, client.getClientId()); // 生成token LoginHelper.login(loginUser, model); diff --git a/zdxt-web-server/zdxt-admin-web-server/src/main/java/org/dromara/web/service/impl/PasswordAuthStrategy.java b/zdxt-web-server/zdxt-admin-web-server/src/main/java/org/dromara/web/service/impl/PasswordAuthStrategy.java index be02f974..54446b94 100644 --- a/zdxt-web-server/zdxt-admin-web-server/src/main/java/org/dromara/web/service/impl/PasswordAuthStrategy.java +++ b/zdxt-web-server/zdxt-admin-web-server/src/main/java/org/dromara/web/service/impl/PasswordAuthStrategy.java @@ -76,10 +76,7 @@ public class PasswordAuthStrategy implements IAuthStrategy { loginUser.setDeviceType(client.getDeviceType()); SaLoginParameter model = new SaLoginParameter(); model.setDeviceType(client.getDeviceType()); - // 自定义分配 不同用户体系 不同 token 授权时间 不设置默认走全局 yml 配置 - // 例如: 后台用户30分钟过期 app用户1天过期 - model.setTimeout(client.getTimeout()); - model.setActiveTimeout(client.getActiveTimeout()); + // 不从数据库读取超时配置,统一使用全局 yml 默认配置(timeout: 86400, active-timeout: 1800) model.setExtra(LoginHelper.CLIENT_KEY, client.getClientId()); // 生成token LoginHelper.login(loginUser, model); diff --git a/zdxt-web-server/zdxt-admin-web-server/src/main/java/org/dromara/web/service/impl/SmsAuthStrategy.java b/zdxt-web-server/zdxt-admin-web-server/src/main/java/org/dromara/web/service/impl/SmsAuthStrategy.java index 1ad18030..6deeee43 100644 --- a/zdxt-web-server/zdxt-admin-web-server/src/main/java/org/dromara/web/service/impl/SmsAuthStrategy.java +++ b/zdxt-web-server/zdxt-admin-web-server/src/main/java/org/dromara/web/service/impl/SmsAuthStrategy.java @@ -60,10 +60,7 @@ public class SmsAuthStrategy implements IAuthStrategy { loginUser.setDeviceType(client.getDeviceType()); SaLoginParameter model = new SaLoginParameter(); model.setDeviceType(client.getDeviceType()); - // 自定义分配 不同用户体系 不同 token 授权时间 不设置默认走全局 yml 配置 - // 例如: 后台用户30分钟过期 app用户1天过期 - model.setTimeout(client.getTimeout()); - model.setActiveTimeout(client.getActiveTimeout()); + // 不从数据库读取超时配置,统一使用全局 yml 默认配置(timeout: 86400, active-timeout: 1800) model.setExtra(LoginHelper.CLIENT_KEY, client.getClientId()); // 生成token LoginHelper.login(loginUser, model); diff --git a/zdxt-web-server/zdxt-admin-web-server/src/main/java/org/dromara/web/service/impl/SocialAuthStrategy.java b/zdxt-web-server/zdxt-admin-web-server/src/main/java/org/dromara/web/service/impl/SocialAuthStrategy.java index 760b14ab..353ca83e 100644 --- a/zdxt-web-server/zdxt-admin-web-server/src/main/java/org/dromara/web/service/impl/SocialAuthStrategy.java +++ b/zdxt-web-server/zdxt-admin-web-server/src/main/java/org/dromara/web/service/impl/SocialAuthStrategy.java @@ -90,10 +90,7 @@ public class SocialAuthStrategy implements IAuthStrategy { loginUser.setDeviceType(client.getDeviceType()); SaLoginParameter model = new SaLoginParameter(); model.setDeviceType(client.getDeviceType()); - // 自定义分配 不同用户体系 不同 token 授权时间 不设置默认走全局 yml 配置 - // 例如: 后台用户30分钟过期 app用户1天过期 - model.setTimeout(client.getTimeout()); - model.setActiveTimeout(client.getActiveTimeout()); + // 不从数据库读取超时配置,统一使用全局 yml 默认配置(timeout: 86400, active-timeout: 1800) model.setExtra(LoginHelper.CLIENT_KEY, client.getClientId()); // 生成token LoginHelper.login(loginUser, model); diff --git a/zdxt-web-server/zdxt-admin-web-server/src/main/java/org/dromara/web/service/impl/XcxAuthStrategy.java b/zdxt-web-server/zdxt-admin-web-server/src/main/java/org/dromara/web/service/impl/XcxAuthStrategy.java index f223dd88..7622436e 100644 --- a/zdxt-web-server/zdxt-admin-web-server/src/main/java/org/dromara/web/service/impl/XcxAuthStrategy.java +++ b/zdxt-web-server/zdxt-admin-web-server/src/main/java/org/dromara/web/service/impl/XcxAuthStrategy.java @@ -78,10 +78,7 @@ public class XcxAuthStrategy implements IAuthStrategy { SaLoginParameter model = new SaLoginParameter(); model.setDeviceType(client.getDeviceType()); - // 自定义分配 不同用户体系 不同 token 授权时间 不设置默认走全局 yml 配置 - // 例如: 后台用户30分钟过期 app用户1天过期 - model.setTimeout(client.getTimeout()); - model.setActiveTimeout(client.getActiveTimeout()); + // 不从数据库读取超时配置,统一使用全局 yml 默认配置(timeout: 86400, active-timeout: 1800) model.setExtra(LoginHelper.CLIENT_KEY, client.getClientId()); // 生成token LoginHelper.login(loginUser, model);