在上传前添加了过滤器校验,上传校验并返回未授权401,但文件仍然执行了上传操作,这样会造成消耗了服务器的流量。因操作说明较多所以写成帖子了,这是我将问题写成的帖子了:
https://www.cnblogs.com/suterfo/p/12204548.html
请问要如何才能实现校验上传文件且不允许上传的功能?
@blackheart 正解,在服务端处理 Expect:100-continue 的请求
具体怎么实现需要研究一下,参考这个问题:(目前还没有人回答)
Handling 100 continue on the server side with asp.net core
临时处理可以做成2个请求:先发一个请求去判断是否有权限,有权限再发第二个请求上传文件。
没有比较安全且通用的做法吗,如果有人绕过请求而是故意不停地调用上传文件接口,这样数据就不停发向服务器,很容易被人攻击的吧。
@努力吧兄Dei: 这个问题不能这么考虑。任何一个接口都可以作为攻击的入口,ddos攻击是世界难题,无法解决的。
@sweetjian: 我感觉是上传的规则问题,像是异步上传,即浏览器一开始告诉后端,有文件要接收,后端拒绝接收,但浏览器不管,直接将数据扔给后端,扔完后才拿着401的结果显示出来。
@努力吧兄Dei: 如果前后端都实现了 Expect:100-continue,就可以变成:
浏览器:我准备上传文件了
服务器:不行,我不接收,断开连接
浏览器:呃。。。
Expect:100-continue 目的就是让服务器确保后续数据可以继续上传。但这是客户端发起的,如果客户端不按照这个协议来那就没办法了。 如果你担心的是服务器流量被耗尽的问题,那么是无解的,发送一个打包和发送1万个小包一样都能消耗掉你的流量,你只能用一些策略来缓解。
我记得curl post的文件时,如果大于1M,一些客户端是会先发送一个head请求,然后通过了服务端的验证后(比如文件超过了大小限制)会返回一个101的响应,这时候客户端才会真正的发送request body。你可以查查如何主动触发这样的流程。
不是101,是100的响应。
https://files.cnblogs.com/files/linianhui/http-post-100-contuine.pcap.zip
之前用curl做的一个模拟,里面出现的100。curl客户端主动发送的请求携带了一个Expect:100-continue
的请求头。
你这里的话再带上自己的token应该就可以了。
也不是head,是正常的POST请求,但是没有request body
@blackheart: 谢谢回复,在看了回复及提供的pcap文件后,感觉这也是一种办法。但我有几个疑问,
1、关于Expect:100-Continue我也查询了很久,一直没找到一个示例的小例子,在netcore下前后端要怎样处理呢?
2,如果客户端绕过“先发送一个head请求”而是直接调用接口并post大文件到服务器,这样会消耗服务器的流量吗
@blackheart: “上传校验返回未授权401,文件仍然执行上传操作”这个问题应该是比较严重的,会白白被人刷流量,可是网上其它人却没有类似的问题,很是奇怪。
@努力吧兄Dei:
1, 目前我也不清楚。不过我认为服务端框架应该会自动处理,我也查一下看看;客户端应该是主动携带这个请求头即可。
2,这是肯定的,客户端执意要发送数据到服务器,你也拦不住。除非你可以在tcp握手连接的时候就给拒绝掉。
因为流量计费都是算得出口流量,而非入口流量。
@blackheart: 的确是出口流量计费,我是担心两点:1是用这种方式攻击我的服务器。2是上传的拒绝结果(401)要等文件上传完之后浏览器才收到401,如果上传几G的话,客户等了几十分钟才显示说没权限,这样就比较坑了。
@努力吧兄Dei:
由于发送数据与否是客户端决定的,所以只要你的接口是公开的,那么你是阻止不了客户端直接发送的。
此外浏览器默认都不会自动携带Expect:100-Continue
(https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Headers/Expect)。
所以你只剩一个可行的办法,当有权限时,才让客户端的上传入口是可用的。
@blackheart: “接口是公开的,那么你是阻止不了客户端直接发送的”,也就是说阻止不了其它人向服务器接口发送数据,但服务器接口可以决定接收哪些数据,是这个意思?
@努力吧兄Dei:
我觉得你还是没理解Expect:100-Continue的工作原理,它是完全的客户端行为(把一次HTTP请求分割为两个阶段)。
服务器也决定不了,只要客户端发,服务器就要收,这是因为服务器正是因为一只监听数据流入才叫服务器。你了解一下TCP的原理就知道了。但是当数据交给上层应用时,上层也许会丢弃自己不要的数据。
要在低级别的Api或者请求链路上拦截处理,
比如在nginx的header读取完成阶段,插入你的代码验证,不符合就返回401。
kestrel的ConnectionContext自己pipe处理
另外,博文里面的例子测试的时候 可以用一个比较大的文件,在浏览器模拟限速,在抓包看看是否把整个文件传完了
试过用几G的文件上传,也是全部上传完了才显示401,但实际是一开始过滤器就已返回401给前端了。
除了前端会调用文件服务器,其它的服务器也会调用文件服务器的接口进行上传或下载,所以在上传或下载前必须要进行验证。我初时设计是在上传时带一个token进行验证的,即使用"基于JWT自定义策略授权",但仍无法阻止浏览器在上传完了才显示401。
关于你说的两点:
1、对于header的验证,我试过使用"基于JWT自定义策略授权"的方式去进行上传文件的验证,前端的header带有token,后端校验header的token,但结果也是一样(上传完了才显示401)。
2、“kestrel的ConnectionContext自己pipe处理”,这个pipe是指中间件吗,刚才用中间件的方式试了,也是阻止不了浏览器不停将数据post到服务器。
@努力吧兄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)=>{})
@czd890: 你好,粘代码时是不是缺少了一部分,上边的代码里研究了很还是不明白如何在netcore下做gateway级别的限制。可以再发详细一点的代码吗。
在过滤器里面这样返回,就不会走action了
filterContext.Result = new RedirectResult("/Manager/Error/”);
我不是要跳转页面,而是要返回信息给前端/其它服务的。
@努力吧兄Dei: 那你把RedirectResult 换成JsonResult就行了
@不知道风往哪儿吹: 使用了JsonResult也没能拒绝浏览器继续向服务器post数据。可参看https://www.cnblogs.com/suterfo/p/12204548.html 该链接里最下边的图。
@努力吧兄Dei: 我下载的你的代码,跑了一下,没有走后台的action,直接返回的
而且看你写的js代码,调接口之前就已经有资源消耗了,你可以在js里面做断点
@不知道风往哪儿吹: 不好意思,回复晚了。的确是的,还未进入要执行的action,浏览器就已经在执行上传操作了,所以有资源消耗。那么,有好的办法可以拒绝上传吗?