首页 新闻 会员 周边 捐助

NetCore文件上传校验返回未授权401,文件仍然执行上传操作,要如何解决呢

0
悬赏园豆:50 [已解决问题] 解决于 2020-02-12 15:00

在上传前添加了过滤器校验,上传校验并返回未授权401,但文件仍然执行了上传操作,这样会造成消耗了服务器的流量。因操作说明较多所以写成帖子了,这是我将问题写成的帖子了:

https://www.cnblogs.com/suterfo/p/12204548.html

请问要如何才能实现校验上传文件且不允许上传的功能?

努力吧兄Dei的主页 努力吧兄Dei | 初学一级 | 园豆:140
提问于:2020-01-17 10:38
< >
分享
最佳答案
0

@blackheart 正解,在服务端处理 Expect:100-continue 的请求
具体怎么实现需要研究一下,参考这个问题:(目前还没有人回答)
Handling 100 continue on the server side with asp.net core

临时处理可以做成2个请求:先发一个请求去判断是否有权限,有权限再发第二个请求上传文件。

收获园豆:25
sweetjian | 菜鸟二级 |园豆:276 | 2020-01-17 14:20

没有比较安全且通用的做法吗,如果有人绕过请求而是故意不停地调用上传文件接口,这样数据就不停发向服务器,很容易被人攻击的吧。

努力吧兄Dei | 园豆:140 (初学一级) | 2020-01-17 14:35

@努力吧兄Dei: 这个问题不能这么考虑。任何一个接口都可以作为攻击的入口,ddos攻击是世界难题,无法解决的。

sweetjian | 园豆:276 (菜鸟二级) | 2020-01-17 14:53

@sweetjian: 我感觉是上传的规则问题,像是异步上传,即浏览器一开始告诉后端,有文件要接收,后端拒绝接收,但浏览器不管,直接将数据扔给后端,扔完后才拿着401的结果显示出来。

努力吧兄Dei | 园豆:140 (初学一级) | 2020-01-17 15:04

@努力吧兄Dei: 如果前后端都实现了 Expect:100-continue,就可以变成:
浏览器:我准备上传文件了
服务器:不行,我不接收,断开连接
浏览器:呃。。。

Expect:100-continue 目的就是让服务器确保后续数据可以继续上传。但这是客户端发起的,如果客户端不按照这个协议来那就没办法了。 如果你担心的是服务器流量被耗尽的问题,那么是无解的,发送一个打包和发送1万个小包一样都能消耗掉你的流量,你只能用一些策略来缓解。

sweetjian | 园豆:276 (菜鸟二级) | 2020-01-17 15:14
其他回答(3)
0

我记得curl post的文件时,如果大于1M,一些客户端是会先发送一个head请求,然后通过了服务端的验证后(比如文件超过了大小限制)会返回一个101的响应,这时候客户端才会真正的发送request body。你可以查查如何主动触发这样的流程。

收获园豆:25
Timetombs | 园豆:3959 (老鸟四级) | 2020-01-17 11:59

不是101,是100的响应。

支持(0) 反对(0) Timetombs | 园豆:3959 (老鸟四级) | 2020-01-17 12:07

https://files.cnblogs.com/files/linianhui/http-post-100-contuine.pcap.zip

之前用curl做的一个模拟,里面出现的100。curl客户端主动发送的请求携带了一个Expect:100-continue的请求头。

你这里的话再带上自己的token应该就可以了。

支持(0) 反对(0) Timetombs | 园豆:3959 (老鸟四级) | 2020-01-17 12:12

也不是head,是正常的POST请求,但是没有request body

支持(0) 反对(0) Timetombs | 园豆:3959 (老鸟四级) | 2020-01-17 12:18

@blackheart: 谢谢回复,在看了回复及提供的pcap文件后,感觉这也是一种办法。但我有几个疑问,
1、关于Expect:100-Continue我也查询了很久,一直没找到一个示例的小例子,在netcore下前后端要怎样处理呢?
2,如果客户端绕过“先发送一个head请求”而是直接调用接口并post大文件到服务器,这样会消耗服务器的流量吗

支持(0) 反对(0) 努力吧兄Dei | 园豆:140 (初学一级) | 2020-01-17 14:13

@blackheart: “上传校验返回未授权401,文件仍然执行上传操作”这个问题应该是比较严重的,会白白被人刷流量,可是网上其它人却没有类似的问题,很是奇怪。

支持(0) 反对(0) 努力吧兄Dei | 园豆:140 (初学一级) | 2020-01-17 14:16

@努力吧兄Dei:

1, 目前我也不清楚。不过我认为服务端框架应该会自动处理,我也查一下看看;客户端应该是主动携带这个请求头即可。
2,这是肯定的,客户端执意要发送数据到服务器,你也拦不住。除非你可以在tcp握手连接的时候就给拒绝掉。

因为流量计费都是算得出口流量,而非入口流量。

支持(0) 反对(0) Timetombs | 园豆:3959 (老鸟四级) | 2020-01-17 14:24

@blackheart: 的确是出口流量计费,我是担心两点:1是用这种方式攻击我的服务器。2是上传的拒绝结果(401)要等文件上传完之后浏览器才收到401,如果上传几G的话,客户等了几十分钟才显示说没权限,这样就比较坑了。

支持(0) 反对(0) 努力吧兄Dei | 园豆:140 (初学一级) | 2020-01-17 15:02

@努力吧兄Dei:

由于发送数据与否是客户端决定的,所以只要你的接口是公开的,那么你是阻止不了客户端直接发送的。

此外浏览器默认都不会自动携带Expect:100-Continue
https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Headers/Expect)。

所以你只剩一个可行的办法,当有权限时,才让客户端的上传入口是可用的。

支持(0) 反对(0) Timetombs | 园豆:3959 (老鸟四级) | 2020-01-17 15:28

@blackheart: “接口是公开的,那么你是阻止不了客户端直接发送的”,也就是说阻止不了其它人向服务器接口发送数据,但服务器接口可以决定接收哪些数据,是这个意思?

支持(0) 反对(0) 努力吧兄Dei | 园豆:140 (初学一级) | 2020-01-18 12:04

@努力吧兄Dei:
我觉得你还是没理解Expect:100-Continue的工作原理,它是完全的客户端行为(把一次HTTP请求分割为两个阶段)。

服务器也决定不了,只要客户端发,服务器就要收,这是因为服务器正是因为一只监听数据流入才叫服务器。你了解一下TCP的原理就知道了。但是当数据交给上层应用时,上层也许会丢弃自己不要的数据。

支持(0) 反对(0) Timetombs | 园豆:3959 (老鸟四级) | 2020-01-18 22:40
0

要在低级别的Api或者请求链路上拦截处理,
比如在nginx的header读取完成阶段,插入你的代码验证,不符合就返回401。
kestrel的ConnectionContext自己pipe处理

另外,博文里面的例子测试的时候 可以用一个比较大的文件,在浏览器模拟限速,在抓包看看是否把整个文件传完了

czd890 | 园豆:14488 (专家六级) | 2020-01-17 18:44

试过用几G的文件上传,也是全部上传完了才显示401,但实际是一开始过滤器就已返回401给前端了。
除了前端会调用文件服务器,其它的服务器也会调用文件服务器的接口进行上传或下载,所以在上传或下载前必须要进行验证。我初时设计是在上传时带一个token进行验证的,即使用"基于JWT自定义策略授权",但仍无法阻止浏览器在上传完了才显示401。
关于你说的两点:
1、对于header的验证,我试过使用"基于JWT自定义策略授权"的方式去进行上传文件的验证,前端的header带有token,后端校验header的token,但结果也是一样(上传完了才显示401)。
2、“kestrel的ConnectionContext自己pipe处理”,这个pipe是指中间件吗,刚才用中间件的方式试了,也是阻止不了浏览器不停将数据post到服务器。

支持(0) 反对(0) 努力吧兄Dei | 园豆:140 (初学一级) | 2020-01-18 08:48

@努力吧兄Dei: 建议在gateway级别上做限制

coonectionconext:

    Host.CreateDefaultBuilder(args)
        .ConfigureWebHostDefaults(webBuilder =>
        {
            webBuilder.ConfigureKestrel(serverOptions =>
            {
                serverOptions.Listen(IPAddress.Loopback, 5000);
                serverOptions.Listen(IPAddress.Loopback, 5001, 
                    listenOptions =>
                    {
                        listenOptions.Use((context,next)=>{})
支持(0) 反对(0) czd890 | 园豆:14488 (专家六级) | 2020-01-19 10:37

@czd890: 你好,粘代码时是不是缺少了一部分,上边的代码里研究了很还是不明白如何在netcore下做gateway级别的限制。可以再发详细一点的代码吗。

支持(0) 反对(0) 努力吧兄Dei | 园豆:140 (初学一级) | 2020-01-20 12:09
0

在过滤器里面这样返回,就不会走action了
filterContext.Result = new RedirectResult("/Manager/Error/”);

不知道风往哪儿吹 | 园豆:2037 (老鸟四级) | 2020-01-20 12:00

我不是要跳转页面,而是要返回信息给前端/其它服务的。

支持(0) 反对(0) 努力吧兄Dei | 园豆:140 (初学一级) | 2020-01-20 12:02

@努力吧兄Dei: 那你把RedirectResult 换成JsonResult就行了

支持(0) 反对(0) 不知道风往哪儿吹 | 园豆:2037 (老鸟四级) | 2020-01-20 12:04

@不知道风往哪儿吹: 使用了JsonResult也没能拒绝浏览器继续向服务器post数据。可参看https://www.cnblogs.com/suterfo/p/12204548.html 该链接里最下边的图。

支持(0) 反对(0) 努力吧兄Dei | 园豆:140 (初学一级) | 2020-01-20 12:06

@努力吧兄Dei: 我下载的你的代码,跑了一下,没有走后台的action,直接返回的
而且看你写的js代码,调接口之前就已经有资源消耗了,你可以在js里面做断点

支持(0) 反对(0) 不知道风往哪儿吹 | 园豆:2037 (老鸟四级) | 2020-01-20 14:09

@不知道风往哪儿吹: 不好意思,回复晚了。的确是的,还未进入要执行的action,浏览器就已经在执行上传操作了,所以有资源消耗。那么,有好的办法可以拒绝上传吗?

支持(0) 反对(0) 努力吧兄Dei | 园豆:140 (初学一级) | 2020-01-31 12:27
清除回答草稿
   您需要登录以后才能回答,未注册用户请先注册