没搞懂 HTTP 请求的安全验证,求指导!

2022-06-02 17:02:24 +08:00
 Eyon

比如请求 https://abc.com/api ,服务器那边可能需要一个验证,比如要求 headers.Authorization === "abcdefg",

那么,也就是说我在请求是,必须在 headers 中添加 Authorization = 'abcdefg'就可以成功请求,这个逻辑没错吧?

问题是:

比如自己做个网站,浏览器打开首页,就需要从服务器提供的 API 中获取一些数据以供后续服务,API 那边定义是要求 headers.Authorization === 'abcdefg',所以前端写 axios 请求的时候,就加上了 authorization="abcdefg"这个请求,正常工作没有问题。可是,由于在浏览器中的请求标头中可以看到 Authorization:abcdefg 这个明文信息,任何人都可以看到,那不就是任何人都可以通过其他任何方式(比如 postman)来请求这个数据了吗?

当然,你可能会说加密。即便吧 abcdefg 加密成任何形式的密钥,但始终能在请求标头中看到加密后的密钥,用这个密钥发送请求依然可以成功,意义何在呢?

当然,这个问题一定是我自己哪里逻辑没搞清楚。求解答!

4117 次点击
所在节点    问与答
81 条回复
libook
2022-06-02 18:29:35 +08:00
这个流程大体是这样的:
1. 用户在登录页面登录;
2. 服务器验证用户账号信息,登录成功则将用户会话信息(如用户 ID )+当前时间合并起来进行加密,加密成一个密文字符串,然后放到返回 Header 的 Authorization 中,返回给用户浏览器;
3. 登录成功的页面从服务器返回的 Authorization 头中提取这个信息,并存在 WebStorage 中;
4. 用户访问其他登录后才能访问的页面时,页面从浏览器的 WebStorage 中读取上述字符串,以请求 Authorization 头的值随请求发到服务器;
5. 服务器从请求 Authorization 头提取字符串,进行解密,获得用户会话信息和上一次生成 Authorization 的时间;用户会话信息用来确定是哪个用户,复杂权限系统可以以此判断用户是否有权访问当前资源;时间用来验证距离上次生成这个密文多长时间,比如超过了半个小时,那么可以认定这个 Authorization 过期;如果 Authorization 有效则用用户会话信息+当前最新时间再次生成 Authorization ,放在返回头中返回给用户。
6. 回到第 4 步循环。

可以了解一下 JWT 。
Z5460520
2022-06-02 18:30:32 +08:00
@Eyon 之前我也很困惑这种 jwt 的验证。其实你可以去了解一下跨域请求攻击,做这个 Authorization=“abcd”,是防止钓鱼网站利用 session 的机制对 api 进行请求。加了这个口令之后,至少你可以允许使用这个口令的用户请求后端地址。至于你不想他直接获取你所有的信息,你可以使用一些特定的字段去限制他获取的信息的长度,有 100 本书,我不会一次返回给他,而是通过特定的其他字段才能获取所有的数据。
libook
2022-06-02 18:32:21 +08:00
安全都是相对的,确保安全的一个最低限度的条件就是物理隔离,比如你的电脑是安全的,那么你只需要确保从你电脑发出的信息都是加密的,除了服务器以外的其他人不能看到解密的原文,你的信息就是安全的。

HTTPS 使用了 TLS 加密,所保障的就是这种“点对点加密”。

换言之,如果你的电脑已经被各种病毒木马侵占,你的所有请求信息在加密前就被人看光光,就没法确保安全。
libook
2022-06-02 18:35:46 +08:00
@libook #41 应该是回到第 3 步
bjfane
2022-06-02 19:20:31 +08:00
哈哈哈,和我的一个需求一样, 太多了 没看其他大神的解决方案,https 是肯定要的,在这个基础之上
ch2
2022-06-02 19:23:57 +08:00
@Eyon #15 你想要的是 api 签名机制,但是这个东西也是不可能完全避免 hacker 直接把你的签名机制拿过来用。就跟灰产的猫鼠游戏永远玩的下去一样,你永远无法保证所有的请求都是自己的客户端发过来的
bjfane
2022-06-02 19:24:32 +08:00
没打完发出去了,再来一条吧,
比如:我的 4 个接口,1 不鉴权 但有参数 ,
2 3 4 鉴权,凭证是 1 的参数输入正确了,给返回的内容 cache 起来就行了

第二个方案是 1 2 3 4 鉴权 凭证是访问第一个页面自己输入的,只有正确所有接口才能返回数据。
yeqizhang
2022-06-02 20:00:04 +08:00
我以前也和楼主一样的疑问。

而现在,我对等保测评,要求 https 下传输手机号也要求加密感到困惑
yeqizhang
2022-06-02 20:07:01 +08:00
有一个技术叫浏览器指纹,自己专门做个 sdk ,不知道能否解决楼主不想让人 postman 请求的问题
bavtoex
2022-06-02 20:45:16 +08:00
@iyear 哈哈!帮楼主解释的清清楚楚,赞!
thunderw
2022-06-02 21:22:58 +08:00
HTTP 的这个 Authorization 本来就是相当于客户输入的密码,为啥你要纠结如何让用户不知道这个密码?不太理解纠结的点在哪里。你可能主要还是误会了 Authorization 的用意。

既然敞开门来做生意,用户想用 IE 用 IE ,想用 Postman 用 Postman ,想用 curl 用 curl 呀……
AItsuki
2022-06-03 04:24:22 +08:00
你是不是想错了什么……
1. 如果是使用 HTTPS ,别人是看不到的。
2. 你说别人能看到不会是别人使用你电脑的浏览器进开发者模式看吧…… 都用上你电脑了,那你哪些没退出的账号别人不是随便用。。。
psydonki
2022-06-03 05:52:28 +08:00
OP 你是对的,确实不应该将后台服务的 token 直接暴露给浏览器。
感觉你们团队也在摸索前后端分离和微服务...


你可能有点混淆了 Authorization 和 long term token;

拿 jwt 最佳实践来说,Authorization 中应该传登录行为产生的 access_token ( jwt ),一般过期时限为 15~60 分钟;具体步骤参见 @libook 41 楼。

long term token 一般是用在 Server to Server 通信时的简单校验; 如下图中 gateway 和 Service 之间。


所以一般微服务框架中会存在一个 API gateway 的角色,用来向前端返回和校验 jwt ;
同时充当反向代理,与后台服务进行交互,如果后台服务也是暴露在公网的情况下,出于安全考虑就会用到 long term token;


一图胜千言,


当然在实际的项目中,还是根据自己的需要,可以选择对应的云服务或者自己简单实现一个;
我自己 Next.js 项目中的样例:

```
// src/pages/api/v1/[...param].js
import axios from 'axios';

export default async (req, res) => {
const instance = axios.create({
baseURL: process.env.LC_API_BASE_URL,
headers: {
'token': process.env.LC_API_TOKEN,
'Content-Type': 'application/json',
}
});

try {
var response;

if (req.method === "GET") {
response = await instance.get(req.url);
}
else if (req.method === "POST") {
response = await instance.post(req.url, req.body);
}
else if (req.method === "PUT") {
response = await instance.put(req.url, req.body);
}
res.status(200).json(response.data)
} catch (err) {
var response = err.response;
res.status(response.status).json(response.data);
}
}

```
binux
2022-06-03 06:58:36 +08:00
安全不来源于破解工具简单,会的人多不多。
byte10
2022-06-03 09:21:37 +08:00
@yeqizhang 主要是逻辑没搞明白,用现实的东西举例子就可以了、
@gkirito 跟 oauth 没关系,基本逻辑都没搞明白

V2EX 也会经常出现这样的问题,主要还是很基本很基本很基本的东西,没搞明白。之前有公司一个同事也问道,如何保证 cookie 的安全,比如把淘宝的 cookie 从我的电脑拷贝下来,放到他电脑上去,岂不是一样的可以访问我的淘宝。但是问题是: 你怎么能拷贝我的电脑浏览器的 cookie 呢?我的电脑锁屏是有加密的,如果我允许你使用我的电脑,那么就有可能存在的这样的问题。。就好像你没法防止你小孩偷你抽屉的零食,因为他可以进卧室,客厅,但是你可以知道零食被偷的最有可能就是那么几个人。

https 是加密的请求,head 也看不到,所以中间人是没办法看到的,所以一般是安全的。你说的任何人是指谁?你身边的同事吗?朋友吗?如果你都允许他使用的你电脑,那么你是很难防止他使用你的浏览器的,除非你把电脑的浏览器 APP 单独加密使用。如果是一台公共的电脑,那么就只有每次访问过后进行退出登录,或者每次访问都需要密码。为啥经常会有小白陷入这么困境,思维太混乱了,太容易被绕进去了。我见过太多的这样的情况了,每次我都很头疼,解释不清楚的。。。之前的公司也遇到过这样的人。

记住没有任何人可以看到你的 Authorization ,除非你自己泄露出去,就好比所有的人如果知道你的银行卡密码,只要拿到你的银行卡就可以取钱,你自己都不保管好?去投诉银行卡不安全是吗?现实多少这样的人?

类似的案例,别人都告诉你了,不要去河里游泳,不要给陌生人验证码,多少餐桌鸡就是这样被坑死的。

另外安全是在一定的范围内的,你很难防止你的亲人偷的你密码转你的钱,你在睡觉的时候,在洗澡的时候,在任何时候,都有可能被亲人转走钱。但是你可以防止别人,陌生人转走你的钱,这是最基本的逻辑。

不知道解释清楚没,能帮 一个算一个。
byte10
2022-06-03 09:31:09 +08:00
对于: “而是,用户既然看得到这个 Authorization: Basic xxxxxxxx 这一串,可以直接在 Postman 中请求得到 json 格式的帖子列表,而用不着抓包,这个不是很尴尬吗?”

你这个想法非常的危险,我作为用户,我可以用谷歌浏览器,我可以用我自己开发的浏览器,我可以用 httpclient ,可以用 postman ,你为啥要阻拦我?你凭什么阻拦我的?我自己的数据我想怎么访问就怎么访问。既然是公共的数据,我想怎么访问就怎么访问,我用鼠标去点击翻页也可以,用脚本自动点击翻页也可以,你为啥要管我?

如果你想要阻拦我,就只能允许这个网页内容只能在你的 app 中访问,你可以把业务都写在你的 app 中,加入各种限制和检测。另外告诉你的是:app 大多都是 http 请求,也是可以被逆向找到访问的 token ,然后我还是可以用 postman 进行访问,你为啥那么想不开?要限制我的访问方式?

头大。。。你翻不过来了,思维太容易固化了,这个问题解决之后,也会有下一个问题。目前我没有啥方案,多画图试试看,多画点流程图,应该能提升逻辑思维能力。
byte10
2022-06-03 09:40:48 +08:00
@bjfane 需求有问题,存粹添加麻烦,自找麻烦,增加了一些校验而已。postman 也可以先请求第 1 个接口,再请求第 2,3,4 的接口呢?头大。
@blackeeper https 的话,域名貌似也看不到吧?只看到 tcp 中的 ip ,域名应该是在 http 协议头的 host 上
@psydonki 还对。。。又来一个。好家伙,那么多人没明白。
conver
2022-06-03 10:40:30 +08:00
楼主担心的是重放攻击吧,做 api 签名可以解决,时间戳+uuid+签名,过期或者 uuid 重复就拒绝
montaro2017
2022-06-03 10:40:31 +08:00
如果要反爬,建议套个 cf
disk
2022-06-03 11:02:34 +08:00
@yeqizhang 提高破解成本,想搞一样可以给你伪造指纹

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/856998

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX