Join GitHub today
GitHub is home to over 31 million developers working together to host and review code, manage projects, and build software together.
Sign upEnforced data size in channels 2.1.7 prevent large file uploads #1240
Comments
EliotBerriot
referenced this issue
Feb 6, 2019
Closed
Installation of Mono docker on a Synology DS416play #15
This comment has been minimized.
This comment has been minimized.
Hi @EliotBerriot. OK, yes, from the description is sounds as if something is amiss. It sounds as if the change (plus your requirements) has unveiled a latent issue. First step: can you put together a reproduce, in a test case or sample project so we can see exactly what's going on? |
carltongibson
added
the
blocked/user-response
label
Feb 6, 2019
This comment has been minimized.
This comment has been minimized.
Hi, @carltongibson @EliotBerriot first of all, sorry that my commit has brought you trouble. Unfortunately, my django knowledge is not good enough to fix it by myself but I would be happy to help you since I created the bug. I think this is also related to #1171. So in a possible solution we could also move the check of DATA_UPLOAD_MAX_MEMORY_SIZE to the read method and provide lazy evalution as it is originaly implemented in Django. |
carltongibson
removed
the
blocked/user-response
label
Feb 6, 2019
This comment has been minimized.
This comment has been minimized.
Yep. That makes sense. @Zarathustra2 this isn’t you fault. |
This comment has been minimized.
This comment has been minimized.
Please don't be, things break and it's nobody's fault :)
I'm not sure if I'll find my way around the fix, but I feel confident enough to write a test case, and I'll be working on that this afternoon! |
This comment has been minimized.
This comment has been minimized.
Awesome. Thanks @EliotBerriot! (It’s much easier from there, since there’s something to play with.) |
added a commit
to EliotBerriot/channels
that referenced
this issue
Feb 7, 2019
added a commit
to EliotBerriot/channels
that referenced
this issue
Feb 7, 2019
added a commit
to EliotBerriot/channels
that referenced
this issue
Feb 7, 2019
EliotBerriot
referenced a pull request that will
close
this issue
Feb 7, 2019
Open
Enforced data size in channels 2.1.7 prevent large file uploads #1242
This comment has been minimized.
This comment has been minimized.
@EliotBerriot did you also try the following suggestion, otherwise can you provide any refutation perhaps ?
|
This comment has been minimized.
This comment has been minimized.
@jpic I didn't, the concrete steps to do that were not really clear for me. Also, I wanted to avoid touching to code I did not understand (this is my first contact with the channels codebase). Since the |
This comment has been minimized.
This comment has been minimized.
Same here, and here's what I figured while searching, you're gonna love this, or i'm completely lost Turns out that:
@EliotBerriot, both your tests still pass after completely reverting a1ecd5e, see for yourself in https://github.com/jpic/channels/tree/testrevert My recommendation would be to keep your security tests which we always need to have, but revert a1ecd5e at all. |
This comment has been minimized.
This comment has been minimized.
Hey @EliotBerriot and @jpic. Thanks for your efforts here. Super. We need to be 100% clear here so all for the good! This line here contrasts markedly with Django's: Lines 131 to 132 in 8499a42
|
This comment has been minimized.
This comment has been minimized.
I might not be able to provide further relevant clues without actually reading the WSGI and ASGI specs themselves. Meanwhile, there's something that I find interesting in the django code you have pointed out.
Does that mean that this check is completely "declarative" ? I mean, what happens if I add a long shellcode in the User-Agent header value along with a small Content-Length header ? Will that really prevent the User-Agent header value from being read in memory at all ? If so, how ? Thanks in advance for baring with me. |
This comment has been minimized.
This comment has been minimized.
No problem. So yes, we have to look at what we're getting here, and work out where best to place our limits. |
This comment has been minimized.
This comment has been minimized.
@jpic You knew this would be fun right! |
This comment has been minimized.
This comment has been minimized.
Maybe we should open a new issue about this, because Eliot's patch itself works as intended:
Wether or not we want to reconsider a1ecd5e & connected code, should not block Eliot's PR because contains a bugfix that looks critical ? After all, the patch fixes a regression and at the same time adds extra tests to prove that it's still fine, and secures channels in case Django changes the contract. |
This comment has been minimized.
This comment has been minimized.
@carltongibson you bet About a1ecd5e, I can understand that it's trying to reproduce the Django code you have pointed out, which legitimates it after all. But it's not clear to me how boundary content is excluded from the check in Django, since Content-Length should include the sum of boundary data length. Is it because they use self._body or just self instead of self.body in the case of multipart/form-data, which completely bypasses the check in the self.body property ? It seems the code from Django in the body property (pointed out by @carltongibson above) is not applicable in the case of multipart/form-data requests. In that case, it will actually avoid calling self.body, call self.parse_file_upload which in turn calls MultiPartParser.parse, which does the check that Eliot's tests prove still working / covering channels code itself. So, it turns out I understand the justification for the parent change a1ecd5e as well as Eliot's change as-is now. Thanks y'all for sharing some of your insight ;) |
This comment has been minimized.
This comment has been minimized.
So, just an update here. I am looking into this. In particular, how we're loading the request body prior to instantiating the Lines 208 to 214 in a660d81 I want to look into whether we can wrap that somehow in a file-like, which would then allow us to leverage Django's established patterns here. (I don't know at all if that'll work yet but...) It would be nice to lazily pull the request body data into memory. I'd rather Measure twice, cut once here. I'm not convinced that there's anything critical at stake, in the sense that we need to rush a half-thought patch out: adjusting |
This comment has been minimized.
This comment has been minimized.
@carltongibson security became a non issue for me when:
So at the end of the day the pull request has no impact on actual security, and still fixes a regression that's pretty critical when supporting file uploads. |
EliotBerriot commentedFeb 6, 2019
Channels was released a few days ago (kudos and thank you for the maintainance effort!) and we noticed a breaking change in our application.
Large file uploads that were working before are now failing, and understand it's related to this specific commit a1ecd5e by @Zarathustra2
I'm not discussing the rationale behind that commit, because enforcing the max size looks indeed better than before from a security/stability perspective. However, it is a breaking change for our app (and possibly others), because file uploads that were working before are now failing.
Since we were not setting DATA_UPLOAD_MAX_MEMORY_SIZE in our settings file, the default value (2.5Mio) applies, which is considerably lower than our average uploaded file size.
In theory, we could stick on channels==2.1.7 and set
DATA_UPLOAD_MAX_MEMORY_SIZE
to match our requirements, but AFAIU, it would apply to the whole payload, and not only file size. And we'd like to allow large files, but not excessively large POST data.Also, as stated in Django's documentation about
DATA_UPLOAD_MAX_MEMORY_SIZE
:Based on that, I do think there is a bug in the way the check was implemented in channels, because it does not exclude file data.
I can try working on a PR if you agree with my suggested changes:
Let me know your thoughts and I'll start working on a fix :)