I've had a problem where getPostParam/getParam returns Nothing for a CSRF token passed to Snap as a hidden form parameter when dealing with file uploads. I've included a minimal-ish demonstration of the behavior.Now, it makes sense that Snap would not find the "comment" field until after the file upload is completed, because the browser sends the comment after the file and Snap would have to process the entire file upload before it would receive the comment field. But the browser sends the CSRF token before the file upload, and yet both getPostParam and getParam return Nothing, which seems like a bug.
Definitely not a bug here. You're misunderstanding the Snap execution model. When control is passed to the user handler, unless the request body has a type of application/x-www-form-encoded, the request body has NOT been read at all. The reason for this is that the request body can be large and Snap doesn't know what to do with it -- we're obviously not going to read it into RAM, and we're also not just going to shunt every request to disk. This has to be left up to the programmer.So with a multipart/form-data upload, the parameter you're looking for is not in the parameters map because you haven't read it from the socket yet! It will be in the parameters map *after* the handleFileUploads call finishes. Usually we stuff the csrf token in a cookie for this reason, although you're going to have to read the whole request body anyways to maintain the HTTP protocol invariants. If you want the connection to be forcibly terminated instead, you have to call terminateConnection.
On Sat, Sep 15, 2012 at 3:01 AM, Gregory Collins <gr...@gregorycollins.net> wrote:Definitely not a bug here. You're misunderstanding the Snap execution model. When control is passed to the user handler, unless the request body has a type of application/x-www-form-encoded, the request body has NOT been read at all. The reason for this is that the request body can be large and Snap doesn't know what to do with it -- we're obviously not going to read it into RAM, and we're also not just going to shunt every request to disk. This has to be left up to the programmer.So with a multipart/form-data upload, the parameter you're looking for is not in the parameters map because you haven't read it from the socket yet! It will be in the parameters map *after* the handleFileUploads call finishes. Usually we stuff the csrf token in a cookie for this reason, although you're going to have to read the whole request body anyways to maintain the HTTP protocol invariants. If you want the connection to be forcibly terminated instead, you have to call terminateConnection.You can't stuff a CSRF token into a cookie, as cookies are submitted with any request from the browser to the site, whether that request is legitimate or not.
For my purposes, allowing the upload before checking the csrf token is perfectly acceptable; I suppose this might be a CSRF DOS attack, but I'm honestly not too worried about that. Still, is there a way to process only part of a multipart/form data upload? Some way of dealing with this use case (under programmer control) seems like a good idea.
Right. Sorry. Although usually you match cookie contents against a token contained in the request.
You can use "handleMultipart" rather than "handleFileUploads" but in general there's no way to safely cancel after a csrf mismatch except for pulling the eject lever and terminating the connection, which is probably not what you want. (The browser is expecting you to read the data it's still sending and respond with an appropriate HTTP response.)