借助ssh实现web服务的安全验证

背景

  • 公有云服务器 http 服务 80端口,想做到安全访问
  • 无须HTTPS + 客户端证书
  • 方便、快捷、安全

SSH 隧道 + 本地代理

使用 SSH 隧道将 HTTP 服务"隐藏"在 SSH 之后:

bash 复制代码
# 客户端建立隧道(将本地 8080 转发到服务器的 80 端口)
ssh -L 8080:localhost:80 user@your-server -i ~/.ssh/id_ed25519

# 然后访问本地端口(需先通过 SSH 认证)
curl http://localhost:8080
  • 适用场景:临时授权访问,不适合公开服务。

因为 SSH 隧道(端口转发)的流量是通过 SSH 协议(默认 22 端口) 传输的,与目标服务(如 HTTP 的 80 端口)无关。

其他方式

✅ 方案一:使用客户端证书(TLS Mutual Authentication)

这是最接近 SSH 公钥认证的做法。

✦ 原理(TLS 双向认证):

  • 客户端持有私钥 + 客户端证书
  • 服务端信任某个 CA(或特定证书)
  • 在 TLS 握手阶段,客户端用私钥签名一个随机值,服务端验证客户端证书和签名
  • 验证通过后,允许访问

✦ 实现步骤(以 Nginx 为例):

1. 创建自签 CA:
bash 复制代码
openssl genrsa -out ca.key 4096
openssl req -x509 -new -nodes -key ca.key -sha256 -days 3650 -out ca.crt
2. 为客户端生成证书:
bash 复制代码
openssl genrsa -out client.key 2048
openssl req -new -key client.key -out client.csr
openssl x509 -req -in client.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out client.crt -days 365 -sha256
3. 配置 Nginx 启用客户端认证:
nginx 复制代码
server {
    listen 443 ssl;
    server_name example.com;

    ssl_certificate     /path/to/server.crt;
    ssl_certificate_key /path/to/server.key;

    ssl_client_certificate /path/to/ca.crt;   # 信任的CA
    ssl_verify_client on;

    location / {
        root /var/www/html;
    }
}
4. 客户端访问时使用浏览器导入证书:
  • Chrome / Firefox 支持在"证书管理"中导入 .crt 和 .key 文件
  • 或用 curl 测试:
bash 复制代码
curl -v --cert client.crt --key client.key https://example.com/

✅ 方案二:基于 JWT(非对称签名)模拟公钥认证

如果 TLS 客户端证书太重,你可以用 JWT 模拟"公钥签名验证"机制。

✦ 原理:

  • 客户端持有私钥,每次请求前用私钥签名一个 payload,生成 JWT
  • 服务端用已知公钥验证签名,确认身份

✦ 实现逻辑(伪代码):

客户端(Python 示例):
python 复制代码
import jwt
from datetime import datetime, timedelta

private_key = open("client.key").read()

payload = {
    "sub": "client1",
    "exp": datetime.utcnow() + timedelta(minutes=5)
}

token = jwt.encode(payload, private_key, algorithm="RS256")
# 在 header 中发送
headers = {"Authorization": f"Bearer {token}"}
服务端验证(Python Flask 示例):
python 复制代码
from flask import request
import jwt

public_key = open("client.pub").read()

token = request.headers.get("Authorization").split()[1]

try:
    payload = jwt.decode(token, public_key, algorithms=["RS256"])
    print("Client ID:", payload["sub"])
except jwt.ExpiredSignatureError:
    return "Token expired", 401
except jwt.InvalidTokenError:
    return "Invalid token", 403

这种方式适合你已有 Web 架构,且不想涉及证书分发的问题。


✅ 方案三:基于公钥的 HTTP 签名(Http Signature)

这是类似于 AWS、GitHub Webhook 的请求签名机制。

✦ 原理:

  • 请求者用私钥签名 HTTP 请求(方法、时间戳、body 等)
  • 服务端使用公钥验证签名是否匹配

✦ 适用场景:

  • REST API 鉴权
  • 高安全需求的 webhook 回调
  • 可接入现有 Web 服务中间件

✦ 示例实现:

参考规范:


🧠 总结对比

方案 是否基于公钥 浏览器支持 安全性 部署复杂度
TLS 客户端证书 ✅ 是 ✅ ★★★★★ 高
JWT + 私钥签名 ✅ 是 ❌(仅后端) ★★★★ 中
HTTP 请求签名(HttpSig) ✅ 是 ❌ ★★★★ 中
HTTP Basic / Cookie / 密码 ❌ 否 ✅ ★★ 低
相关推荐
虎头金猫3 天前
4K 视频总卡在公网带宽?用 N1 + OpenList 把网盘播放链路重新理顺
运维·服务器·网络·python·容器·beautifulsoup·pandas
AI职业加油站3 天前
AI智能体应用工程师证书:政策红利下的职业新风口
大数据·运维·人工智能·学习·职场发展
龙亘川3 天前
一网统管AI平台民生业务实践:基于城市数字底座赋能公积金业务服务升级
大数据·安全·智慧城市·开源软件·数据可视化·政务
此冬歌咏3 天前
K8s 节点故障实战:优雅驱逐 31 秒,硬故障 331 秒,以及那个永远 Pending 的 Pod
运维·k8s
kybs19913 天前
全球灾害数据分析可视化 毕业设计-附源码66794
vue.js·spring boot·mysql·安全·django·c#·asp.net
-梅3 天前
linux(8) 软硬链接
linux·运维·服务器
张洛闻Eren3 天前
k8s云原生【第十课】:水平 Pod 自动扩缩容
运维·数据库·云原生·kubernetes·github
LorryJovens3 天前
【LAAP科研】双系统具身AGI范式研究——基于LAAP认知架构与Jev概率决策模型的系统性技术调研与范式验证
人工智能·gpt·安全·架构
其实防守也摸鱼3 天前
内网穿透与反向代理:原理、工具与实战指南
android·大数据·运维·安全·网络安全·自动化·渗透